Line data Source code
1 0 : /*
2 :
3 : PlanetEntity.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 "PlanetEntity.h"
26 :
27 : #if !NEW_PLANETS
28 :
29 : #import "OOOpenGLExtensionManager.h"
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.
36 : #import "OOPixMapTextureLoader.h"
37 : #import "MyOpenGLView.h"
38 : #import "ShipEntityAI.h"
39 : #import "OOColor.h"
40 : #import "OOCharacter.h"
41 : #import "OOStringParsing.h"
42 : #import "PlayerEntity.h"
43 : #import "OOCollectionExtractors.h"
44 : #import "OODebugFlags.h"
45 : #import "OOGraphicsResetManager.h"
46 :
47 :
48 : #if !OOLITE_MAC_OS_X
49 : #define NSIntegerMapKeyCallBacks NSIntMapKeyCallBacks
50 : #define NSIntegerMapValueCallBacks NSIntMapValueCallBacks
51 : #endif
52 :
53 :
54 : // straight C
55 0 : static Vector base_vertex_array[MAX_PLANET_VERTICES];
56 0 : static int base_terrain_array[MAX_PLANET_VERTICES];
57 0 : static unsigned next_free_vertex;
58 0 : static NSMapTable *sEdgeToVertex;
59 :
60 0 : static int n_triangles[MAX_SUBDIVIDE];
61 0 : static int triangle_start[MAX_SUBDIVIDE];
62 0 : static GLuint vertex_index_array[3*(20+80+320+1280+5120+20480)];
63 :
64 0 : static GLfloat texture_uv_array[MAX_PLANET_VERTICES * 2];
65 :
66 :
67 : @interface PlanetEntity (OOPrivate) <OOGraphicsResetClient>
68 :
69 0 : - (double) sqrtZeroDistance;
70 :
71 0 : - (void) drawModelWithVertexArraysAndSubdivision: (int) subdivide;
72 :
73 0 : - (void) initialiseBaseVertexArray;
74 :
75 :
76 0 : - (void) initialiseBaseTerrainArray:(int) percent_land;
77 0 : - (void) paintVertex:(unsigned) vi :(int) seed;
78 0 : - (void) scaleVertices;
79 :
80 0 : - (id) initAsAtmosphereForPlanet:(PlanetEntity *)planet dictionary:(NSDictionary *)dict;
81 0 : - (void) setTextureColorForPlanet:(BOOL)isMain inSystem:(BOOL)isLocal;
82 :
83 0 : - (id) initMiniatureFromPlanet:(PlanetEntity*) planet withAlpha:(float) alpha;
84 :
85 0 : - (void) loadTexture:(NSDictionary *)configuration;
86 0 : - (OOTexture *) planetTextureWithInfo:(NSDictionary *)info;
87 0 : - (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias;
88 :
89 0 : - (void) deleteDisplayLists;
90 :
91 0 : - (void) setUseTexturedModel:(BOOL)flag;
92 :
93 : @end
94 :
95 0 : static unsigned baseVertexIndexForEdge(GLushort va, GLushort vb, BOOL textured);
96 :
97 :
98 0 : typedef struct
99 : {
100 0 : unsigned v;
101 0 : float s;
102 0 : float t;
103 : } BaseFace;
104 :
105 :
106 0 : static 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 :
122 0 : static 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 :
147 0 : static 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 :
165 0 : static 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 0 : - (id) init
193 : {
194 : [self release];
195 : [NSException raise:NSInternalInconsistencyException format:@"%s, believed dead, called.", __PRETTY_FUNCTION__];
196 : return nil;
197 : }
198 :
199 :
200 0 : - (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 0 : #define CLEAR_SKY_ALPHA 0.05
213 0 : #define CLOUD_ALPHA 0.50
214 0 : #define POLAR_CLEAR_SKY_ALPHA 0.34
215 0 : #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 :
315 : if (planet->planet_type == STELLAR_TYPE_NORMAL_PLANET)
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 :
353 : [[OOGraphicsResetManager sharedManager] registerClient:self];
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 :
430 : seed_for_planet_description(p_seed);
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 :
574 : [[OOGraphicsResetManager sharedManager] registerClient:self];
575 :
576 : return self;
577 : }
578 :
579 :
580 0 : - (void) dealloc
581 : {
582 : [self deleteDisplayLists];
583 :
584 : DESTROY(atmosphere);
585 : DESTROY(_texture);
586 : DESTROY(_textureFileName);
587 :
588 : [[OOGraphicsResetManager sharedManager] unregisterClient:self];
589 :
590 : [super dealloc];
591 : }
592 :
593 :
594 0 : - (NSString*) descriptionComponents
595 : {
596 : NSString *typeString;
597 : switch (planet_type)
598 : {
599 : case STELLAR_TYPE_MINIATURE:
600 : typeString = @"STELLAR_TYPE_MINIATURE"; break;
601 : case STELLAR_TYPE_NORMAL_PLANET:
602 : typeString = @"STELLAR_TYPE_NORMAL_PLANET"; break;
603 : case STELLAR_TYPE_ATMOSPHERE:
604 : typeString = @"STELLAR_TYPE_ATMOSPHERE"; break;
605 : case STELLAR_TYPE_MOON:
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 0 : - (BOOL) canCollide
616 : {
617 : switch (planet_type)
618 : {
619 : case STELLAR_TYPE_MINIATURE:
620 : case STELLAR_TYPE_ATMOSPHERE:
621 : return NO;
622 : break;
623 : case STELLAR_TYPE_MOON:
624 : case STELLAR_TYPE_NORMAL_PLANET:
625 : case STELLAR_TYPE_SUN:
626 : return YES;
627 : break;
628 : }
629 : return YES;
630 : }
631 :
632 :
633 0 : - (BOOL) checkCloseCollisionWith:(Entity *)other
634 : {
635 : #ifndef NDEBUG
636 : if (gDebugFlags & DEBUG_COLLISIONS)
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 0 : - (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 : {
669 : case STELLAR_TYPE_NORMAL_PLANET:
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 : }
699 : case STELLAR_TYPE_MOON:
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 :
711 : case STELLAR_TYPE_MINIATURE:
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 :
718 : case STELLAR_TYPE_ATMOSPHERE:
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 0 : - (void) setPosition:(HPVector)posn
733 : {
734 : position = posn;
735 : [atmosphere setPosition:posn];
736 : }
737 :
738 :
739 0 : - (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 0 : - (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 0 : - (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 :
803 : OOSetOpenGLState(OPENGL_STATE_OPAQUE);
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 : {
833 : case STELLAR_TYPE_ATMOSPHERE:
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 :
843 : case STELLAR_TYPE_MOON:
844 : case STELLAR_TYPE_NORMAL_PLANET:
845 : case STELLAR_TYPE_MINIATURE:
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;
852 : OOGLWireframeModeOn();
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));
877 : [OOTexture applyNone];
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 : {
954 : OOGLWireframeModeOff();
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());
975 : OOVerifyOpenGLState();
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 0 : - (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 0 : - (double) sqrtZeroDistance
1152 : {
1153 : return sqrt_zero_distance;
1154 : }
1155 :
1156 :
1157 : - (BOOL) hasAtmosphere
1158 : {
1159 : return atmosphere != nil;
1160 : }
1161 :
1162 :
1163 0 : - (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 :
1176 : quaternion_set_random(&q1);
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 :
1211 0 : - (void) initialiseBaseVertexArray
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 :
1317 0 : static 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 0 : - (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
1399 : if (base_terrain_array[v0] == base_terrain_array[v1])
1400 : base_terrain_array[v01] = base_terrain_array[v0];
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
1410 : if (base_terrain_array[v1] == base_terrain_array[v2])
1411 : base_terrain_array[v12] = base_terrain_array[v1];
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
1421 : if (base_terrain_array[v2] == base_terrain_array[v0])
1422 : base_terrain_array[v20] = base_terrain_array[v2];
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 0 : - (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 0 : - (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 0 : - (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 0 : - (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 0 : - (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 0 : - (OOTexture *) planetTextureWithInfo:(NSDictionary *)info
1562 : {
1563 : unsigned char *data;
1564 : GLuint width, height;
1565 :
1566 : fillRanNoiseBuffer();
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 0 : - (OOTexture *) cloudTextureWithCloudColor:(OOColor *)cloudColor cloudImpress:(GLfloat)cloud_impress cloudBias:(GLfloat)cloud_bias
1586 : {
1587 : unsigned char *data;
1588 : GLuint width, height;
1589 :
1590 : fillRanNoiseBuffer();
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 0 : - (NSSet *) allTextures
1613 : {
1614 : if (_texture != nil) return [NSSet setWithObject:_texture];
1615 : else return nil;
1616 : }
1617 : #endif
1618 :
1619 :
1620 0 : - (BOOL)isPlanet
1621 : {
1622 : return YES;
1623 : }
1624 :
1625 :
1626 0 : - (BOOL) isVisible
1627 : {
1628 : return YES;
1629 : }
1630 :
1631 : @end
1632 :
1633 : #endif // !NEW_PLANETS
|