Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
PlanetEntity.m
Go to the documentation of this file.
1/*
2
3PlanetEntity.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 "PlanetEntity.h"
26
27#if !NEW_PLANETS
28
30
31#import "Universe.h"
32#import "AI.h"
33#import "TextureStore.h"
34#import "OOTexture.h"
35#import "OOTextureInternal.h" // For GL_TEXTURE_CUBE_MAP -- need to clean this up.
37#import "MyOpenGLView.h"
38#import "ShipEntityAI.h"
39#import "OOColor.h"
40#import "OOCharacter.h"
41#import "OOStringParsing.h"
42#import "PlayerEntity.h"
44#import "OODebugFlags.h"
46
47
48#if !OOLITE_MAC_OS_X
49#define NSIntegerMapKeyCallBacks NSIntMapKeyCallBacks
50#define NSIntegerMapValueCallBacks NSIntMapValueCallBacks
51#endif
52
53
54// straight C
55static Vector base_vertex_array[MAX_PLANET_VERTICES];
56static int base_terrain_array[MAX_PLANET_VERTICES];
57static unsigned next_free_vertex;
58static NSMapTable *sEdgeToVertex;
59
60static int n_triangles[MAX_SUBDIVIDE];
61static int triangle_start[MAX_SUBDIVIDE];
62static GLuint vertex_index_array[3*(20+80+320+1280+5120+20480)];
63
64static GLfloat texture_uv_array[MAX_PLANET_VERTICES * 2];
65
66
67@interface PlanetEntity (OOPrivate) <OOGraphicsResetClient>
68
69- (double) sqrtZeroDistance;
70
71- (void) drawModelWithVertexArraysAndSubdivision: (int) subdivide;
72
74
75
76- (void) initialiseBaseTerrainArray:(int) percent_land;
77- (void) paintVertex:(unsigned) vi :(int) seed;
78- (void) scaleVertices;
79
80- (id) initAsAtmosphereForPlanet:(PlanetEntity *)planet dictionary:(NSDictionary *)dict;
81- (void) setTextureColorForPlanet:(BOOL)isMain inSystem:(BOOL)isLocal;
82
83- (id) initMiniatureFromPlanet:(PlanetEntity*) planet withAlpha:(float) alpha;
84
85- (void) loadTexture:(NSDictionary *)configuration;
86- (OOTexture *) planetTextureWithInfo:(NSDictionary *)info;
87- (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias;
88
89- (void) deleteDisplayLists;
90
91- (void) setUseTexturedModel:(BOOL)flag;
92
93@end
94
95static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured);
96
97
98typedef struct
99{
100 unsigned v;
101 float s;
102 float t;
103} BaseFace;
104
105
106static const Vector kUntexturedVertices[] =
107{
108 { +0.000000, -0.850664, -0.525710 },
109 { +0.000000, -0.850664, +0.525710 },
110 { +0.000000, +0.850664, +0.525710 },
111 { +0.000000, +0.850664, -0.525710 },
112 { -0.525710, +0.000000, -0.850664 },
113 { +0.525710, +0.000000, -0.850664 },
114 { +0.525710, +0.000000, +0.850664 },
115 { -0.525710, +0.000000, +0.850664 },
116 { -0.850664, -0.525710, +0.000000 },
117 { -0.850664, +0.525710, +0.000000 },
118 { +0.850664, +0.525710, +0.000000 },
119 { +0.850664, -0.525710, +0.000000 }
120};
121
122static const BaseFace kUntexturedFaces[][3] =
123{
124 { { 9, +0.600000, +0.666667 }, { 7, +0.800000, +0.666667 }, { 8, +0.800000, +0.333333 } },
125 { { 8, +0.800000, +0.333333 }, { 4, +0.600000, +0.333333 }, { 9, +0.600000, +0.666667 } },
126 { { 3, +0.400000, +0.666667 }, { 9, +0.600000, +0.666667 }, { 4, +0.600000, +0.333333 } },
127 { { 8, +0.800000, +0.333333 }, { 0, +0.500000, +0.000000 }, { 4, +0.600000, +0.333333 } },
128 { { 7, +0.800000, +0.666667 }, { 1, +1.000000, +0.333333 }, { 8, +0.800000, +0.333333 } },
129 { { 2, +0.500000, +1.000000 }, { 7, +0.800000, +0.666667 }, { 9, +0.600000, +0.666667 } },
130 { { 2, +0.500000, +1.000000 }, { 9, +0.600000, +0.666667 }, { 3, +0.400000, +0.666667 } },
131 { { 1, +1.000000, +0.333333 }, { 0, +0.500000, +0.000000 }, { 8, +0.800000, +0.333333 } },
132 { { 4, +0.600000, +0.333333 }, { 0, +0.500000, +0.000000 }, { 5, +0.400000, +0.333333 } },
133 { { 5, +0.400000, +0.333333 }, { 3, +0.400000, +0.666667 }, { 4, +0.600000, +0.333333 } },
134 { { 6, +1.000000, +0.666667 }, { 1, +1.000000, +0.333333 }, { 7, +0.800000, +0.666667 } },
135 { { 7, +0.800000, +0.666667 }, { 2, +0.500000, +1.000000 }, { 6, +1.000000, +0.666667 } },
136 { { 1, +0.000000, +0.333333 }, { 11, +0.200000, +0.333333 }, { 0, +0.500000, +0.000000 } },
137 { { 3, +0.400000, +0.666667 }, { 10, +0.200000, +0.666667 }, { 2, +0.500000, +1.000000 } },
138 { { 0, +0.500000, +0.000000 }, { 11, +0.200000, +0.333333 }, { 5, +0.400000, +0.333333 } },
139 { { 5, +0.400000, +0.333333 }, { 10, +0.200000, +0.666667 }, { 3, +0.400000, +0.666667 } },
140 { { 1, +0.000000, +0.333333 }, { 6, +0.000000, +0.666667 }, { 11, +0.200000, +0.333333 } },
141 { { 6, +0.000000, +0.666667 }, { 2, +0.500000, +1.000000 }, { 10, +0.200000, +0.666667 } },
142 { { 5, +0.400000, +0.333333 }, { 11, +0.200000, +0.333333 }, { 10, +0.200000, +0.666667 } },
143 { { 11, +0.200000, +0.333333 }, { 6, +0.000000, +0.666667 }, { 10, +0.200000, +0.666667 } }
144};
145
146
147static const Vector kTexturedVertices[] =
148{
149 { +0.525731, +0.000000, +0.850651 },
150 { -0.525731, +0.000000, +0.850651 },
151 { +0.525731, +0.000000, -0.850651 },
152 { -0.525731, +0.000000, -0.850651 },
153 { +0.000000, +0.850651, +0.525731 },
154 { +0.000000, +0.850651, -0.525731 },
155 { +0.000000, -0.850651, +0.525731 },
156 { +0.000000, -0.850651, -0.525731 },
157 { -0.850651, +0.525731, +0.000000 },
158 { +0.850651, +0.525731, +0.000000 },
159 { -0.850651, -0.525731, +0.000000 },
160 { +0.850651, -0.525731, +0.000000 },
161 { +0.000000, +0.850651, -0.525731 },
162 { +0.525731, +0.000000, -0.850651 }
163};
164
165static const BaseFace kTexturedFaces[][3] =
166{
167 { { 1, +0.400000, +0.666667 }, { 0, +0.600000, +0.666667 }, { 6, +0.500000, +0.333333 } },
168 { { 3, +0.100000, +0.333333 }, { 2, -0.100000, +0.333333 }, { 5, +0.000000, +0.666667 } },
169 { { 4, +0.500000, +1.000000 }, { 0, +0.600000, +0.666667 }, { 1, +0.400000, +0.666667 } },
170 { { 4, +0.500000, +1.000000 }, { 1, +0.400000, +0.666667 }, { 8, +0.200000, +0.666667 } },
171 { { 12, +1.000000, +0.666667 }, { 13, +0.900000, +0.333333 }, { 9, +0.800000, +0.666667 } },
172 { { 5, +0.000000, +0.666667 }, { 4, +0.500000, +1.000000 }, { 8, +0.200000, +0.666667 } },
173 { { 6, +0.500000, +0.333333 }, { 0, +0.600000, +0.666667 }, { 11, +0.700000, +0.333333 } },
174 { { 7, +0.500000, +0.000000 }, { 2, -0.100000, +0.333333 }, { 3, +0.100000, +0.333333 } },
175 { { 7, +0.500000, +0.000000 }, { 3, +0.100000, +0.333333 }, { 10, +0.300000, +0.333333 } },
176 { { 7, +0.500000, +0.000000 }, { 6, +0.500000, +0.333333 }, { 11, +0.700000, +0.333333 } },
177 { { 8, +0.200000, +0.666667 }, { 1, +0.400000, +0.666667 }, { 10, +0.300000, +0.333333 } },
178 { { 8, +0.200000, +0.666667 }, { 3, +0.100000, +0.333333 }, { 5, +0.000000, +0.666667 } },
179 { { 9, +0.800000, +0.666667 }, { 0, +0.600000, +0.666667 }, { 4, +0.500000, +1.000000 } },
180 { { 9, +0.800000, +0.666667 }, { 13, +0.900000, +0.333333 }, { 11, +0.700000, +0.333333 } },
181 { { 9, +0.800000, +0.666667 }, { 4, +0.500000, +1.000000 }, { 12, +1.000000, +0.666667 } },
182 { { 10, +0.300000, +0.333333 }, { 1, +0.400000, +0.666667 }, { 6, +0.500000, +0.333333 } },
183 { { 10, +0.300000, +0.333333 }, { 3, +0.100000, +0.333333 }, { 8, +0.200000, +0.666667 } },
184 { { 10, +0.300000, +0.333333 }, { 6, +0.500000, +0.333333 }, { 7, +0.500000, +0.000000 } },
185 { { 11, +0.700000, +0.333333 }, { 0, +0.600000, +0.666667 }, { 9, +0.800000, +0.666667 } },
186 { { 11, +0.700000, +0.333333 }, { 13, +0.900000, +0.333333 }, { 7, +0.500000, +0.000000 } }
187};
188
189
190@implementation PlanetEntity
191
192- (id) init
193{
194 [self release];
195 [NSException raise:NSInternalInconsistencyException format:@"%s, believed dead, called.", __PRETTY_FUNCTION__];
196 return nil;
197}
198
199
200- (id) initAsAtmosphereForPlanet:(PlanetEntity *)planet dictionary:(NSDictionary *)dict
201{
202 BOOL procGen = [UNIVERSE doProcedurallyTexturedPlanets];
203
204 if (dict == nil) dict = [NSDictionary dictionary];
205
206 self = [super init];
207
208 int percent_land = 100 - [dict oo_intForKey:@"percent_cloud" defaultValue:100 - (3 + (gen_rnd_number() & 31)+(gen_rnd_number() & 31))];
209
210 polar_color_factor = 1.0;
211
212#define CLEAR_SKY_ALPHA 0.05
213#define CLOUD_ALPHA 0.50
214#define POLAR_CLEAR_SKY_ALPHA 0.34
215#define POLAR_CLOUD_ALPHA 0.75
216
217 amb_land[0] = gen_rnd_number() / 256.0;
218 amb_land[1] = gen_rnd_number() / 256.0;
219 amb_land[2] = gen_rnd_number() / 256.0;
220 amb_land[3] = CLEAR_SKY_ALPHA; // blue sky, zero clouds
221 amb_sea[0] = 0.5 + gen_rnd_number() / 512.0;
222 amb_sea[1] = 0.5 + gen_rnd_number() / 512.0;
223 amb_sea[2] = 0.5 + gen_rnd_number() / 512.0;
224 amb_sea[3] = CLOUD_ALPHA; // 50% opaque clouds
225 amb_polar_land[0] = gen_rnd_number() / 256.0;
226 amb_polar_land[1] = gen_rnd_number() / 256.0;
227 amb_polar_land[2] = gen_rnd_number() / 256.0;
228 amb_polar_land[3] = POLAR_CLEAR_SKY_ALPHA; // 34% gray clouds
229 amb_polar_sea[0] = 0.9 + gen_rnd_number() / 2560.0;
230 amb_polar_sea[1] = 0.9 + gen_rnd_number() / 2560.0;
231 amb_polar_sea[2] = 0.9 + gen_rnd_number() / 2560.0;
232 amb_polar_sea[3] = POLAR_CLOUD_ALPHA; // 75% clouds
233
234 // Colour overrides from dictionary
235 OOColor *clearSkyColor = nil;
236 OOColor *cloudColor = nil;
237 OOColor *polarClearSkyColor = nil;
238 OOColor *polarCloudColor = nil;
239 float cloudAlpha;
240
241
242 clearSkyColor = [OOColor colorWithDescription:[dict objectForKey:@"atmosphere_color"]];
243 cloudColor = [OOColor colorWithDescription:[dict objectForKey:@"cloud_color"]];
244 polarClearSkyColor = [OOColor colorWithDescription:[dict objectForKey:@"polar_atmosphere_color"]];
245 polarCloudColor = [OOColor colorWithDescription:[dict objectForKey:@"polar_cloud_color"]];
246 cloudAlpha = OOClamp_0_1_f([dict oo_floatForKey:@"cloud_alpha" defaultValue:1.0]);
247
248 if (clearSkyColor != nil)
249 {
250 [clearSkyColor getRed:&amb_land[0] green:&amb_land[1] blue:&amb_land[2] alpha:&amb_land[3]];
251 }
252
253 if (cloudColor != nil)
254 {
255 [cloudColor getRed:&amb_sea[0] green:&amb_sea[1] blue:&amb_sea[2] alpha:&amb_sea[3]];
256 }
257
258 if (polarClearSkyColor != nil)
259 {
260 [polarClearSkyColor getRed:&amb_polar_land[0] green:&amb_polar_land[1] blue:&amb_polar_land[2] alpha:&amb_polar_land[3]];
261 }
262 else if (clearSkyColor != nil)
263 {
264 memmove(amb_polar_land, amb_land, sizeof amb_polar_land);
265 amb_polar_land[3] = OOClamp_0_1_f(amb_polar_land[3] * (POLAR_CLEAR_SKY_ALPHA / CLEAR_SKY_ALPHA));
266 }
267
268 if (polarCloudColor != nil)
269 {
270 [polarCloudColor getRed:&amb_polar_sea[0] green:&amb_polar_sea[1] blue:&amb_polar_sea[2] alpha:&amb_polar_sea[3]];
271 }
272 else if (cloudColor != nil)
273 {
274 memmove(amb_polar_sea, amb_sea, sizeof amb_polar_sea);
275 amb_polar_sea[3] *= (POLAR_CLOUD_ALPHA / CLOUD_ALPHA);
276 }
277
278 //amb_land[3] is already 0.05
279 amb_sea[3] *= cloudAlpha;
280 amb_polar_land[3] *= cloudAlpha;
281 amb_polar_sea[3] *= cloudAlpha;
282
283 amb_sea[3] = OOClamp_0_1_f(amb_sea[3]);
284 amb_polar_sea[3] = OOClamp_0_1_f(amb_polar_sea[3]);
285
286 atmosphere = nil;
287
288 if (procGen)
289 {
290 RANROTSeed ranrotSavedSeed = RANROTGetFullSeed();
291 RNG_Seed saved_seed = currentRandomSeed();
292 cloudColor = [OOColor colorWithRed: amb_sea[0] green: amb_sea[1] blue: amb_sea[2] alpha: amb_sea[3]];
293 float cloud_bias = -0.01 * (float)percent_land;
294 float cloud_impress = 1.0 - cloud_bias;
295
296 _texture = [self cloudTextureWithCloudColor:cloudColor cloudImpress:cloud_impress cloudBias:cloud_bias];
297 [_texture retain];
298 isTextureImage = NO;
299
300 setRandomSeed(saved_seed);
301 RANROTSetFullSeed(ranrotSavedSeed);
302 }
303
304 if (!planet)
305 {
306 OOLogERR(@"planet.atmosphere.init.noPlanet", @"planet entity initAsAtmosphereForPlanet: no planet found.");
307 return self;
308 }
309
310 [self setOwner: planet];
311
312 position = [planet position];
313 orientation = [planet orientation];
314
316 collision_radius = planet->collision_radius + ATMOSPHERE_DEPTH; // atmosphere is 500m deep only
317 if (planet->planet_type == STELLAR_TYPE_MINIATURE)
318 collision_radius = planet->collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR*2.0; //not to scale: invisible otherwise
319
320 shuttles_on_ground = 0;
321 last_launch_time = 0.0;
322 shuttle_launch_interval = 3600.0;
323
324 scanClass = CLASS_NO_DRAW;
325
326 // orientation.w = M_SQRT1_2; // is already planet->orientation
327 // orientation.x = M_SQRT1_2;
328 // orientation.y = 0.0;
329 // orientation.z = 0.0;
330
331 planet_type = STELLAR_TYPE_ATMOSPHERE;
332
333 planet_seed = ranrot_rand(); // random set-up for vertex colours
334
335 [self setUseTexturedModel:YES];
336 [self initialiseBaseVertexArray];
337 [self initialiseBaseTerrainArray:percent_land];
338 unsigned i;
339 for (i = 0; i < next_free_vertex; i++)
340 {
341 [self paintVertex:i :planet_seed];
342 }
343
344 [self scaleVertices];
345
346 // set speed of rotation
347 rotational_velocity = [dict oo_floatForKey:@"atmosphere_rotational_velocity" defaultValue:[planet rotationalVelocity]*(0.9+(randf()*0.2))]; // 90-110% of planet rotation speed
348
349 root_planet = planet;
350
351 rotationAxis = vector_up_from_quaternion(orientation);
352
354
355 return self;
356}
357
358
359- (void) miniaturize
360{
361 planet_type = STELLAR_TYPE_MINIATURE;
362 shuttles_on_ground = 0;
363 last_launch_time = 0.0;
364 shuttle_launch_interval = 3600.0;
365 [self setStatus:STATUS_COCKPIT_DISPLAY];
366 collision_radius = [self collisionRadius] * PLANET_MINIATURE_FACTOR; // teeny tiny
367 [self scaleVertices];
368 if (atmosphere != nil)
369 {
370 atmosphere->collision_radius = collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR*2.0; //not to scale: invisible otherwise
371 [atmosphere scaleVertices];
372 }
373 rotational_velocity = 0.04;
374 rotationAxis = kBasisYVector;
375}
376
377
378- (id) initFromDictionary:(NSDictionary*)dict withAtmosphere:(BOOL)atmo andSeed:(Random_Seed)p_seed
379{
380 BOOL procGen = [UNIVERSE doProcedurallyTexturedPlanets];
381
382 if (dict == nil) dict = [NSDictionary dictionary];
383 RANROTSeed ranrotSavedSeed = RANROTGetFullSeed();
384
385 self = [super init];
386
387 planet_type = atmo ? STELLAR_TYPE_NORMAL_PLANET : STELLAR_TYPE_MOON;
388
389 if (atmo)
390 planet_seed = p_seed.a * 13 + p_seed.c * 11 + p_seed.e * 7; // pseudo-random set-up for vertex colours
391 else
392 planet_seed = p_seed.a * 7 + p_seed.c * 11 + p_seed.e * 13; // pseudo-random set-up for vertex colours
393
394 OOTexture *texture = [dict oo_objectOfClass:[OOTexture class] forKey:@"_oo_textureObject"];
395 if (texture != nil)
396 {
397 _texture = [texture retain];
398 isTextureImage = [dict oo_boolForKey:@"_oo_isExplicitlyTextured"];
399 }
400 else
401 {
402 NSDictionary *textureSpec = [dict oo_textureSpecifierForKey:@"texture" defaultName:nil];
403 if (textureSpec != nil)
404 {
405 [self loadTexture:textureSpec];
406 }
407
408// CIM: nothing actually uses textureSpec after the assignment below, so skip it
409/* if (textureSpec == nil && !procGen && !atmo)
410 {
411 // Moons use metal.png by default.
412 textureSpec = OOTextureSpecFromObject(@"metal.png", nil);
413 } */
414
415 NSString *seedStr = [dict oo_stringForKey:@"seed"];
416 if (seedStr != nil)
417 {
418 Random_Seed seed = RandomSeedFromString(seedStr);
419 if (!is_nil_seed(seed))
420 {
421 p_seed = seed;
422 }
423 else
424 {
425 OOLogERR(@"planet.fromDict", @"could not interpret \"%@\" as planet seed, using default.", seedStr);
426 }
427 }
428 }
429
431
432 NSMutableDictionary *planetInfo = [NSMutableDictionary dictionaryWithDictionary:[UNIVERSE generateSystemData:p_seed]];
433 int radius_km = [dict oo_intForKey:KEY_RADIUS
434 defaultValue:[planetInfo oo_intForKey:KEY_RADIUS]];
435 int techlevel = [dict oo_intForKey:KEY_TECHLEVEL
436 defaultValue:[planetInfo oo_intForKey:KEY_TECHLEVEL]];
437
438 shuttles_on_ground = 1 + floor(techlevel * 0.5);
439 last_launch_time = 0.0;
440 shuttle_launch_interval = 3600.0 / shuttles_on_ground; // all are launched in an hour
441
442 last_launch_time = [UNIVERSE getTime] + 30.0 - shuttle_launch_interval; // debug - launch 30s after player enters universe
443
444 collision_radius = radius_km * 10.0; // scale down by a factor of 100 !
445
446 scanClass = CLASS_NO_DRAW;
447
448 orientation.w = M_SQRT1_2;
449 orientation.x = M_SQRT1_2;
450 orientation.y = 0.0;
451 orientation.z = 0.0;
452
453 [self setUseTexturedModel:(procGen || _texture != nil)];
454
455 int percent_land = [planetInfo oo_intForKey:@"percent_land" defaultValue:24 + (gen_rnd_number() % 48)];
456 //if (isTextured) percent_land = atmo ? 0 :100; // moon/planet override
457
458 // save the current random number generator seed
459 RNG_Seed saved_seed = currentRandomSeed();
460
461 // For historical reasons, stir the PRNG vertexCount times.
462 unsigned i;
463 for (i = 0; i < vertexCount; i++) gen_rnd_number();
464
465 [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"land_fraction"];
466
467 polar_color_factor = [dict oo_doubleForKey:@"polar_color_factor" defaultValue:0.5f];
468
469 Vector land_hsb, sea_hsb, land_polar_hsb, sea_polar_hsb;
470
471 if (isTextureImage)
472 {
473 // standard overlay colours.
474 land_hsb.x = 0.0; land_hsb.y = 0.0; land_hsb.z = 1.0; // non-saturated fully bright (white)
475 sea_hsb.x = 0.0; sea_hsb.y = 1.0; sea_hsb.z = 1.0; // fully-saturated fully bright (red)
476 // override the mainPlanet texture colour...
477 [self setTextureColorForPlanet:!![dict objectForKey:@"mainForLocalSystem"] inSystem:[dict oo_boolForKey:@"mainForLocalSystem" defaultValue:NO]];
478 }
479 else
480 {
481 // random land & sea colours.
482 land_hsb.x = gen_rnd_number() / 256.0; land_hsb.y = gen_rnd_number() / 256.0; land_hsb.z = 0.5 + gen_rnd_number() / 512.0;
483 sea_hsb.x = gen_rnd_number() / 256.0; sea_hsb.y = gen_rnd_number() / 256.0; sea_hsb.z = 0.5 + gen_rnd_number() / 512.0;
484 while (dot_product(land_hsb,sea_hsb) > .80) // make sure land and sea colors differ significantly
485 {
486 sea_hsb.x = gen_rnd_number() / 256.0; sea_hsb.y = gen_rnd_number() / 256.0; sea_hsb.z = 0.5 + gen_rnd_number() / 512.0;
487 }
488
489 // assign land_hsb and sea_hsb overrides from planetinfo.plist if they're there.
490 ScanVectorFromString([dict objectForKey:@"land_hsb_color"], &land_hsb);
491 ScanVectorFromString([dict objectForKey:@"sea_hsb_color"], &sea_hsb);
492
493 // polar areas are brighter but have less color (closer to white)
494 land_polar_hsb.x = land_hsb.x; land_polar_hsb.y = (land_hsb.y / 4.0); land_polar_hsb.z = 1.0 - (land_hsb.z / 10.0);
495 sea_polar_hsb.x = sea_hsb.x; sea_polar_hsb.y = (sea_hsb.y / 4.0); sea_polar_hsb.z = 1.0 - (sea_hsb.z / 10.0);
496
497 OOColor *amb_land_color = [OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0];
498 OOColor *amb_sea_color = [OOColor colorWithHue:sea_hsb.x saturation:sea_hsb.y brightness:sea_hsb.z alpha:1.0];
499 OOColor *amb_polar_land_color = [OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0];
500 OOColor *amb_polar_sea_color = [OOColor colorWithHue:sea_polar_hsb.x saturation:sea_polar_hsb.y brightness:sea_polar_hsb.z alpha:1.0];
501
502 amb_land[0] = [amb_land_color redComponent];
503 amb_land[1] = [amb_land_color blueComponent];
504 amb_land[2] = [amb_land_color greenComponent];
505 amb_land[3] = 1.0;
506 amb_sea[0] = [amb_sea_color redComponent];
507 amb_sea[1] = [amb_sea_color blueComponent];
508 amb_sea[2] = [amb_sea_color greenComponent];
509 amb_sea[3] = 1.0;
510 amb_polar_land[0] = [amb_polar_land_color redComponent];
511 amb_polar_land[1] = [amb_polar_land_color blueComponent];
512 amb_polar_land[2] = [amb_polar_land_color greenComponent];
513 amb_polar_land[3] = 1.0;
514 amb_polar_sea[0] = [amb_polar_sea_color redComponent];
515 amb_polar_sea[1] = [amb_polar_sea_color blueComponent];
516 amb_polar_sea[2] = [amb_polar_sea_color greenComponent];
517 amb_polar_sea[3] = 1.0;
518
519 [planetInfo setObject:amb_land_color forKey:@"land_color"];
520 [planetInfo setObject:amb_sea_color forKey:@"sea_color"];
521 [planetInfo setObject:amb_polar_land_color forKey:@"polar_land_color"];
522 [planetInfo setObject:amb_polar_sea_color forKey:@"polar_sea_color"];
523 }
524
525 if (procGen && _texture == nil)
526 {
527 _texture = [self planetTextureWithInfo:planetInfo];
528 isTextureImage = NO;
529 [_texture retain];
530 }
531
532 [self initialiseBaseVertexArray];
533 [self initialiseBaseTerrainArray:percent_land];
534
535 for (i = 0; i < next_free_vertex; i++)
536 {
537 [self paintVertex:i :planet_seed];
538 }
539
540 [self scaleVertices];
541 // set speed of rotation
542 if ([dict objectForKey:@"rotational_velocity"])
543 {
544 rotational_velocity = [dict oo_floatForKey:@"rotational_velocity" defaultValue:0.01f * randf()]; // 0.0 .. 0.01 avr 0.005
545 }
546 else
547 {
548 rotational_velocity = [planetInfo oo_floatForKey:@"rotation_speed" defaultValue:0.002 * (0.5+0.5*randf())]; // 0.001 .. 0.002 avr 0.0015
549 rotational_velocity *= [planetInfo oo_floatForKey:@"rotation_speed_factor" defaultValue:1.0f];
550 }
551
552 // do atmosphere
553 NSDictionary *atmoDict = dict;
554 if (_texture != nil) atmoDict = [NSDictionary dictionaryWithObjectsAndKeys:@"0", @"percent_cloud", [NSNumber numberWithFloat:[planetInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0]], @"cloud_alpha", nil];
555 if (atmo) atmosphere = [[PlanetEntity alloc] initAsAtmosphereForPlanet:self dictionary:atmoDict];
556
557 setRandomSeed(saved_seed);
558 RANROTSetFullSeed(ranrotSavedSeed);
559
560 // set energy
561 energy = collision_radius * 1000.0;
562
563 root_planet = self;
564
565 rotationAxis = vector_up_from_quaternion(orientation);
566
567 /* MKW - rotate planet based on current time.
568 * - do it here so that we catch all planets (OXP-added and otherwise! */
569 int deltaT = floor(fmod([PLAYER clockTimeAdjusted], 86400));
570 quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * deltaT);
571
572 [self setStatus:STATUS_ACTIVE];
573
575
576 return self;
577}
578
579
580- (void) dealloc
581{
582 [self deleteDisplayLists];
583
584 DESTROY(atmosphere);
585 DESTROY(_texture);
586 DESTROY(_textureFileName);
587
589
590 [super dealloc];
591}
592
593
594- (NSString*) descriptionComponents
595{
596 NSString *typeString;
597 switch (planet_type)
598 {
600 typeString = @"STELLAR_TYPE_MINIATURE"; break;
602 typeString = @"STELLAR_TYPE_NORMAL_PLANET"; break;
604 typeString = @"STELLAR_TYPE_ATMOSPHERE"; break;
606 typeString = @"STELLAR_TYPE_MOON"; break;
607
608 default:
609 typeString = @"UNKNOWN";
610 }
611 return [NSString stringWithFormat:@"ID: %u position: %@ type: %@ radius: %.3fkm", [self universalID], HPVectorDescription([self position]), typeString, 0.001 * [self radius]];
612}
613
614
615- (BOOL) canCollide
616{
617 switch (planet_type)
618 {
621 return NO;
622 break;
625 case STELLAR_TYPE_SUN:
626 return YES;
627 break;
628 }
629 return YES;
630}
631
632
633- (BOOL) checkCloseCollisionWith:(Entity *)other
634{
635#ifndef NDEBUG
637 OOLog(@"planet.collide", @"PLANET Collision!");
638#endif
639
640 if (!other)
641 return NO;
642 if (other->isShip)
643 {
644 ShipEntity *ship = (ShipEntity *)other;
645 if ([ship behaviour] == BEHAVIOUR_LAND_ON_PLANET)
646 {
647 return NO;
648 }
649#ifndef NDEBUG
650 if ([ship reportAIMessages])
651 {
652 HPVector p1 = ship->position;
653 OOLog(@"planet.collide.shipHit", @"DEBUG: %@ %d collided with planet at (%.1f,%.1f,%.1f)",[ship name], [ship universalID], p1.x,p1.y,p1.z);
654 }
655#endif
656 }
657
658 return YES;
659}
660
661
662- (void) update:(OOTimeDelta) delta_t
663{
664 [super update:delta_t];
665 sqrt_zero_distance = sqrt(cam_zero_distance);
666
667 switch (planet_type)
668 {
670 // we have atmosphere in any case.
671 {
672 double alt = sqrt_zero_distance - collision_radius;
673 double atmo = 10.0 * (atmosphere->collision_radius - collision_radius); // effect starts at 10x the height of the clouds
674
675 if ((alt > 0)&&(alt <= atmo))
676 {
677 double aleph = (atmo - alt) / atmo;
678 if (aleph < 0.0) aleph = 0.0;
679 if (aleph > 1.0) aleph = 1.0;
680
681 [UNIVERSE setSkyColorRed:0.8 * aleph * aleph
682 green:0.8 * aleph * aleph
683 blue:0.9 * aleph
684 alpha:aleph];
685 }
686 else if (alt > 0 && alt <= atmo * 1.5)
687 {
688 /* Without this, if you leave the atmosphere at very low
689 * frame rates, you might still have skyalpha > 0 when you
690 * go sun-skimming. Since skyalpha > 0 simulates atmospheric
691 * friction and continually pumps heat into the ship, this
692 * is rapidly fatal - CIM */
693 [UNIVERSE setSkyColorRed:0.0f
694 green:0.0f
695 blue:0.0f
696 alpha:0.0f];
697 }
698 }
700 {
701 double ugt = [UNIVERSE getTime];
702
703 if ((shuttles_on_ground > 0)&&(ugt > last_launch_time + shuttle_launch_interval))
704 {
705 [self launchShuttle];
706 shuttles_on_ground--;
707 last_launch_time = ugt;
708 }
709 }
710
712 // normal planetary rotation
713 if (atmosphere) [atmosphere update:delta_t];
714 quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * delta_t);
715 [self orientationChanged];
716 break;
717
719 {
720 // atmospheric rotation
721 quaternion_rotate_about_axis(&orientation, rotationAxis, rotational_velocity * delta_t);
722 [self orientationChanged];
723 }
724 break;
725
726 case STELLAR_TYPE_SUN:
727 break;
728 }
729}
730
731
732- (void) setPosition:(HPVector)posn
733{
734 position = posn;
735 [atmosphere setPosition:posn];
736}
737
738
739- (void) setOrientation:(Quaternion)inOrientation
740{
741 rotationAxis = vector_up_from_quaternion(inOrientation);
742 [super setOrientation:inOrientation];
743 if (atmosphere) [atmosphere setOrientation:inOrientation];
744}
745
746
747- (void) setUseTexturedModel:(BOOL)flag
748{
749 if (flag)
750 {
751 useTexturedModel = YES;
752 vertexCount = sizeof kTexturedVertices / sizeof *kTexturedVertices;
753 }
754 else
755 {
756 useTexturedModel = NO;
757 vertexCount = sizeof kUntexturedVertices / sizeof *kTexturedVertices;
758 }
759}
760
761
762// TODO: some translucent stuff is drawn in the opaque pass, which is Naughty.
763- (void) drawImmediate:(bool)immediate translucent:(bool)translucent
764{
765 if ([UNIVERSE breakPatternHide] || translucent || immediate) return; // DON'T DRAW
766 GLfloat radWithAtmosphere = [self radius] + ATMOSPHERE_DEPTH;
767 if (radWithAtmosphere * radWithAtmosphere * 1.1 < cam_zero_distance)
768 {
769 // for some reason this check doesn't work when extremely close to
770 // the planet and with the horizon near the side of the frame (FP
771 // inaccuracy?)
772 if (![UNIVERSE viewFrustumIntersectsSphereAt:cameraRelativePosition withRadius:radWithAtmosphere])
773 {
774 // Don't draw
775 return;
776 }
777 }
778
779 [self drawUnconditionally];
780}
781
782
783- (void) drawUnconditionally
784{
785 uint8_t subdivideLevel = 2; // 4 is probably the maximum!
786
787 double drawFactor = [[UNIVERSE gameView] viewSize].width / 100.0;
788 double drawRatio2 = drawFactor * collision_radius / sqrt_zero_distance; // equivalent to size on screen in pixels
789
790 if (cam_zero_distance > 0.0)
791 {
792 subdivideLevel = 2 + floor(drawRatio2);
793 if (subdivideLevel > 4) subdivideLevel = 4;
794 }
795
796 if (planet_type == STELLAR_TYPE_MINIATURE)
797 {
798 subdivideLevel = [UNIVERSE reducedDetail]? 3 : 4; // max detail or less
799 }
800
801 lastSubdivideLevel = subdivideLevel; // record
802
804 OOGL(glPushAttrib(GL_ENABLE_BIT));
805
806// OOGL(glEnable(GL_LIGHTING));
807// OOGL(glEnable(GL_LIGHT1));
808 GLfloat specular[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
809 OOGL(glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular));
810 OOGL(glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0));
811
812 /*
813
814 The depth test gets disabled in parts of this and instead
815 we rely on the painters algorithm instead.
816
817 The depth buffer isn't granular enough to cope with huge objects at vast
818 distances.
819
820 */
821
822 BOOL ignoreDepthBuffer = (planet_type == STELLAR_TYPE_ATMOSPHERE);
823
824 if (cam_zero_distance > collision_radius * collision_radius * 25) // is 'far away'
825 {
826 ignoreDepthBuffer |= YES;
827 }
828
829 [_texture ensureFinishedLoading];
830
831 switch (planet_type)
832 {
834 if (root_planet)
835 {
836 subdivideLevel = root_planet->lastSubdivideLevel; // copy it from the planet (stops jerky LOD and such)
837 }
838 OOGLMultModelVew(rotMatrix); // rotate the clouds!
839 OOGL(glEnable(GL_BLEND));
840// OOGL(glDisable(GL_LIGHTING));
841 // Fall through.
842
846 //if ((gDebugFlags & DEBUG_WIREFRAME_GRAPHICS)
847 if ([UNIVERSE wireframeGraphics])
848 {
849 // Drop the detail level a bit, it still looks OK in wireframe and does not penalize
850 // the system that much.
851 subdivideLevel = 2;
853 }
854
855 {
856 GLfloat mat1[] = { 1.0, 1.0, 1.0, 1.0 }; // opaque white
857
858 if (_texture != nil)
859 {
860 if ([_texture isCubeMap])
861 {
862#if OO_TEXTURE_CUBE_MAP
863 OOGL(glDisable(GL_TEXTURE_2D));
864 OOGL(glEnable(GL_TEXTURE_CUBE_MAP));
865#endif
866 }
867 else
868 {
869// OOGL(glEnable(GL_TEXTURE_2D));
870 }
871 OOGL(glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mat1));
872 [_texture apply];
873 }
874 else
875 {
876 OOGL(glDisable(GL_TEXTURE_2D));
878 }
879
880 OOGL(glShadeModel(GL_SMOOTH));
881
882 // far enough away to draw flat ?
883 if (ignoreDepthBuffer)
884 {
885 OOGL(glDisable(GL_DEPTH_TEST));
886 }
887
888 OOGL(glColor4fv(mat1));
889 OOGL(glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat1));
890
891 OOGL(glEnableClientState(GL_COLOR_ARRAY));
892 OOGL(glColorPointer(4, GL_FLOAT, 0, vertexdata.color_array));
893// OOGL(glEnableClientState(GL_VERTEX_ARRAY));
894 OOGL(glVertexPointer(3, GL_FLOAT, 0, vertexdata.vertex_array));
895// OOGL(glEnableClientState(GL_NORMAL_ARRAY));
896 OOGL(glNormalPointer(GL_FLOAT, 0, vertexdata.normal_array));
897
898 if (_texture != nil)
899 {
900 OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
901 if ([_texture isCubeMap])
902 {
903 OOGL(glTexCoordPointer(3, GL_FLOAT, 0, vertexdata.vertex_array));
904 }
905 else
906 {
907 OOGL(glTexCoordPointer(2, GL_FLOAT, 0, vertexdata.uv_array));
908 }
909 }
910 else
911 {
912 OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
913 }
914
915 if (displayListNames[subdivideLevel] != 0)
916 {
917 OOGL(glCallList(displayListNames[subdivideLevel]));
918 }
919 else
920 {
921
922 OOGL(displayListNames[subdivideLevel] = glGenLists(1));
923 if (displayListNames[subdivideLevel] != 0) // sanity check
924 {
925 OOGL(glNewList(displayListNames[subdivideLevel], GL_COMPILE_AND_EXECUTE));
926
927 OOGL(glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE));
928 OOGL(glEnable(GL_COLOR_MATERIAL));
929
930 [self drawModelWithVertexArraysAndSubdivision:subdivideLevel];
931
932 OOGL(glDisable(GL_COLOR_MATERIAL));
933 OOGL(glEndList());
934 }
935 }
936
937#if OO_TEXTURE_CUBE_MAP
938 if ([_texture isCubeMap])
939 {
940 OOGL(glDisable(GL_TEXTURE_CUBE_MAP));
941 OOGL(glEnable(GL_TEXTURE_2D));
942 }
943#endif
944
945 OOGL(glDisableClientState(GL_COLOR_ARRAY));
946 OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
947 OOGL(glEnable(GL_DEPTH_TEST));
948
949 }
950
951 //if ((gDebugFlags & DEBUG_WIREFRAME_GRAPHICS)
952 if ([UNIVERSE wireframeGraphics])
953 {
955 }
956// OOGL(glDisableClientState(GL_VERTEX_ARRAY));
957// OOGL(glDisableClientState(GL_NORMAL_ARRAY));
958
959 break;
960
961 case STELLAR_TYPE_SUN:
962 break;
963 }
964
965 if (ignoreDepthBuffer)
966 {
967 OOGL(glEnable(GL_DEPTH_TEST));
968 }
969 OOGL(glEnable(GL_TEXTURE_2D));
970// OOGL(glEnable(GL_LIGHTING));
971 OOGL(glDisable(GL_BLEND));
972
973
974 OOGL(glPopAttrib());
976 OOCheckOpenGLErrors(@"PlanetEntity after drawing %@", self);
977
978 if (atmosphere)
979 {
980 OOGLPopModelView(); // get old draw matrix back
981 OOGLPushModelView(); // and store it again
982 OOGLTranslateModelView(cameraRelativePosition); // centre on the planet
983 // rotate
984// OOGLMultModelView([atmosphere rotationMatrix]);
985 // draw atmosphere entity
986 [atmosphere drawImmediate:false translucent:false];
987 }
988
989
990}
991
992
993#ifndef NDEBUG
994- (PlanetEntity *) atmosphere
995{
996 return atmosphere;
997}
998#endif
999
1000
1001- (int) planet_seed
1002{
1003 return planet_seed;
1004}
1005
1006
1007- (BOOL) isTextured
1008{
1009 return _texture != nil;
1010}
1011
1012
1013- (NSString *) textureFileName
1014{
1015 return _textureFileName;
1016}
1017
1018
1019- (void) setTextureColorForPlanet:(BOOL)isMain inSystem:(BOOL)isLocal
1020{
1021 Vector land_hsb, land_polar_hsb;
1022 land_hsb.x = 0.0; land_hsb.y = 0.0; land_hsb.z = 1.0; // white
1023
1024 // the colour override should only apply to main planets
1025 if (isMain)
1026 {
1027 if (isLocal) ScanVectorFromString([[UNIVERSE currentSystemData] objectForKey:@"texture_hsb_color"], &land_hsb);
1028 else ScanVectorFromString([[UNIVERSE generateSystemData:[PLAYER target_system_seed]] objectForKey:@"texture_hsb_color"], &land_hsb);
1029 }
1030
1031 land_polar_hsb.x = land_hsb.x; land_polar_hsb.y = (land_hsb.y / 5.0); land_polar_hsb.z = 1.0 - (land_hsb.z / 10.0);
1032
1033 amb_sea[0] = amb_land[0] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] redComponent];
1034 amb_sea[1] = amb_land[1] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] blueComponent];
1035 amb_sea[2] = amb_land[2] = [[OOColor colorWithHue:land_hsb.x saturation:land_hsb.y brightness:land_hsb.z alpha:1.0] greenComponent];
1036 amb_sea[3] = amb_land[3] = 1.0;
1037 amb_polar_sea[0] =amb_polar_land[0] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] redComponent];
1038 amb_polar_sea[1] =amb_polar_land[1] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] blueComponent];
1039 amb_polar_sea[2] = amb_polar_land[2] = [[OOColor colorWithHue:land_polar_hsb.x saturation:land_polar_hsb.y brightness:land_polar_hsb.z alpha:1.0] greenComponent];
1040 amb_polar_sea[3] =amb_polar_land[3] = 1.0;
1041}
1042
1043
1044- (BOOL) setUpPlanetFromTexture:(NSString *)fileName
1045{
1046 if (fileName == nil) return NO;
1047
1048 [self loadTexture:OOTextureSpecFromObject(fileName, nil)];
1049 [self deleteDisplayLists];
1050
1051 unsigned i;
1052 [self setUseTexturedModel:YES];
1053
1054 // recolour main planet according to "texture_hsb_color"
1055 // this function is only called for local systems!
1056 [self setTextureColorForPlanet:([UNIVERSE planet] == self) inSystem:YES];
1057
1058 [self initialiseBaseVertexArray];
1059 [self initialiseBaseTerrainArray:100];
1060 for (i = 0; i < next_free_vertex; i++)
1061 {
1062 [self paintVertex:i :planet_seed];
1063 }
1064
1065 [self scaleVertices];
1066
1067 GLfloat oldCloudAlpha = 0.0;
1068 if (atmosphere)
1069 {
1070 oldCloudAlpha = [atmosphere amb_sea][3] / CLOUD_ALPHA;
1071 }
1072
1073 NSDictionary *atmo_dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"0", @"percent_cloud", [NSNumber numberWithFloat:oldCloudAlpha], @"cloud_alpha", nil];
1074 [atmosphere autorelease];
1075 atmosphere = [self hasAtmosphere] ? [[PlanetEntity alloc] initAsAtmosphereForPlanet:self dictionary:atmo_dictionary] : nil;
1076
1077 //rotationAxis = vector_up_from_quaternion(orientation);
1078
1079 return [self isTextured];
1080}
1081
1082
1083- (double) polar_color_factor
1084{
1085 return polar_color_factor;
1086}
1087
1088
1089- (GLfloat *) amb_land
1090{
1091 return amb_land;
1092}
1093
1094
1095- (GLfloat *) amb_polar_land
1096{
1097 return amb_polar_land;
1098}
1099
1100
1101- (GLfloat *) amb_sea
1102{
1103 return amb_sea;
1104}
1105
1106
1107- (GLfloat *) amb_polar_sea
1108{
1109 return amb_polar_sea;
1110}
1111
1112
1113- (OOStellarBodyType) planetType
1114{
1115 return planet_type;
1116}
1117
1118
1119- (void) setPlanetType:(OOStellarBodyType) pt
1120{
1121 planet_type = pt;
1122}
1123
1124
1125- (double) radius
1126{
1127 return collision_radius;
1128}
1129
1130
1131- (void) setRadius:(GLfloat) rad
1132{
1133 collision_radius = rad;
1134}
1135
1136- (double) rotationalVelocity
1137{
1138 return rotational_velocity;
1139}
1140
1141- (void) setRotationalVelocity:(double) v
1142{
1143 if (atmosphere) // change rotation speed proportionally
1144 {
1145 [atmosphere setRotationalVelocity:[atmosphere rotationalVelocity] * v / [self rotationalVelocity]];
1146 }
1147 rotational_velocity = v;
1148}
1149
1150
1151- (double) sqrtZeroDistance
1152{
1153 return sqrt_zero_distance;
1154}
1155
1156
1157- (BOOL) hasAtmosphere
1158{
1159 return atmosphere != nil;
1160}
1161
1162
1163- (void) drawModelWithVertexArraysAndSubdivision: (int) subdivide
1164{
1165 OOGL(glDrawElements(GL_TRIANGLES, 3 * n_triangles[subdivide], GL_UNSIGNED_INT, &vertexdata.index_array[triangle_start[subdivide]]));
1166}
1167
1168
1169- (void) launchShuttle
1170{
1171 ShipEntity *shuttle_ship;
1172 Quaternion q1;
1173 HPVector launch_pos = position;
1174 double start_distance = collision_radius + 125.0;
1175
1177
1178 Vector vf = vector_forward_from_quaternion(q1);
1179
1180 launch_pos.x += start_distance * vf.x;
1181 launch_pos.y += start_distance * vf.y;
1182 launch_pos.z += start_distance * vf.z;
1183
1184 shuttle_ship = [UNIVERSE newShipWithRole:@"shuttle"]; // retain count = 1
1185 if (shuttle_ship)
1186 {
1187 if (![shuttle_ship crew])
1188 {
1189 [shuttle_ship setSingleCrewWithRole:@"trader"];
1190 }
1191
1192 [shuttle_ship setPosition:launch_pos];
1193 [shuttle_ship setOrientation:q1];
1194
1195 [shuttle_ship setScanClass: CLASS_NEUTRAL];
1196 [shuttle_ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
1197 [shuttle_ship switchAITo:@"oolite-shuttleAI.js"];
1198 [UNIVERSE addEntity:shuttle_ship];
1199
1200 [shuttle_ship release];
1201 }
1202}
1203
1204
1205- (void) welcomeShuttle:(ShipEntity *) shuttle
1206{
1207 shuttles_on_ground++;
1208}
1209
1210
1212{
1213 BOOL isTextured = [self isTextured];
1214 static BOOL lastOneWasTextured;
1215
1216 if (lastOneWasTextured != isTextured)
1217 {
1218 if (sEdgeToVertex != NULL)
1219 {
1220 NSFreeMapTable(sEdgeToVertex);
1221 sEdgeToVertex = NULL;
1222 }
1223 lastOneWasTextured = isTextured;
1224 }
1225
1226 if (sEdgeToVertex == NULL)
1227 {
1228 sEdgeToVertex = NSCreateMapTable(NSIntegerMapKeyCallBacks, NSIntegerMapValueCallBacks, 7680); // make a new one
1229 next_free_vertex = 0;
1230
1231 const Vector *vertices = NULL;
1232 const BaseFace (*faces)[3] = NULL;
1233 GLuint faceCount = 0;
1234 if (useTexturedModel)
1235 {
1236 vertices = kTexturedVertices;
1237 faces = kTexturedFaces;
1238 faceCount = sizeof kTexturedFaces / sizeof *kTexturedFaces;
1239 }
1240 else
1241 {
1242 vertices = kUntexturedVertices;
1243 faces = kUntexturedFaces;
1244 faceCount = sizeof kUntexturedFaces / sizeof *kUntexturedFaces;
1245 }
1246
1247 // set first 12 or 14 vertices
1248 GLuint vi;
1249 for (vi = 0; vi < vertexCount; vi++)
1250 {
1251 base_vertex_array[next_free_vertex++] = vertices[vi];
1252 }
1253
1254 // set first 20 triangles
1255 triangle_start[0] = 0;
1256 n_triangles[0] = faceCount;
1257 GLuint fi;
1258 for (fi = 0; fi < faceCount; fi++)
1259 {
1260 unsigned j;
1261 for (j = 0; j < 3; j++)
1262 {
1263 vertex_index_array[fi * 3 + j] = faces[fi][j].v;
1264 texture_uv_array[faces[fi][j].v * 2 + 0] = faces[fi][j].s;
1265 texture_uv_array[faces[fi][j].v * 2 + 1] = faces[fi][j].t;
1266 }
1267 }
1268
1269 // for the next levels of subdivision simply build up from the level below!...
1270 unsigned sublevel;
1271 for (sublevel = 0; sublevel < MAX_SUBDIVIDE - 1; sublevel++)
1272 {
1273 int newlevel = sublevel + 1;
1274 triangle_start[newlevel] = triangle_start[sublevel] + n_triangles[sublevel] * 3;
1275 n_triangles[newlevel] = n_triangles[sublevel] * 4;
1276
1277 int tri;
1278 for (tri = 0; tri < n_triangles[sublevel]; tri++)
1279 {
1280 // get the six vertices for this group of four triangles
1281 int v0 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 0];
1282 int v1 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 1];
1283 int v2 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 2];
1284 int v01 = baseVertexIndexForEdge(v0, v1, isTextured); // sets it up if required
1285 int v12 = baseVertexIndexForEdge(v1, v2, isTextured); // ..
1286 int v20 = baseVertexIndexForEdge(v2, v0, isTextured); // ..
1287 // v0 v01 v20
1288 vertex_index_array[triangle_start[newlevel] + tri * 12 + 0] = v0;
1289 vertex_index_array[triangle_start[newlevel] + tri * 12 + 1] = v01;
1290 vertex_index_array[triangle_start[newlevel] + tri * 12 + 2] = v20;
1291 // v01 v1 v12
1292 vertex_index_array[triangle_start[newlevel] + tri * 12 + 3] = v01;
1293 vertex_index_array[triangle_start[newlevel] + tri * 12 + 4] = v1;
1294 vertex_index_array[triangle_start[newlevel] + tri * 12 + 5] = v12;
1295 // v20 v12 v2
1296 vertex_index_array[triangle_start[newlevel] + tri * 12 + 6] = v20;
1297 vertex_index_array[triangle_start[newlevel] + tri * 12 + 7] = v12;
1298 vertex_index_array[triangle_start[newlevel] + tri * 12 + 8] = v2;
1299 // v01 v12 v20
1300 vertex_index_array[triangle_start[newlevel] + tri * 12 + 9] = v01;
1301 vertex_index_array[triangle_start[newlevel] + tri * 12 +10] = v12;
1302 vertex_index_array[triangle_start[newlevel] + tri * 12 +11] = v20;
1303
1304 }
1305 }
1306 }
1307
1308 // all done - copy the indices to the instance
1309 unsigned i;
1310 for (i = 0; i < MAX_TRI_INDICES; i++)
1311 {
1312 vertexdata.index_array[i] = vertex_index_array[i];
1313 }
1314}
1315
1316
1317static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured)
1318{
1319 if (va < vb)
1320 {
1321 GLushort temp = va;
1322 va = vb;
1323 vb = temp;
1324 }
1325 void *key = (void *)(((uintptr_t)va << 16) | vb);
1326 uintptr_t num = (uintptr_t)NSMapGet(sEdgeToVertex, key);
1327 if (num != 0)
1328 {
1329 // Overall cache hit rate is just over 83 %.
1330 return (unsigned)num - 1;
1331 }
1332 else
1333 {
1334 unsigned vindex = next_free_vertex++;
1335 NSCAssert(vindex < sizeof base_vertex_array / sizeof *base_vertex_array, @"Vertex array overflow in planet setup.");
1336
1337 // calculate position of new vertex
1338 Vector pos = vector_add(base_vertex_array[va], base_vertex_array[vb]);
1339 pos = vector_normal(pos); // guaranteed non-zero
1340 base_vertex_array[vindex] = pos;
1341
1342 if (textured)
1343 {
1344 //calculate new texture coordinates
1345 NSPoint uva = (NSPoint){ texture_uv_array[va * 2], texture_uv_array[va * 2 + 1] };
1346 NSPoint uvb = (NSPoint){ texture_uv_array[vb * 2], texture_uv_array[vb * 2 + 1] };
1347
1348 // if either of these is the polar vertex treat it specially to help with polar distortion:
1349 if (uva.y == 0.0 || uva.y == 1.0) uva.x = uvb.x;
1350 if (uvb.y == 0.0 || uvb.y == 1.0) uvb.x = uva.x;
1351
1352 texture_uv_array[vindex * 2] = 0.5 * (uva.x + uvb.x);
1353 texture_uv_array[vindex * 2 + 1] = 0.5 * (uva.y + uvb.y);
1354 }
1355
1356 // add new edge to the look-up
1357 num = vindex + 1;
1358 NSMapInsertKnownAbsent(sEdgeToVertex, key, (void *)num);
1359 return vindex;
1360 }
1361}
1362
1363
1364- (void) initialiseBaseTerrainArray:(int) percent_land
1365{
1366 RANROTSeed saved_seed = RANROTGetFullSeed();
1367
1368 // set first 12 or 14 vertices
1369 if (percent_land >= 0)
1370 {
1371 GLuint vi;
1372 for (vi = 0; vi < vertexCount; vi++)
1373 {
1374 if (gen_rnd_number() < 256 * percent_land / 100)
1375 base_terrain_array[vi] = 0; // land
1376 else
1377 base_terrain_array[vi] = 100; // sea
1378
1379 }
1380 }
1381
1382 // for the next levels of subdivision simply build up from the level below!...
1383 BOOL isTextured = [self isTextured];
1384
1385 int sublevel;
1386 for (sublevel = 0; sublevel < MAX_SUBDIVIDE - 1; sublevel++)
1387 {
1388 int tri;
1389 for (tri = 0; tri < n_triangles[sublevel]; tri++)
1390 {
1391 // get the six vertices for this group of four triangles
1392 int v0 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 0];
1393 int v1 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 1];
1394 int v2 = vertex_index_array[triangle_start[sublevel] + tri * 3 + 2];
1395 int v01 = baseVertexIndexForEdge(v0, v1, isTextured); // sets it up if required
1396 int v12 = baseVertexIndexForEdge(v1, v2, isTextured); // ..
1397 int v20 = baseVertexIndexForEdge(v2, v0, isTextured); // ..
1398 // v01
1401 else
1402 {
1403 uint32_t s1 = 0xffff0000 * base_vertex_array[v01].x;
1404 uint32_t s2 = 0x00ffff00 * base_vertex_array[v01].y;
1405 uint32_t s3 = 0x0000ffff * base_vertex_array[v01].z;
1406 ranrot_srand(s1+s2+s3);
1407 base_terrain_array[v01] = (ranrot_rand() & 4) *25;
1408 }
1409 // v12
1412 else
1413 {
1414 uint32_t s1 = 0xffff0000 * base_vertex_array[v12].x;
1415 uint32_t s2 = 0x00ffff00 * base_vertex_array[v12].y;
1416 uint32_t s3 = 0x0000ffff * base_vertex_array[v12].z;
1417 ranrot_srand(s1+s2+s3);
1418 base_terrain_array[v12] = (ranrot_rand() & 4) *25;
1419 }
1420 // v20
1423 else
1424 {
1425 uint32_t s1 = 0xffff0000 * base_vertex_array[v20].x;
1426 uint32_t s2 = 0x00ffff00 * base_vertex_array[v20].y;
1427 uint32_t s3 = 0x0000ffff * base_vertex_array[v20].z;
1428 ranrot_srand(s1+s2+s3);
1429 base_terrain_array[v20] = (ranrot_rand() & 4) *25;
1430 }
1431 }
1432 }
1433
1434 RANROTSetFullSeed(saved_seed);
1435}
1436
1437
1438- (void) paintVertex:(unsigned) vi :(int) seed
1439{
1440 RANROTSeed saved_seed = RANROTGetFullSeed();
1441 BOOL isTextured = _texture != nil;
1442
1443 GLfloat paint_land[4] = { 0.2, 0.9, 0.0, 1.0};
1444 GLfloat paint_sea[4] = { 0.0, 0.2, 0.9, 1.0};
1445 GLfloat paint_color[4];
1446 Vector v = base_vertex_array[vi];
1447 int r = isTextured ? 0 : base_terrain_array[vi]; // use land color (0) for textured planets
1448 int i;
1449 double pole_blend = v.z * v.z * polar_color_factor;
1450 if (pole_blend < 0.0) pole_blend = 0.0;
1451 if (pole_blend > 1.0) pole_blend = 1.0;
1452
1453 paint_land[0] = (1.0 - pole_blend)*amb_land[0] + pole_blend*amb_polar_land[0];
1454 paint_land[1] = (1.0 - pole_blend)*amb_land[1] + pole_blend*amb_polar_land[1];
1455 paint_land[2] = (1.0 - pole_blend)*amb_land[2] + pole_blend*amb_polar_land[2];
1456 paint_sea[0] = (1.0 - pole_blend)*amb_sea[0] + pole_blend*amb_polar_sea[0];
1457 paint_sea[1] = (1.0 - pole_blend)*amb_sea[1] + pole_blend*amb_polar_sea[1];
1458 paint_sea[2] = (1.0 - pole_blend)*amb_sea[2] + pole_blend*amb_polar_sea[2];
1459 if (planet_type == STELLAR_TYPE_ATMOSPHERE) // do alphas
1460 {
1461 paint_land[3] = (1.0 - pole_blend)*amb_land[3] + pole_blend*amb_polar_land[3];
1462 paint_sea[3] = (1.0 - pole_blend)*amb_sea[3] + pole_blend*amb_polar_sea[3];
1463 }
1464
1465 ranrot_srand((uint32_t)(seed+v.x*1000+v.y*100+v.z*10));
1466
1467 for (i = 0; i < 3; i++)
1468 {
1469 double cv = (ranrot_rand() % 100)*0.01; // 0..1 ***** DON'T CHANGE THIS LINE, '% 100' MAY NOT BE EFFICIENT BUT THE PATTERNING IS GOOD.
1470 paint_land[i] += (cv - 0.5)*0.1;
1471 paint_sea[i] += (cv - 0.5)*0.1;
1472 }
1473
1474 for (i = 0; i < 4; i++)
1475 {
1476 if (planet_type == STELLAR_TYPE_ATMOSPHERE && isTextured)
1477 paint_color[i] = 1.0;
1478 else
1479 paint_color[i] = (r * paint_sea[i])*0.01 + ((100 - r) * paint_land[i])*0.01;
1480 // finally initialise the color array entry
1481 vertexdata.color_array[vi*4 + i] = paint_color[i];
1482 }
1483
1484 RANROTSetFullSeed(saved_seed);
1485}
1486
1487
1488- (void) scaleVertices
1489{
1490 NSUInteger vi;
1491 for (vi = 0; vi < next_free_vertex; vi++)
1492 {
1493 Vector v = base_vertex_array[vi];
1494 vertexdata.normal_array[vi] = v;
1495 vertexdata.vertex_array[vi] = make_vector(v.x * collision_radius, v.y * collision_radius, v.z * collision_radius);
1496
1497 vertexdata.uv_array[vi * 2] = texture_uv_array[vi * 2];
1498 vertexdata.uv_array[vi * 2 + 1] = texture_uv_array[vi * 2 + 1];
1499 }
1500}
1501
1502
1503- (void) deleteDisplayLists
1504{
1505 unsigned i;
1506 for (i = 0; i < MAX_SUBDIVIDE; i++)
1507 {
1508 if (displayListNames[i] != 0)
1509 {
1510 glDeleteLists(displayListNames[i], 1);
1511 displayListNames[i] = 0;
1512 }
1513 }
1514}
1515
1516
1517- (void)resetGraphicsState
1518{
1519 [self deleteDisplayLists];
1520}
1521
1522
1523- (BOOL) isExplicitlyTextured
1524{
1525 return isTextureImage;
1526}
1527
1528
1529- (OOTexture *) texture
1530{
1531 return _texture;
1532}
1533
1534
1535- (void) loadTexture:(NSDictionary *)configuration
1536{
1537 [_texture release];
1538 _texture = [OOTexture textureWithConfiguration:configuration extraOptions:kOOTextureAllowCubeMap | kOOTextureRepeatS];
1539 [_texture retain];
1540
1541 [_textureFileName release];
1542 if (_texture != nil)
1543 {
1544 _textureFileName = [[configuration oo_stringForKey:@"name"] copy];
1545 isTextureImage = YES;
1546 }
1547 else
1548 {
1549 _textureFileName = nil;
1550 isTextureImage = NO;
1551 }
1552}
1553
1554
1555/* Ideally, these would use OOPlanetTextureGenerator. However, it isn't
1556 designed to use separate invocations for diffuse and cloud generation,
1557 while old-style PlanetEntity calls these from different places for
1558 different objects.
1559 -- Ahruman 2010-06-04
1560*/
1561- (OOTexture *) planetTextureWithInfo:(NSDictionary *)info
1562{
1563 unsigned char *data;
1564 GLuint width, height;
1565
1567 if (![TextureStore getPlanetTextureNameFor:info
1568 intoData:&data
1569 width:&width
1570 height:&height])
1571 {
1572 return nil;
1573 }
1574
1575 OOPixMap pm = OOMakePixMap(data, width, height, kOOPixMapRGBA, 0, 0);
1576 OOTextureGenerator *loader = [[OOPixMapTextureLoader alloc] initWithPixMap:pm
1577 textureOptions:kOOTextureDefaultOptions | kOOTextureRepeatS
1578 freeWhenDone:YES];
1579 [loader autorelease];
1580
1581 return [OOTexture textureWithGenerator:loader];
1582}
1583
1584
1585- (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias
1586{
1587 unsigned char *data;
1588 GLuint width, height;
1589
1591 if (![TextureStore getCloudTextureNameFor:cloudColor
1592 :cloud_impress
1593 :cloud_bias
1594 intoData:&data
1595 width:&width
1596 height:&height])
1597 {
1598 return nil;
1599 }
1600
1601 OOPixMap pm = OOMakePixMap(data, width, height, kOOPixMapRGBA, 0, 0);
1602 OOTextureGenerator *loader = [[OOPixMapTextureLoader alloc] initWithPixMap:pm
1603 textureOptions:kOOTextureDefaultOptions | kOOTextureRepeatS
1604 freeWhenDone:YES];
1605 [loader autorelease];
1606
1607 return [OOTexture textureWithGenerator:loader];
1608}
1609
1610
1611#ifndef NDEBUG
1612- (NSSet *) allTextures
1613{
1614 if (_texture != nil) return [NSSet setWithObject:_texture];
1615 else return nil;
1616}
1617#endif
1618
1619
1620- (BOOL)isPlanet
1621{
1622 return YES;
1623}
1624
1625
1626- (BOOL) isVisible
1627{
1628 return YES;
1629}
1630
1631@end
1632
1633#endif // !NEW_PLANETS
NSUInteger gDebugFlags
Definition main.m:7
#define DESTROY(x)
Definition OOCocoa.h:77
@ DEBUG_COLLISIONS
Definition OODebugFlags.h:7
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define M_SQRT1_2
Definition OOMaths.h:94
void OOGLPushModelView(void)
void OOGLTranslateModelView(Vector vector)
OOMatrix OOGLPopModelView(void)
void OOGLWireframeModeOn(void)
Definition OOOpenGL.m:87
void OOGLWireframeModeOff(void)
Definition OOOpenGL.m:103
@ OPENGL_STATE_OPAQUE
Definition OOOpenGL.h:123
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
BOOL OOCheckOpenGLErrors(NSString *format,...)
Definition OOOpenGL.m:39
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
#define OOGL(statement)
Definition OOOpenGL.h:251
@ kOOPixMapRGBA
Definition OOPixMap.h:43
OOPixMap OOMakePixMap(void *pixels, OOPixMapDimension width, OOPixMapDimension height, OOPixMapFormat format, size_t rowBytes, size_t bufferSize)
Definition OOPixMap.m:53
return nil
Vector vector_up_from_quaternion(Quaternion quat)
Vector vector_forward_from_quaternion(Quaternion quat)
void quaternion_set_random(Quaternion *quat)
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
float y
float x
#define PLANET_MINIATURE_FACTOR
#define ATMOSPHERE_DEPTH
OOStellarBodyType
@ STELLAR_TYPE_MOON
@ STELLAR_TYPE_ATMOSPHERE
@ STELLAR_TYPE_MINIATURE
@ STELLAR_TYPE_SUN
@ STELLAR_TYPE_NORMAL_PLANET
#define MAX_SUBDIVIDE
Random_Seed RandomSeedFromString(NSString *abcdefString)
BOOL ScanVectorFromString(NSString *xyzString, Vector *outVector)
double OOTimeDelta
Definition OOTypes.h:224
const Vector kBasisYVector
Definition OOVector.m:30
#define MAX_TRI_INDICES
#define CLOUD_ALPHA
static GLuint vertex_index_array[3 *(20+80+320+1280+5120+20480)]
#define POLAR_CLEAR_SKY_ALPHA
static const Vector kUntexturedVertices[]
static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured)
static Vector base_vertex_array[MAX_PLANET_VERTICES]
#define POLAR_CLOUD_ALPHA
static const Vector kTexturedVertices[]
static int base_terrain_array[MAX_PLANET_VERTICES]
static NSMapTable * sEdgeToVertex
static int triangle_start[MAX_SUBDIVIDE]
static GLfloat texture_uv_array[MAX_PLANET_VERTICES *2]
static int n_triangles[MAX_SUBDIVIDE]
static unsigned next_free_vertex
static const BaseFace kUntexturedFaces[][3]
static const BaseFace kTexturedFaces[][3]
#define CLEAR_SKY_ALPHA
#define PLAYER
void fillRanNoiseBuffer()
#define UNIVERSE
Definition Universe.h:840
GLfloat collision_radius
Definition Entity.h:111
Quaternion orientation
Definition Entity.h:114
void setOrientation:(Quaternion quat)
Definition Entity.m:725
unsigned isShip
Definition Entity.h:91
void setScanClass:(OOScanClass sClass)
Definition Entity.m:799
HPVector position
Definition Entity.h:112
void setPosition:(HPVector posn)
Definition Entity.m:647
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
Definition OOColor.m:95
float blueComponent()
Definition OOColor.m:362
OOColor * colorWithDescription:(id description)
Definition OOColor.m:127
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
Definition OOColor.m:368
OOColor * colorWithHue:saturation:brightness:alpha:(float hue,[saturation] float saturation,[brightness] float brightness,[alpha] float alpha)
Definition OOColor.m:87
float redComponent()
Definition OOColor.m:350
float greenComponent()
Definition OOColor.m:356
void registerClient:(id< OOGraphicsResetClient > client)
void unregisterClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
id textureWithGenerator:(OOTextureGenerator *generator)
Definition OOTexture.m:217
id textureWithConfiguration:extraOptions:(id configuration,[extraOptions] OOTextureFlags extraOptions)
Definition OOTexture.m:198
void applyNone()
Definition OOTexture.m:275
OOStellarBodyType planet_type
double rotationalVelocity()
void setCargoFlag:(OOCargoFlag flag)
void setSingleCrewWithRole:(NSString *crewRole)
void switchAITo:(NSString *aiString)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
RANROTSeed RANROTGetFullSeed(void)
void ranrot_srand(uint32_t seed)
void setRandomSeed(RNG_Seed a_seed)
RNG_Seed currentRandomSeed(void)
void RANROTSetFullSeed(RANROTSeed seed)
int gen_rnd_number(void)
void seed_for_planet_description(Random_Seed s_seed)
OOINLINE int is_nil_seed(Random_Seed a_seed) INLINE_CONST_FUNC
#define ranrot_rand()
unsigned v