Oolite 1.91.0.7658-250404-b1488af
All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
DustEntity.m
Go to the documentation of this file.
1/*
2
3DustEntity.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "DustEntity.h"
26
27#import "OOMaths.h"
28#import "Universe.h"
29#import "MyOpenGLView.h"
31#import "OODebugFlags.h"
32#import "OOMacroOpenGL.h"
33
34
35#if OO_SHADERS
36#import "OOMaterial.h" // For kTangentAttributeIndex
37#import "OOShaderProgram.h"
38#import "OOShaderUniform.h"
39#endif
40
41#import "PlayerEntity.h"
42
43
44#define FAR_PLANE (DUST_SCALE * 0.50f)
45#define NEAR_PLANE (DUST_SCALE * 0.25f)
46
47
48// Declare protocol conformance
49@interface DustEntity (Private) <OOGraphicsResetClient>
50
52
53@end
54
55#if OO_SHADERS
56enum
57{
58 kShaderModeOff,
59 kShaderModeOn,
60 kShaderModeUnknown
61};
62#endif
63
64
65@implementation DustEntity
66
67- (id) init
68{
69 int vi;
70
71// this should be unnecessary
72// ranrot_srand((uint32_t)[[NSDate date] timeIntervalSince1970]); // seed randomiser by time
73
74 self = [super init];
75
76 for (vi = 0; vi < DUST_N_PARTICLES; vi++)
77 {
81
82 // Set up element index array for warp mode.
83 indices[vi * 2] = vi;
84 indices[vi * 2 + 1] = vi + DUST_N_PARTICLES;
85
86#if OO_SHADERS
87 vertices[vi + DUST_N_PARTICLES] = vertices[vi];
88 warpinessAttr[vi] = 0.0f;
89 warpinessAttr[vi + DUST_N_PARTICLES] = 1.0f;
90#endif
91 }
92
93#if OO_SHADERS
94 shaderMode = kShaderModeUnknown;
95#endif
96
97 drawDust = ![[[NSProcessInfo processInfo] arguments] containsObject:@"-nodust"];
98
99 dust_color = [[OOColor colorWithRed:0.5 green:1.0 blue:1.0 alpha:1.0] retain];
100 [self setStatus:STATUS_ACTIVE];
101
103
104 if (hasPointSprites)
105 {
106 texture = [[OOTexture textureWithName:@"oolite-particle-dust.png"
107 inFolder:@"Textures"
108 options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask
109 anisotropy:kOOTextureDefaultAnisotropy / 2.0
110 lodBias:0.0] retain];
111 }
112
113 collision_radius = DUST_SCALE; // for draw pass calculations
114
116
117 return self;
118}
119
120
121- (void) dealloc
122{
125
127#if OO_SHADERS
128 DESTROY(shader);
129 DESTROY(uniforms);
130#endif
131
132 [super dealloc];
133}
134
135
136- (void) setDustColor:(OOColor *) color
137{
138 if (dust_color) [dust_color release];
139 dust_color = [color retain];
140 [dust_color getRed:&color_fv[0] green:&color_fv[1] blue:&color_fv[2] alpha:&color_fv[3]];
141}
142
143
145{
146 return dust_color;
147}
148
149
151{
152 return NO;
153}
154
155
157{
158 HPVector c_pos = [PLAYER viewpointPosition];
159 cameraRelativePosition = make_vector((OOScalar)-fmod(c_pos.x,DUST_SCALE),(OOScalar)-fmod(c_pos.y,DUST_SCALE),(OOScalar)-fmod(c_pos.z,DUST_SCALE));
160}
161
162
163- (void) update:(OOTimeDelta) delta_t
164{
165 // [self setPosition:position];
166 zero_distance = 0.0;
167
168#if OO_SHADERS
169 if (EXPECT_NOT(shaderMode == kShaderModeUnknown)) [self checkShaderMode];
170
171 // Shader takes care of repositioning.
172 if (shaderMode == kShaderModeOn) return;
173#endif
174
175 Vector offset = vector_flip(cameraRelativePosition);
176 GLfloat half_scale = DUST_SCALE * 0.50;
177 int vi;
178 for (vi = 0; vi < DUST_N_PARTICLES; vi++)
179 {
180 while (vertices[vi].x - offset.x < -half_scale)
181 vertices[vi].x += DUST_SCALE;
182 while (vertices[vi].x - offset.x > half_scale)
183 vertices[vi].x -= DUST_SCALE;
184
185 while (vertices[vi].y - offset.y < -half_scale)
186 vertices[vi].y += DUST_SCALE;
187 while (vertices[vi].y - offset.y > half_scale)
188 vertices[vi].y -= DUST_SCALE;
189
190 while (vertices[vi].z - offset.z < -half_scale)
191 vertices[vi].z += DUST_SCALE;
192 while (vertices[vi].z - offset.z > half_scale)
193 vertices[vi].z -= DUST_SCALE;
194 }
195}
196
197
198#if OO_SHADERS
199- (OOShaderProgram *) shader
200{
201 if (shader == nil)
202 {
203 NSString *prefix = [NSString stringWithFormat:
204 @"#define OODUST_SCALE_MAX (float(%g))\n"
205 "#define OODUST_SCALE_FACTOR (float(%g))\n"
206 "#define OODUST_SIZE (float(%g))\n",
207 FAR_PLANE / NEAR_PLANE,
208 1.0f / (FAR_PLANE - NEAR_PLANE),
209 (float)DUST_SCALE];
210
211 // Reuse tangent attribute ID for "warpiness", as we don't need a tangent.
212 NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kTangentAttributeIndex]
213 forKey:@"aWarpiness"];
214
215 shader = [[OOShaderProgram shaderProgramWithVertexShaderName:@"oolite-dust.vertex"
216 fragmentShaderName:@"oolite-dust.fragment"
217 prefix:prefix
218 attributeBindings:attributes] retain];
219
220 DESTROY(uniforms);
221 OOShaderUniform *uWarp = [[OOShaderUniform alloc] initWithName:@"uWarp"
222 shaderProgram:shader
223 boundToObject:self
224 property:@selector(warpVector)
225 convertOptions:0];
226 OOShaderUniform *uOffsetPlayerPosition = [[OOShaderUniform alloc] initWithName:@"uOffsetPlayerPosition"
227 shaderProgram:shader
228 boundToObject:self
229 property:@selector(offsetPlayerPosition)
230 convertOptions:0];
231
232 uniforms = [[NSArray alloc] initWithObjects:uWarp, uOffsetPlayerPosition, nil];
233 [uWarp release];
234 [uOffsetPlayerPosition release];
235 }
236
237 return shader;
238}
239
240- (Vector) offsetPlayerPosition
241{
242 // used as shader uniform, so needs to be low precision
243 HPVector c_pos = [PLAYER viewpointPosition];
244 Vector offset = make_vector((OOScalar)fmod(c_pos.x,DUST_SCALE),(OOScalar)fmod(c_pos.y,DUST_SCALE),(OOScalar)fmod(c_pos.z,DUST_SCALE));
245 return vector_subtract(offset, make_vector(DUST_SCALE * 0.5f, DUST_SCALE * 0.5f, DUST_SCALE * 0.5f));
246}
247
248
249- (void) checkShaderMode
250{
251 shaderMode = kShaderModeOff;
252 if ([UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS)
253 {
254 if ([[OOOpenGLExtensionManager sharedManager] useDustShader])
255 {
256 shaderMode = kShaderModeOn;
257 }
258 }
259}
260#endif
261
262
263- (Vector) warpVector
264{
265 return vector_multiply_scalar([PLAYER velocity], 1.0f / HYPERSPEED_FACTOR);
266}
267
268
269- (void) drawImmediate:(bool)immediate translucent:(bool)translucent
270{
271 if (!drawDust || [UNIVERSE breakPatternHide] || !translucent) return; // DON'T DRAW
272
273 PlayerEntity* player = PLAYER;
274 assert(player != nil);
275
276#ifndef NDEBUG
277 if (gDebugFlags & DEBUG_NO_DUST) return;
278#endif
279
280#if OO_SHADERS
281 if (EXPECT_NOT(shaderMode == kShaderModeUnknown)) [self checkShaderMode];
282 BOOL useShader = (shaderMode == kShaderModeOn);
283#endif
284
285
286 GLfloat *fogcolor = [UNIVERSE skyClearColor];
287 float idealDustSize = [[UNIVERSE gameView] viewSize].width / 800.0f;
288
289 BOOL warp_stars = [player atHyperspeed];
290 float dustIntensity;
291
294 OOGL(glDisableClientState(GL_NORMAL_ARRAY));
295
296 if (!warp_stars)
297 {
298 // Draw points.
299 float dustPointSize = ceil(idealDustSize);
300 if (dustPointSize < 1.0f) dustPointSize = 1.0f;
301 OOGL(GLScaledPointSize(dustPointSize));
302 dustIntensity = OOClamp_0_1_f(idealDustSize / dustPointSize);
303 }
304 else
305 {
306 // Draw lines.
307 float idealLineSize = idealDustSize * 0.5f;
308 float dustLineSize = ceil(idealLineSize);
309 if (dustLineSize < 1.0f) dustLineSize = 1.0f;
310 GLScaledLineWidth(dustLineSize);
311 dustIntensity = OOClamp_0_1_f(idealLineSize / dustLineSize);
312 }
313 if (fogcolor[3] > 0.0)
314 {
315 // fade out dust when entering atmosphere (issue #100)
316 dustIntensity = OOClamp_0_1_f(dustIntensity-(fogcolor[3]*3.0));
317 }
318
319
320 if (dustIntensity > 0.0)
321 {
322
323 float *color = NULL;
324 if (player->isSunlit) color = color_fv;
325 else color = UNIVERSE->stars_ambient;
326 OOGL(glColor4f(color[0], color[1], color[2], dustIntensity));
327
328#if OO_SHADERS
329 if (useShader)
330 {
331 [[self shader] apply];
332 [uniforms makeObjectsPerformSelector:@selector(apply)];
333 }
334 else
335#endif
336 {
337 OOGL(glEnable(GL_FOG));
338 OOGL(glFogi(GL_FOG_MODE, GL_LINEAR));
339 OOGL(glFogfv(GL_FOG_COLOR, fogcolor));
340 OOGL(glHint(GL_FOG_HINT, GL_NICEST));
341 OOGL(glFogf(GL_FOG_START, NEAR_PLANE));
342 OOGL(glFogf(GL_FOG_END, FAR_PLANE));
343 }
344
345 OOGL(glEnable(GL_BLEND));
346 OOGL(glDepthMask(GL_FALSE));
347
348 if (warp_stars)
349 {
350 OOGL(glDisable(GL_TEXTURE_2D));
351#if OO_SHADERS
352 if (useShader)
353 {
354 OOGL(glEnableVertexAttribArrayARB(kTangentAttributeIndex));
355 OOGL(glVertexAttribPointerARB(kTangentAttributeIndex, 1, GL_FLOAT, GL_FALSE, 0, warpinessAttr));
356 }
357 else
358#endif
359 {
360 Vector warpVector = [self warpVector];
361 unsigned vi;
362 for (vi = 0; vi < DUST_N_PARTICLES; vi++)
363 {
364 vertices[vi + DUST_N_PARTICLES] = vector_subtract(vertices[vi], warpVector);
365 }
366 }
367
368 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
369 OOGL(glDrawElements(GL_LINES, DUST_N_PARTICLES * 2, GL_UNSIGNED_SHORT, indices));
370
371#if OO_SHADERS
372 if (useShader)
373 {
374 OOGL(glDisableVertexAttribArrayARB(kTangentAttributeIndex));
375 }
376#endif
377 OOGL(glEnable(GL_TEXTURE_2D));
378
379 }
380 else
381 {
382 if (hasPointSprites)
383 {
384#if OO_SHADERS
385 if (!useShader)
386#endif
387 {
388 OOGL(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
389 }
390 OOGL(glEnable(GL_POINT_SPRITE_ARB));
391 [texture apply];
392 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
393 OOGL(glDrawArrays(GL_POINTS, 0, DUST_N_PARTICLES));
394 OOGL(glDisable(GL_POINT_SPRITE_ARB));
395 }
396 else
397 {
398 OOGL(glDisable(GL_TEXTURE_2D));
399 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
400 OOGL(glDrawArrays(GL_POINTS, 0, DUST_N_PARTICLES));
401 OOGL(glEnable(GL_TEXTURE_2D));
402 }
403 }
404
405 // reapply normal conditions
406#if OO_SHADERS
407 if (useShader)
408 {
409 [OOShaderProgram applyNone];
410 }
411 else
412#endif
413 {
414 OOGL(glDisable(GL_FOG));
415 OOGL(glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA));
416 }
417
418 OOGL(glDisable(GL_BLEND));
419 OOGL(glDepthMask(GL_TRUE));
420
421 }
422 OOGL(glEnableClientState(GL_NORMAL_ARRAY));
423
425 OOCheckOpenGLErrors(@"DustEntity after drawing %@", self);
426}
427
428
430{
431#if OO_SHADERS
432 DESTROY(shader);
433 DESTROY(uniforms);
434
435 shaderMode = kShaderModeUnknown;
436
437 /* Duplicate vertex data. This is only required if we're switching from
438 non-shader mode to a shader mode, but let's KISS.
439 */
441#endif
442}
443
444
445#ifndef NDEBUG
447{
448 // Don't include range and visibility flag as they're irrelevant.
449 return [self descriptionForObjDumpBasic];
450}
451#endif
452
453@end
NSUInteger gDebugFlags
Definition main.m:7
#define DUST_N_PARTICLES
Definition DustEntity.h:32
#define DUST_SCALE
Definition DustEntity.h:31
#define NEAR_PLANE
Definition DustEntity.m:45
#define FAR_PLANE
Definition DustEntity.m:44
#define DESTROY(x)
Definition OOCocoa.h:77
@ DEBUG_NO_DUST
#define EXPECT_NOT(x)
#define OO_ENTER_OPENGL()
GLfloat OOScalar
Definition OOMaths.h:64
@ OPENGL_STATE_OPAQUE
Definition OOOpenGL.h:123
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
BOOL OOCheckOpenGLErrors(NSString *format,...)
Definition OOOpenGL.m:39
void GLScaledLineWidth(GLfloat width)
Definition OOOpenGL.m:218
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
#define OOGL(statement)
Definition OOOpenGL.h:251
void GLScaledPointSize(GLfloat size)
Definition OOOpenGL.m:225
return nil
float y
float x
@ DETAIL_LEVEL_SHADERS
Definition OOTypes.h:246
double OOTimeDelta
Definition OOTypes.h:224
#define HYPERSPEED_FACTOR
#define PLAYER
#define UNIVERSE
Definition Universe.h:840
Vector vertices[DUST_N_PARTICLES *2]
Definition DustEntity.h:41
bool drawDust
Definition DustEntity.h:46
bool hasPointSprites
Definition DustEntity.h:45
void dealloc()
Definition DustEntity.m:121
OOColor * dust_color
Definition DustEntity.h:40
void resetGraphicsState()
Definition DustEntity.m:429
BOOL canCollide()
Definition DustEntity.m:150
OOColor * dustColor()
Definition DustEntity.m:144
NSString * descriptionForObjDump()
Definition DustEntity.m:446
void updateCameraRelativePosition()
Definition DustEntity.m:156
GLushort indices[DUST_N_PARTICLES *2]
Definition DustEntity.h:42
OOTexture * texture
Definition DustEntity.h:44
void checkShaderMode()
GLfloat color_fv[4]
Definition DustEntity.h:43
Vector warpVector()
Definition DustEntity.m:263
GLfloat collision_radius
Definition Entity.h:111
NSString * descriptionForObjDumpBasic()
Definition Entity.m:1087
GLfloat zero_distance
Definition Entity.h:108
Vector cameraRelativePosition
Definition Entity.m:617
Vector velocity
Definition Entity.m:763
id init()
Definition Entity.m:68
void setStatus:(OOEntityStatus stat)
Definition Entity.m:787
unsigned isSunlit
Definition Entity.m:173
void dealloc()
Definition Entity.m:101
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
Definition OOColor.m:95
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
Definition OOColor.m:368
void registerClient:(id< OOGraphicsResetClient > client)
void unregisterClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
OOOpenGLExtensionManager * sharedManager()
BOOL haveExtension:(NSString *extension)
void apply()
Definition OOTexture.m:269
id textureWithName:inFolder:options:anisotropy:lodBias:(NSString *name,[inFolder] NSString *directory,[options] OOTextureFlags options,[anisotropy] GLfloat anisotropy,[lodBias] GLfloat lodBias)
Definition OOTexture.m:134
voidpf uLong offset
Definition ioapi.h:140
#define ranrot_rand()