Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
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
51- (void) checkShaderMode;
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 {
78 vertices[vi].x = (ranrot_rand() % DUST_SCALE) - DUST_SCALE / 2;
79 vertices[vi].y = (ranrot_rand() % DUST_SCALE) - DUST_SCALE / 2;
80 vertices[vi].z = (ranrot_rand() % DUST_SCALE) - DUST_SCALE / 2;
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 dust_color = [[OOColor colorWithRed:0.5 green:1.0 blue:1.0 alpha:1.0] retain];
98 [self setStatus:STATUS_ACTIVE];
99
100 hasPointSprites = [[OOOpenGLExtensionManager sharedManager] haveExtension:@"GL_ARB_point_sprite"];
101
102 if (hasPointSprites)
103 {
104 texture = [[OOTexture textureWithName:@"oolite-particle-dust.png"
105 inFolder:@"Textures"
106 options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask
107 anisotropy:kOOTextureDefaultAnisotropy / 2.0
108 lodBias:0.0] retain];
109 }
110
111 collision_radius = DUST_SCALE; // for draw pass calculations
112
114
115 return self;
116}
117
118
119- (void) dealloc
120{
121 DESTROY(dust_color);
123
124 DESTROY(texture);
125#if OO_SHADERS
126 DESTROY(shader);
127 DESTROY(uniforms);
128#endif
129
130 [super dealloc];
131}
132
133
134- (void) setDustColor:(OOColor *) color
135{
136 if (dust_color) [dust_color release];
137 dust_color = [color retain];
138 [dust_color getRed:&color_fv[0] green:&color_fv[1] blue:&color_fv[2] alpha:&color_fv[3]];
139}
140
141
142- (OOColor *) dustColor
143{
144 return dust_color;
145}
146
147
148- (BOOL) canCollide
149{
150 return NO;
151}
152
153
154- (void) updateCameraRelativePosition
155{
156 HPVector c_pos = [PLAYER viewpointPosition];
157 cameraRelativePosition = make_vector((OOScalar)-fmod(c_pos.x,DUST_SCALE),(OOScalar)-fmod(c_pos.y,DUST_SCALE),(OOScalar)-fmod(c_pos.z,DUST_SCALE));
158}
159
160
161- (void) update:(OOTimeDelta) delta_t
162{
163 // [self setPosition:position];
164 zero_distance = 0.0;
165
166#if OO_SHADERS
167 if (EXPECT_NOT(shaderMode == kShaderModeUnknown)) [self checkShaderMode];
168
169 // Shader takes care of repositioning.
170 if (shaderMode == kShaderModeOn) return;
171#endif
172
173 Vector offset = vector_flip(cameraRelativePosition);
174 GLfloat half_scale = DUST_SCALE * 0.50;
175 int vi;
176 for (vi = 0; vi < DUST_N_PARTICLES; vi++)
177 {
178 while (vertices[vi].x - offset.x < -half_scale)
179 vertices[vi].x += DUST_SCALE;
180 while (vertices[vi].x - offset.x > half_scale)
181 vertices[vi].x -= DUST_SCALE;
182
183 while (vertices[vi].y - offset.y < -half_scale)
184 vertices[vi].y += DUST_SCALE;
185 while (vertices[vi].y - offset.y > half_scale)
186 vertices[vi].y -= DUST_SCALE;
187
188 while (vertices[vi].z - offset.z < -half_scale)
189 vertices[vi].z += DUST_SCALE;
190 while (vertices[vi].z - offset.z > half_scale)
191 vertices[vi].z -= DUST_SCALE;
192 }
193}
194
195
196#if OO_SHADERS
197- (OOShaderProgram *) shader
198{
199 if (shader == nil)
200 {
201 NSString *prefix = [NSString stringWithFormat:
202 @"#define OODUST_SCALE_MAX (float(%g))\n"
203 "#define OODUST_SCALE_FACTOR (float(%g))\n"
204 "#define OODUST_SIZE (float(%g))\n",
205 FAR_PLANE / NEAR_PLANE,
206 1.0f / (FAR_PLANE - NEAR_PLANE),
207 (float)DUST_SCALE];
208
209 // Reuse tangent attribute ID for "warpiness", as we don't need a tangent.
210 NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kTangentAttributeIndex]
211 forKey:@"aWarpiness"];
212
213 shader = [[OOShaderProgram shaderProgramWithVertexShaderName:@"oolite-dust.vertex"
214 fragmentShaderName:@"oolite-dust.fragment"
215 prefix:prefix
216 attributeBindings:attributes] retain];
217
218 DESTROY(uniforms);
219 OOShaderUniform *uWarp = [[OOShaderUniform alloc] initWithName:@"uWarp"
220 shaderProgram:shader
221 boundToObject:self
222 property:@selector(warpVector)
223 convertOptions:0];
224 OOShaderUniform *uOffsetPlayerPosition = [[OOShaderUniform alloc] initWithName:@"uOffsetPlayerPosition"
225 shaderProgram:shader
226 boundToObject:self
227 property:@selector(offsetPlayerPosition)
228 convertOptions:0];
229
230 uniforms = [[NSArray alloc] initWithObjects:uWarp, uOffsetPlayerPosition, nil];
231 [uWarp release];
232 [uOffsetPlayerPosition release];
233 }
234
235 return shader;
236}
237
238- (Vector) offsetPlayerPosition
239{
240 // used as shader uniform, so needs to be low precision
241 HPVector c_pos = [PLAYER viewpointPosition];
242 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));
243 return vector_subtract(offset, make_vector(DUST_SCALE * 0.5f, DUST_SCALE * 0.5f, DUST_SCALE * 0.5f));
244}
245
246
247- (void) checkShaderMode
248{
249 shaderMode = kShaderModeOff;
250 if ([UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS)
251 {
252 if ([[OOOpenGLExtensionManager sharedManager] useDustShader])
253 {
254 shaderMode = kShaderModeOn;
255 }
256 }
257}
258#endif
259
260
261- (Vector) warpVector
262{
263 return vector_multiply_scalar([PLAYER velocity], 1.0f / HYPERSPEED_FACTOR);
264}
265
266
267- (void) drawImmediate:(bool)immediate translucent:(bool)translucent
268{
269 if ([UNIVERSE breakPatternHide] || !translucent) return; // DON'T DRAW
270
271 PlayerEntity* player = PLAYER;
272 assert(player != nil);
273
274#ifndef NDEBUG
275 if (gDebugFlags & DEBUG_NO_DUST) return;
276#endif
277
278#if OO_SHADERS
279 if (EXPECT_NOT(shaderMode == kShaderModeUnknown)) [self checkShaderMode];
280 BOOL useShader = (shaderMode == kShaderModeOn);
281#endif
282
283
284 GLfloat *fogcolor = [UNIVERSE skyClearColor];
285 float idealDustSize = [[UNIVERSE gameView] viewSize].width / 800.0f;
286
287 BOOL warp_stars = [player atHyperspeed];
288 float dustIntensity;
289
292 OOGL(glDisableClientState(GL_NORMAL_ARRAY));
293
294 if (!warp_stars)
295 {
296 // Draw points.
297 float dustPointSize = ceil(idealDustSize);
298 if (dustPointSize < 1.0f) dustPointSize = 1.0f;
299 OOGL(GLScaledPointSize(dustPointSize));
300 dustIntensity = OOClamp_0_1_f(idealDustSize / dustPointSize);
301 }
302 else
303 {
304 // Draw lines.
305 float idealLineSize = idealDustSize * 0.5f;
306 float dustLineSize = ceil(idealLineSize);
307 if (dustLineSize < 1.0f) dustLineSize = 1.0f;
308 GLScaledLineWidth(dustLineSize);
309 dustIntensity = OOClamp_0_1_f(idealLineSize / dustLineSize);
310 }
311 if (fogcolor[3] > 0.0)
312 {
313 // fade out dust when entering atmosphere (issue #100)
314 dustIntensity = OOClamp_0_1_f(dustIntensity-(fogcolor[3]*3.0));
315 }
316
317
318 if (dustIntensity > 0.0)
319 {
320
321 float *color = NULL;
322 if (player->isSunlit) color = color_fv;
323 else color = UNIVERSE->stars_ambient;
324 OOGL(glColor4f(color[0], color[1], color[2], dustIntensity));
325
326#if OO_SHADERS
327 if (useShader)
328 {
329 [[self shader] apply];
330 [uniforms makeObjectsPerformSelector:@selector(apply)];
331 }
332 else
333#endif
334 {
335 OOGL(glEnable(GL_FOG));
336 OOGL(glFogi(GL_FOG_MODE, GL_LINEAR));
337 OOGL(glFogfv(GL_FOG_COLOR, fogcolor));
338 OOGL(glHint(GL_FOG_HINT, GL_NICEST));
339 OOGL(glFogf(GL_FOG_START, NEAR_PLANE));
340 OOGL(glFogf(GL_FOG_END, FAR_PLANE));
341 }
342
343 OOGL(glEnable(GL_BLEND));
344 OOGL(glDepthMask(GL_FALSE));
345
346 if (warp_stars)
347 {
348 OOGL(glDisable(GL_TEXTURE_2D));
349#if OO_SHADERS
350 if (useShader)
351 {
352 OOGL(glEnableVertexAttribArrayARB(kTangentAttributeIndex));
353 OOGL(glVertexAttribPointerARB(kTangentAttributeIndex, 1, GL_FLOAT, GL_FALSE, 0, warpinessAttr));
354 }
355 else
356#endif
357 {
358 Vector warpVector = [self warpVector];
359 unsigned vi;
360 for (vi = 0; vi < DUST_N_PARTICLES; vi++)
361 {
362 vertices[vi + DUST_N_PARTICLES] = vector_subtract(vertices[vi], warpVector);
363 }
364 }
365
366 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
367 OOGL(glDrawElements(GL_LINES, DUST_N_PARTICLES * 2, GL_UNSIGNED_SHORT, indices));
368
369#if OO_SHADERS
370 if (useShader)
371 {
372 OOGL(glDisableVertexAttribArrayARB(kTangentAttributeIndex));
373 }
374#endif
375 OOGL(glEnable(GL_TEXTURE_2D));
376
377 }
378 else
379 {
380 if (hasPointSprites)
381 {
382#if OO_SHADERS
383 if (!useShader)
384#endif
385 {
386 OOGL(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
387 }
388 OOGL(glEnable(GL_POINT_SPRITE_ARB));
389 [texture apply];
390 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
391 OOGL(glDrawArrays(GL_POINTS, 0, DUST_N_PARTICLES));
392 OOGL(glDisable(GL_POINT_SPRITE_ARB));
393 }
394 else
395 {
396 OOGL(glDisable(GL_TEXTURE_2D));
397 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertices));
398 OOGL(glDrawArrays(GL_POINTS, 0, DUST_N_PARTICLES));
399 OOGL(glEnable(GL_TEXTURE_2D));
400 }
401 }
402
403 // reapply normal conditions
404#if OO_SHADERS
405 if (useShader)
406 {
407 [OOShaderProgram applyNone];
408 }
409 else
410#endif
411 {
412 OOGL(glDisable(GL_FOG));
413 OOGL(glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA));
414 }
415
416 OOGL(glDisable(GL_BLEND));
417 OOGL(glDepthMask(GL_TRUE));
418
419 }
420 OOGL(glEnableClientState(GL_NORMAL_ARRAY));
421
423 OOCheckOpenGLErrors(@"DustEntity after drawing %@", self);
424}
425
426
427- (void) resetGraphicsState
428{
429#if OO_SHADERS
430 DESTROY(shader);
431 DESTROY(uniforms);
432
433 shaderMode = kShaderModeUnknown;
434
435 /* Duplicate vertex data. This is only required if we're switching from
436 non-shader mode to a shader mode, but let's KISS.
437 */
438 memcpy(vertices + DUST_N_PARTICLES, vertices, sizeof *vertices * DUST_N_PARTICLES);
439#endif
440}
441
442
443#ifndef NDEBUG
444- (NSString *) descriptionForObjDump
445{
446 // Don't include range and visibility flag as they're irrelevant.
447 return [self descriptionForObjDumpBasic];
448}
449#endif
450
451@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:833
unsigned isSunlit
Definition Entity.h:99
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
Definition OOColor.m:95
void registerClient:(id< OOGraphicsResetClient > client)
void unregisterClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
OOOpenGLExtensionManager * sharedManager()
BOOL haveExtension:(NSString *extension)
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()