Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
OOPlanetDrawable.m
Go to the documentation of this file.
1/*
2
3 OOPlanetDrawable.m
4
5 Oolite
6 Copyright (C) 2004-2013 Giles C Williams and contributors
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 MA 02110-1301, USA.
22
23 */
24
25#import "OOStellarBody.h"
26#if NEW_PLANETS
27
28
29#import "OOPlanetDrawable.h"
30#import "OOPlanetData.h"
32#import "OOOpenGL.h"
33#import "OOMacroOpenGL.h"
34#import "Universe.h"
35#import "MyOpenGLView.h"
36
37#ifndef NDEBUG
38#import "Entity.h"
39#import "OODebugGLDrawing.h"
40#import "OODebugFlags.h"
41#endif
42
43
44#define LOD_GRANULARITY ((float)(kOOPlanetDataLevels - 1))
45#define LOD_FACTOR (1.0 / 4.0)
46
47
48@interface OOPlanetDrawable (Private)
49
50- (void) recalculateTransform;
51
52- (void) debugDrawNormals;
53
54- (void) renderCommonParts;
55
56@end
57
58
59@implementation OOPlanetDrawable
60
61+ (instancetype) planetWithTextureName:(NSString *)textureName radius:(float)radius
62{
63 OOPlanetDrawable *result = [[[self alloc] init] autorelease];
64 [result setTextureName:textureName];
65 [result setRadius:radius];
66
67 return result;
68}
69
70
71+ (instancetype) atmosphereWithRadius:(float)radius
72{
73 OOPlanetDrawable *result = [[[self alloc] initAsAtmosphere] autorelease];
74 [result setRadius:radius];
75
76 return result;
77}
78
79
80- (id) init
81{
82 if ((self = [super init]))
83 {
84 _radius = 1.0f;
85 [self recalculateTransform];
86 [self setLevelOfDetail:0.5f];
87 }
88
89 return self;
90}
91
92
93- (id) initAsAtmosphere
94{
95 if ((self = [self init]))
96 {
97 _isAtmosphere = YES;
98 }
99
100 return self;
101}
102
103
104- (void) dealloc
105{
106 DESTROY(_material);
107
108 [super dealloc];
109}
110
111
112- (id) copyWithZone:(NSZone *)zone
113{
114 OOPlanetDrawable *copy = [[[self class] allocWithZone:zone] init];
115 [copy setMaterial:[self material]];
116 copy->_isAtmosphere = _isAtmosphere;
117 copy->_radius = _radius;
118 copy->_transform = _transform;
119 copy->_lod = _lod;
120
121 return copy;
122}
123
124
125- (OOMaterial *) material
126{
127 return _material;
128}
129
130
131- (void) setMaterial:(OOMaterial *)material
132{
133 [_material autorelease];
134 _material = [material retain];
135}
136
137
138- (NSString *) textureName
139{
140 return [_material name];
141}
142
143
144- (void) setTextureName:(NSString *)textureName
145{
146 if (![textureName isEqual:[self textureName]])
147 {
148 [_material release];
149 NSDictionary *spec = [@"{diffuse_map={repeat_s=yes;cube_map=yes};}" propertyList];
150 _material = [[OOSingleTextureMaterial alloc] initWithName:textureName configuration:spec];
151 }
152}
153
154
155- (float) radius
156{
157 return _radius;
158}
159
160
161- (void) setRadius:(float)radius
162{
163 _radius = fabsf(radius);
164 [self recalculateTransform];
165}
166
167
168- (float) levelOfDetail
169{
170 return (float)_lod / LOD_GRANULARITY;
171}
172
173
174- (void) setLevelOfDetail:(float)lod
175{
176 _lod = roundf(OOClamp_0_1_f(lod) * LOD_GRANULARITY);
177}
178
179
180- (void) calculateLevelOfDetailForViewDistance:(float)distance
181{
182 BOOL simple = [UNIVERSE reducedDetail];
183 float drawFactor = [[UNIVERSE gameView] viewSize].width / (simple ? 100.0 : 40.0);
184 float drawRatio2 = drawFactor * _radius / sqrtf(distance); // proportional to size on screen in pixels
185
186 float lod = sqrtf(drawRatio2 * LOD_FACTOR);
187 if (simple)
188 {
189 lod -= 0.5f / LOD_GRANULARITY; // Make LOD transitions earlier.
190 lod = OOClamp_0_max_f(lod, (LOD_GRANULARITY - 1) / LOD_GRANULARITY); // Don't use highest LOD.
191 }
192 [self setLevelOfDetail:lod];
193}
194
195
196- (void) renderOpaqueParts
197{
198 assert(_lod < kOOPlanetDataLevels);
199
201
202 [self renderCommonParts];
203
205
206}
207
208
209- (void) renderTranslucentParts
210{
211 assert(_lod < kOOPlanetDataLevels);
212
213 // yes, opaque - necessary changes made later
215
216 [self renderCommonParts];
217
219
220}
221
222
223- (void) renderTranslucentPartsOnOpaquePass
224{
225 assert(_lod < kOOPlanetDataLevels);
226
228
229 // yes, opaque - necessary changes made later
231
232 OOGL(glDisable(GL_DEPTH_TEST));
233 [self renderCommonParts];
234 OOGL(glEnable(GL_DEPTH_TEST));
235
237
238}
239
240
241- (void) renderCommonParts
242{
243 const OOPlanetDataLevel *data = &kPlanetData[_lod];
244
246
247 OOGL(glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT));
248 OOGL(glShadeModel(GL_SMOOTH));
249
250 if (_isAtmosphere)
251 {
252 OOGL(glEnable(GL_BLEND));
253 OOGL(glDepthMask(GL_FALSE));
254 }
255 else
256 {
257 OOGL(glDisable(GL_BLEND));
258 }
259
260 // Scale the ball.
262 OOGLMultModelView(_transform);
263
264 [_material apply];
265
266 OOGL(glEnable(GL_LIGHTING));
267 OOGL(glEnable(GL_TEXTURE_2D));
268
269#if OO_TEXTURE_CUBE_MAP
270 if ([_material wantsNormalsAsTextureCoordinates])
271 {
272 OOGL(glDisable(GL_TEXTURE_2D));
273 OOGL(glEnable(GL_TEXTURE_CUBE_MAP));
274 }
275#endif
276
277 OOGL(glDisableClientState(GL_COLOR_ARRAY));
278
279 OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
280
281 OOGL(glVertexPointer(3, GL_FLOAT, 0, kOOPlanetVertices));
282 if ([_material wantsNormalsAsTextureCoordinates])
283 {
284 OOGL(glTexCoordPointer(3, GL_FLOAT, 0, kOOPlanetVertices));
285 }
286 else
287 {
288 OOGL(glTexCoordPointer(2, GL_FLOAT, 0, kOOPlanetTexCoords));
289 }
290
291 // FIXME: instead of GL_RESCALE_NORMAL, consider copying and transforming the vertex array for each planet.
292 OOGL(glEnable(GL_RESCALE_NORMAL));
293 OOGL(glNormalPointer(GL_FLOAT, 0, kOOPlanetVertices));
294
295 OOGL(glDrawElements(GL_TRIANGLES, data->faceCount*3, data->type, data->indices));
296
297#ifndef NDEBUG
298 if ([UNIVERSE wireframeGraphics])
299 {
301 }
302#endif
303
304#if OO_TEXTURE_CUBE_MAP
305 if ([_material wantsNormalsAsTextureCoordinates])
306 {
307 OOGL(glEnable(GL_TEXTURE_2D));
308 OOGL(glDisable(GL_TEXTURE_CUBE_MAP));
309 }
310#endif
311
312
314#ifndef NDEBUG
315 if (gDebugFlags & DEBUG_DRAW_NORMALS) [self debugDrawNormals];
316#endif
317
319 OOGL(glPopAttrib());
320
321 OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
322
323}
324
325
326- (BOOL) hasOpaqueParts
327{
328 return !_isAtmosphere;
329}
330
331
332- (BOOL) hasTranslucentParts
333{
334 return _isAtmosphere;
335}
336
337
338- (GLfloat) collisionRadius
339{
340 return _radius;
341}
342
343
344- (GLfloat) maxDrawDistance
345{
346 // FIXME
347 return INFINITY;
348}
349
350
351- (BoundingBox) boundingBox
352{
353 return (BoundingBox){{ -_radius, -_radius, -_radius }, { _radius, _radius, _radius }};
354}
355
356
357- (void) setBindingTarget:(id<OOWeakReferenceSupport>)target
358{
359 [_material setBindingTarget:target];
360}
361
362
363- (void) dumpSelfState
364{
365 [super dumpSelfState];
366 OOLog(@"dumpState.planetDrawable", @"radius: %g", [self radius]);
367 OOLog(@"dumpState.planetDrawable", @"LOD: %g", [self levelOfDetail]);
368}
369
370
371- (void) recalculateTransform
372{
373 _transform = OOMatrixForScaleUniform(_radius);
374}
375
376
377#ifndef NDEBUG
378
379- (void) debugDrawNormals
380{
381 OODebugWFState state;
382
384
385 state = OODebugBeginWireframe(NO);
386
387 const OOPlanetDataLevel *data = &kPlanetData[_lod];
388 unsigned i;
389
390 OOGLBEGIN(GL_LINES);
391 for (i = 0; i < data->vertexCount; i++)
392 {
393 /* Fun sphere facts: the normalized coordinates of a point on a sphere at the origin
394 is equal to the object-space normal of the surface at that point.
395 Furthermore, we can construct the binormal (a vector pointing westward along the
396 surface) as the cross product of the normal with the Y axis. (This produces
397 singularities at the pole, but there have to be singularities according to the
398 Hairy Ball Theorem.) The tangent (a vector north along the surface) is then the
399 inverse of the cross product of the normal and binormal.
400
401 (This comment courtesy of the in-development planet shader.)
402 */
403 Vector v = make_vector(kOOPlanetVertices[i * 3], kOOPlanetVertices[i * 3 + 1], kOOPlanetVertices[i * 3 + 2]);
404 Vector n = v;
405 v = OOVectorMultiplyMatrix(v, _transform);
406
407 glColor3f(0.0f, 1.0f, 1.0f);
408 GLVertexOOVector(v);
409 GLVertexOOVector(vector_add(v, vector_multiply_scalar(n, _radius * 0.05)));
410
411 Vector b = cross_product(n, kBasisYVector);
412 Vector t = vector_flip(true_cross_product(n, b));
413
414 glColor3f(1.0f, 1.0f, 0.0f);
415 GLVertexOOVector(v);
416 GLVertexOOVector(vector_add(v, vector_multiply_scalar(t, _radius * 0.03)));
417
418 glColor3f(0.0f, 1.0f, 0.0f);
419 GLVertexOOVector(v);
420 GLVertexOOVector(vector_add(v, vector_multiply_scalar(b, _radius * 0.03)));
421 }
422 OOGLEND();
423
424 OODebugEndWireframe(state);
425}
426
427
428- (NSSet *) allTextures
429{
430 return [[self material] allTextures];
431}
432
433#endif
434
435@end
436
437#endif /* NEW_PLANETS */
NSUInteger gDebugFlags
Definition main.m:7
#define DESTROY(x)
Definition OOCocoa.h:77
@ DEBUG_DRAW_NORMALS
OOINLINE void OODebugDrawBasisAtOrigin(GLfloat scale)
void OODebugEndWireframe(OODebugWFState state)
OODebugWFState OODebugBeginWireframe(BOOL ignoreZ)
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OO_ENTER_OPENGL()
Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
Definition OOMatrix.m:129
void OOGLPushModelView(void)
void OOGLMultModelView(OOMatrix matrix)
OOMatrix OOGLPopModelView(void)
#define OOGLBEGIN
Definition OOOpenGL.h:253
@ OPENGL_STATE_OPAQUE
Definition OOOpenGL.h:123
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
#define OOGL(statement)
Definition OOOpenGL.h:251
#define OOGLEND
Definition OOOpenGL.h:254
const OOPlanetDataLevel kPlanetData[kOOPlanetDataLevels]
const GLfloat kOOPlanetVertices[kOOPlanetDataVertexCount *3]
const GLfloat kOOPlanetTexCoords[kOOPlanetDataVertexCount *2]
#define kOOPlanetDataLevels
const Vector kBasisYVector
Definition OOVector.m:30
#define UNIVERSE
Definition Universe.h:840
void applyNone()
Definition OOMaterial.m:80
void setTextureName:(NSString *textureName)
void setRadius:(float radius)
void setMaterial:(OOMaterial *material)
const void * indices