Oolite 1.91.0.7646-241128-10e222e
Loading...
Searching...
No Matches
OOPlanetTextureGenerator.m
Go to the documentation of this file.
1/*
2 OOPlanetTextureGenerator.m
3
4 Generator for planet diffuse maps.
5
6
7 Oolite
8 Copyright (C) 2004-2013 Giles C Williams and contributors
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 MA 02110-1301, USA.
24*/
25
26#import "OOCocoa.h"
27#import "OOStellarBody.h"
28
29#if NEW_PLANETS
30
31
32#define DEBUG_DUMP ( 0 && OOLITE_DEBUG)
33#define DEBUG_DUMP_RAW ( 1 && DEBUG_DUMP)
34
35#define POLAR_CAPS 1
36#define ALBEDO_FACTOR 0.7f // Overall darkening of everything, allowing better contrast for snow and specular highlights.
37
38
41#import "OOColor.h"
42
43#ifndef TEXGEN_TEST_RIG
44#import "OOTexture.h"
45#import "Universe.h"
46#endif
47
48#if DEBUG_DUMP
49#import "MyOpenGLView.h"
50#endif
51
52
53#define FREE(x) do { if (0) { void *x__ = x; x__ = x__; } /* Preceeding is for type checking only. */ void **x_ = (void **)&(x); free(*x_); *x_ = NULL; } while (0)
54
55
56#define PLANET_TEXTURE_OPTIONS (kOOTextureMinFilterLinear | kOOTextureMagFilterLinear | kOOTextureRepeatS | kOOTextureNoShrink)
57
58
59enum
60{
61 kRandomBufferSize = 128
62};
63
64
65/* The planet generator actually generates two textures when shaders are
66 active, but the texture loader interface assumes we only load/generate
67 one texture per loader. Rather than complicate that, we use a mock
68 generator for the normal/light map.
69*/
70@interface OOPlanetNormalMapGenerator: OOTextureGenerator
71{
72@private
73 BOOL _enqueued;
74 NSString *_cacheKey;
75 RANROTSeed _seed;
76}
77
78- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed;
79
80- (void) completeWithData:(void *)data width:(unsigned)width height:(unsigned)height;
81
82- (BOOL) enqueued;
83
84@end
85
86
87// Doing the same as above for the atmosphere.
88@interface OOPlanetAtmosphereGenerator: OOTextureGenerator
89{
90@private
91 BOOL _enqueued;
92 NSString *_cacheKey;
93 RANROTSeed _seed;
95}
96
97- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed andParent:(OOPlanetTextureGenerator *)parent;
98
99- (void) completeWithData:(void *)data width:(unsigned)width height:(unsigned)height;
100
101- (BOOL) enqueued;
102
103@end
104
105
106@interface OOPlanetTextureGenerator (Private)
107
108- (NSString *) cacheKeyForType:(NSString *)type;
109- (OOPlanetNormalMapGenerator *) normalMapGenerator; // Must be called before generator is enqueued for rendering.
110- (OOPlanetAtmosphereGenerator *) atmosphereGenerator; // Must be called before generator is enqueued for rendering.
111
112#if DEBUG_DUMP_RAW
113- (void) dumpNoiseBuffer:(float *)noise;
114#endif
115
116@end
117
118
119static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key);
120
121static BOOL FillFBMBuffer(OOPlanetTextureGeneratorInfo *info);
122
123static float QFactor(float *accbuffer, int x, int y, unsigned width, float polar_y_value, float bias, float polar_y);
124static float GetQ(float *qbuffer, int x, int y, unsigned width, unsigned height, unsigned widthMask, unsigned heightMask);
125
126static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b);
127static float BlendAlpha(float fraction, float a, float b);
128static void SetMixConstants(OOPlanetTextureGeneratorInfo *info, float temperatureFraction);
129static FloatRGBA CloudMix(OOPlanetTextureGeneratorInfo *info, float q, float nearPole);
130static FloatRGBA PlanetMix(OOPlanetTextureGeneratorInfo *info, float q, float nearPole);
131
132
133enum
134{
135 kPlanetScale256x256 = 1,
136 kPlanetScale512x512,
137 kPlanetScale1024x1024,
138 kPlanetScale2048x2048,
139 kPlanetScale4096x4096,
140
141 kPlanetScaleReducedDetail = kPlanetScale512x512,
142 kPlanetScaleFullDetail = kPlanetScale1024x1024,
143 kPlanetScaleExtraDetail = kPlanetScale2048x2048
144};
145
146
147@implementation OOPlanetTextureGenerator
148
149- (id) initWithPlanetInfo:(NSDictionary *)planetInfo
150{
151 OOLog(@"texture.planet.generate", @"%@", @"Initialising planetary generator");
152
153 // AllowCubeMap not used yet but might be in future
154 if ((self = [super initWithPath:[NSString stringWithFormat:@"OOPlanetTexture@%p", self] options:kOOTextureAllowCubeMap]))
155 {
156 OOLog(@"texture.planet.generate", @"Extracting parameters for generator %@",self);
157
158 _info.landFraction = OOClamp_0_1_f([planetInfo oo_floatForKey:@"land_fraction" defaultValue:0.3]);
159 _info.polarFraction = OOClamp_0_1_f([planetInfo oo_floatForKey:@"polar_fraction" defaultValue:0.05]);
160 _info.landColor = FloatRGBFromDictColor(planetInfo, @"land_color");
161 _info.seaColor = FloatRGBFromDictColor(planetInfo, @"sea_color");
162 _info.paleLandColor = FloatRGBFromDictColor(planetInfo, @"polar_land_color");
163 _info.polarSeaColor = FloatRGBFromDictColor(planetInfo, @"polar_sea_color");
164 [[planetInfo objectForKey:@"noise_map_seed"] getValue:&_info.seed];
165 if ([planetInfo objectForKey:@"cloud_alpha"])
166 {
167 OOLog(@"texture.planet.generate", @"%@", @"Extracting atmosphere parameters");
168 // we have an atmosphere:
169 _info.cloudAlpha = [planetInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0f];
170 _info.cloudFraction = OOClamp_0_1_f([planetInfo oo_floatForKey:@"cloud_fraction" defaultValue:0.3]);
171 _info.cloudColor = FloatRGBFromDictColor(planetInfo, @"cloud_color");
172 _info.paleCloudColor = FloatRGBFromDictColor(planetInfo, @"polar_cloud_color");
173 }
174
175 OOGraphicsDetail detailLevel = [UNIVERSE detailLevel];
176
177#ifndef TEXGEN_TEST_RIG
178 if (detailLevel < DETAIL_LEVEL_SHADERS || [planetInfo oo_boolForKey:@"isMiniature" defaultValue:NO])
179 {
180 _planetScale = kPlanetScaleReducedDetail;
181 }
182 else if (detailLevel == DETAIL_LEVEL_SHADERS)
183 {
184 _planetScale = kPlanetScaleFullDetail;
185 }
186 else
187 {
188 _planetScale = kPlanetScaleExtraDetail;
189 }
190#else
191 _planetScale = kPlanetScale4096x4096;
192#endif
193 _info.perlin3d = [planetInfo oo_boolForKey:@"perlin_3d" defaultValue:detailLevel > DETAIL_LEVEL_SHADERS];
194 _info.planetAspectRatio = _info.perlin3d ? 2 : 1;
195 _info.planetScaleOffset = 8 - _info.planetAspectRatio;
196 }
197
198 return self;
199}
200
201
202+ (OOTexture *) planetTextureWithInfo:(NSDictionary *)planetInfo
203{
204 OOTexture *result = nil;
205 OOPlanetTextureGenerator *generator = [[self alloc] initWithPlanetInfo:planetInfo];
206 if (generator != nil)
207 {
208 result = [OOTexture textureWithGenerator:generator];
209 [generator release];
210 }
211
212 return result;
213}
214
215
216+ (BOOL) generatePlanetTexture:(OOTexture **)texture andAtmosphere:(OOTexture **)atmosphere withInfo:(NSDictionary *)planetInfo
217{
218 NSParameterAssert(texture != NULL);
219
220 OOPlanetTextureGenerator *diffuseGen = [[[self alloc] initWithPlanetInfo:planetInfo] autorelease];
221 if (diffuseGen == nil) return NO;
222
223 OOPlanetAtmosphereGenerator *atmoGen = [diffuseGen atmosphereGenerator];
224 if (atmoGen == nil) return NO;
225
226 *atmosphere = [OOTexture textureWithGenerator:atmoGen];
227 if (*atmosphere == nil) return NO;
228
229 *texture = [OOTexture textureWithGenerator:diffuseGen enqueue: [atmoGen enqueued]];
230
231 return *texture != nil;
232}
233
234
235+ (BOOL) generatePlanetTexture:(OOTexture **)texture secondaryTexture:(OOTexture **)secondaryTexture withInfo:(NSDictionary *)planetInfo
236{
237 NSParameterAssert(texture != NULL);
238
239 BOOL enqueue = NO;
240
241 OOPlanetTextureGenerator *diffuseGen = [[[self alloc] initWithPlanetInfo:planetInfo] autorelease];
242 if (diffuseGen == nil) return NO;
243
244 if (secondaryTexture != NULL)
245 {
246 OOPlanetNormalMapGenerator *normalGen = [diffuseGen normalMapGenerator];
247 if (normalGen == nil) return NO;
248
249 *secondaryTexture = [OOTexture textureWithGenerator:normalGen];
250 if (*secondaryTexture == nil) return NO;
251 enqueue = [normalGen enqueued];
252 }
253
254 *texture = [OOTexture textureWithGenerator:diffuseGen enqueue: enqueue];
255
256 return *texture != nil;
257}
258
259
260+ (BOOL) generatePlanetTexture:(OOTexture **)texture secondaryTexture:(OOTexture **)secondaryTexture andAtmosphere:(OOTexture **)atmosphere withInfo:(NSDictionary *)planetInfo
261{
262 NSParameterAssert(texture != NULL);
263
264 BOOL enqueue = NO;
265
266 OOPlanetTextureGenerator *diffuseGen = [[[self alloc] initWithPlanetInfo:planetInfo] autorelease];
267 if (diffuseGen == nil) return NO;
268
269 if (secondaryTexture != NULL)
270 {
271 OOPlanetNormalMapGenerator *normalGen = [diffuseGen normalMapGenerator];
272 if (normalGen == nil) return NO;
273
274 *secondaryTexture = [OOTexture textureWithGenerator:normalGen];
275 if (*secondaryTexture == nil) return NO;
276 enqueue = [normalGen enqueued];
277 }
278
279 OOPlanetAtmosphereGenerator *atmoGen = [diffuseGen atmosphereGenerator];
280 if (atmoGen == nil) return NO;
281
282 *atmosphere = [OOTexture textureWithGenerator:atmoGen];
283 if (*atmosphere == nil)
284 {
285 if (secondaryTexture != NULL) {
286 *secondaryTexture = nil;
287 }
288 return NO;
289 }
290 enqueue = enqueue || [atmoGen enqueued];
291
292 OOLog(@"texture.planet.generate",@"Generator %@ has atmosphere %@",diffuseGen,*atmosphere);
293
294 *texture = [OOTexture textureWithGenerator:diffuseGen enqueue: enqueue];
295 return *texture != nil;
296}
297
298
299- (void) dealloc
300{
301 DESTROY(_nMapGenerator);
302 DESTROY(_atmoGenerator);
303
304 [super dealloc];
305}
306
307
308- (NSString *) descriptionComponents
309{
310 return [NSString stringWithFormat:@"seed: %u,%u land: %g", _info.seed.high, _info.seed.low, _info.landFraction];
311}
312
313
314- (uint32_t) textureOptions
315{
316 return PLANET_TEXTURE_OPTIONS;
317}
318
319
320- (NSString *) cacheKey
321{
322 NSString *type =(_nMapGenerator == nil) ? @"diffuse-baked" : @"diffuse-raw";
323 if (_atmoGenerator != nil) type = [NSString stringWithFormat:@"%@-atmo", type];
324 return [self cacheKeyForType:type];
325}
326
327
328- (NSString *) cacheKeyForType:(NSString *)type
329{
330 return [NSString stringWithFormat:@"OOPlanetTextureGenerator-%@@%u\n%u,%u/%g/%u,%u/%f,%f,%f/%f,%f,%f/%f,%f,%f/%f,%f,%f",
331 type, _planetScale,
332 _info.width, _info.height, _info.landFraction, _info.seed.high, _info.seed.low,
333 _info.landColor.r, _info.landColor.g, _info.landColor.b,
334 _info.seaColor.r, _info.seaColor.g, _info.seaColor.b,
335 _info.paleLandColor.r, _info.paleLandColor.g, _info.paleLandColor.b,
336 _info.polarSeaColor.r, _info.polarSeaColor.g, _info.polarSeaColor.b];
337}
338
339
340- (OOPlanetNormalMapGenerator *) normalMapGenerator
341{
342 if (_nMapGenerator == nil)
343 {
344 _nMapGenerator = [[OOPlanetNormalMapGenerator alloc] initWithCacheKey:[self cacheKeyForType:@"normal"] seed:_info.seed];
345 }
346 return _nMapGenerator;
347}
348
349
350- (OOPlanetAtmosphereGenerator *) atmosphereGenerator
351{
352 if (_atmoGenerator == nil)
353 {
354 _atmoGenerator = [[OOPlanetAtmosphereGenerator alloc] initWithCacheKey:[self cacheKeyForType:@"atmo"] seed:_info.seed andParent:self];
355 }
356 return _atmoGenerator;
357}
358
359
360- (BOOL)getResult:(OOPixMap *)outData
361 format:(OOTextureDataFormat *)outFormat
362 width:(uint32_t *)outWidth
363 height:(uint32_t *)outHeight
364{
365 BOOL waiting = NO;
366 if (![self isReady])
367 {
368 waiting = true;
369 OOLog(@"texture.planet.generate.wait", @"%s generator %@", "Waiting for", self);
370 }
371
372 BOOL result = [super getResult:outData format:outFormat originalWidth:outWidth originalHeight:outHeight];
373
374 if (waiting)
375 {
376 OOLog(@"texture.planet.generate.dequeue", @"%s generator %@", result ? "Dequeued" : "Failed to dequeue", self);
377 }
378 else
379 {
380 OOLog(@"texture.planet.generate.dequeue", @"%s generator %@ without waiting.", result ? "Dequeued" : "Failed to dequeue", self);
381 }
382
383 return result;
384}
385
386
387- (void) loadTexture
388{
389 OOLog(@"texture.planet.generate.begin", @"Started generator %@", self);
390
391 BOOL success = NO;
392 BOOL generateNormalMap = (_nMapGenerator != nil);
393 BOOL generateAtmosphere = (_atmoGenerator != nil);
394
395 uint8_t *buffer = NULL, *px = NULL;
396 uint8_t *nBuffer = NULL, *npx = NULL;
397 uint8_t *aBuffer = NULL, *apx = NULL;
398 float *randomBuffer = NULL;
399
400 _height = _info.height = 1 << (_planetScale + _info.planetScaleOffset);
401 _width = _info.width = _height * _info.planetAspectRatio;
402
403#define FAIL_IF(cond) do { if (EXPECT_NOT(cond)) goto END; } while (0)
404#define FAIL_IF_NULL(x) FAIL_IF((x) == NULL)
405
406 buffer = malloc(4 * _width * _height);
407 FAIL_IF_NULL(buffer);
408 px = buffer;
409
410 if (generateNormalMap)
411 {
412 nBuffer = malloc(4 * _width * _height);
413 FAIL_IF_NULL(nBuffer);
414 npx = nBuffer;
415 }
416
417 if (generateAtmosphere)
418 {
419 aBuffer = malloc(4 * _width * _height);
420 FAIL_IF_NULL(aBuffer);
421 apx = aBuffer;
422 }
423
424 FAIL_IF(!FillFBMBuffer(&_info));
425#if DEBUG_DUMP_RAW
426 [self dumpNoiseBuffer:_info.fbmBuffer];
427#endif
428
429 float paleClouds = (_info.cloudFraction * _info.fbmBuffer[0] < 1.0f - _info.cloudFraction) ? 0.0f : 1.0f;
430 float poleValue = (_info.landFraction > 0.5f) ? 0.5f * _info.landFraction : 0.0f;
431 float seaBias = _info.landFraction - 1.0f;
432
433 _info.paleSeaColor = Blend(0.35f, _info.polarSeaColor, Blend(0.7f, _info.seaColor, _info.landColor));
434 float normalScale = (1 << _planetScale)
435#ifndef NDEBUG
436 // test-release only, make normalScale adjustable from within user defaults
437 * [[NSUserDefaults standardUserDefaults] oo_floatForKey:@"p3dnsf" defaultValue:1.0f]
438#endif
439 ; // float normalScale = ...
440 if (!generateNormalMap) normalScale *= 3.0f;
441
442 // Deep sea colour: sea darker past the continental shelf.
443 _info.deepSeaColor = Blend(0.85f, _info.seaColor, (FloatRGB){ 0, 0, 0 });
444
445 int x, y;
446 FloatRGBA color;
447 Vector norm;
448 float q, yN, yS, yW, yE, nearPole;
449 GLfloat shade;
450 float rHeight = 1.0f / _height;
451 float fy, fHeight = _height;
452 // The second parameter is the temperature fraction. Most favourable: 1.0f, little ice. Most unfavourable: 0.0f, frozen planet. TODO: make it dependent on ranrot / planetinfo key...
453 SetMixConstants(&_info, 1.0f-_info.polarFraction); // no need to recalculate them inside each loop!
454
455 // first pass, calculate q.
456 _info.qBuffer = malloc(_width * _height * sizeof (float));
457 FAIL_IF_NULL(_info.qBuffer);
458
459 for (y = (int)_height - 1, fy = (float)y; y >=0; y--, fy--)
460 {
461 nearPole = (2.0f * fy - fHeight) * rHeight;
462 nearPole *= nearPole;
463
464 for (x = (int)_width - 1; x >=0; x--)
465 {
466 _info.qBuffer[y * _width + x] = QFactor(_info.fbmBuffer, x, y, _width, poleValue, seaBias, nearPole);
467 }
468 }
469
470 // second pass, use q.
471 float cloudFraction = _info.cloudFraction;
472 unsigned widthMask = _width - 1;
473 unsigned heightMask = _height - 1;
474
475 for (y = (int)_height - 1, fy = (float)y; y >= 0; y--, fy--)
476 {
477 nearPole = (2.0f * fy - fHeight) * rHeight;
478 nearPole *= nearPole;
479
480 for (x = (int)_width - 1; x >= 0; x--)
481 {
482 q = _info.qBuffer[y * _width + x]; // no need to use GetQ, x and y are always within bounds.
483 yN = GetQ(_info.qBuffer, x, y - 1, _width, _height, widthMask, heightMask); // recalculates x & y if they go out of bounds.
484 yS = GetQ(_info.qBuffer, x, y + 1, _width, _height, widthMask, heightMask);
485 yW = GetQ(_info.qBuffer, x - 1, y, _width, _height, widthMask, heightMask);
486 yE = GetQ(_info.qBuffer, x + 1, y, _width, _height, widthMask, heightMask);
487
488 color = PlanetMix(&_info, q, nearPole);
489
490 norm = vector_normal(make_vector(normalScale * (yE - yW), normalScale * (yN - yS), 1.0f));
491 if (generateNormalMap)
492 {
493 shade = 1.0f;
494
495 // Flatten the sea.
496 norm = OOVectorInterpolate(norm, kBasisZVector, color.a);
497
498 // Put norm in normal map, scaled from [-1..1] to [0..255].
499 *npx++ = 127.5f * (norm.y + 1.0f);
500 *npx++ = 127.5f * (-norm.x + 1.0f);
501 *npx++ = 127.5f * (norm.z + 1.0f);
502
503 *npx++ = 255.0f * color.a; // Specular channel.
504 }
505 else
506 {
507 // Terrain shading - lambertian lighting from straight above.
508 shade = norm.z;
509
510 /* We don't want terrain shading in the sea. The alpha channel
511 of color is a measure of "seaishness" for the specular map,
512 so we can recycle that to avoid branching.
513 -- Ahruman
514 */
515 shade += color.a - color.a * shade; // equivalent to - but slightly faster than - previous implementation.
516 }
517
518 *px++ = 255.0f * color.r * shade;
519 *px++ = 255.0f * color.g * shade;
520 *px++ = 255.0f * color.b * shade;
521
522 *px++ = 0; // FIXME: light map goes here.
523
524 if (generateAtmosphere)
525 {
526 q = QFactor(_info.fbmBuffer, x, y, _width, paleClouds, cloudFraction, nearPole);
527 color = CloudMix(&_info, q, nearPole);
528 *apx++ = 255.0f * color.r;
529 *apx++ = 255.0f * color.g;
530 *apx++ = 255.0f * color.b;
531 *apx++ = 255.0f * color.a * _info.cloudAlpha;
532 }
533 }
534 }
535
536 success = YES;
537 _format = kOOTextureDataRGBA;
538
539END:
540 FREE(_info.fbmBuffer);
541 FREE(_info.qBuffer);
542 FREE(randomBuffer);
543 if (success)
544 {
545 _data = buffer;
546 if (generateNormalMap) [_nMapGenerator completeWithData:nBuffer width:_width height:_height];
547 if (generateAtmosphere) [_atmoGenerator completeWithData:aBuffer width:_width height:_height];
548 }
549 else
550 {
551 FREE(buffer);
552 FREE(nBuffer);
553 FREE(aBuffer);
554 }
555 DESTROY(_nMapGenerator);
556 DESTROY(_atmoGenerator);
557
558 OOLog(@"texture.planet.generate.complete", @"Completed generator %@ %@successfully", self, success ? @"" : @"un");
559
560#if DEBUG_DUMP
561 if (success)
562 {
563 NSString *diffuseName = [NSString stringWithFormat:@"planet-%u-%u-diffuse-new", _info.seed.high, _info.seed.low];
564 NSString *lightsName = [NSString stringWithFormat:@"planet-%u-%u-lights-new", _info.seed.high, _info.seed.low];
565
566 [[UNIVERSE gameView] dumpRGBAToRGBFileNamed:diffuseName
567 andGrayFileNamed:lightsName
568 bytes:buffer
569 width:_width
570 height:_height
571 rowBytes:_width * 4];
572 }
573#endif
574}
575
576
577#if DEBUG_DUMP_RAW
578
579- (void) dumpNoiseBuffer:(float *)noise
580{
581 NSString *noiseName = [NSString stringWithFormat:@"planet-%u-%u-noise-new", _info.seed.high, _info.seed.low];
582
583 uint8_t *noisePx = malloc(_width * _height);
584 unsigned x, y;
585 for (y = 0; y < _height; y++)
586 {
587 for (x = 0; x < _width; x++)
588 {
589 noisePx[y * _width + x] = 255.0f * noise[y * _width + x];
590 }
591 }
592
593 [[UNIVERSE gameView] dumpGrayToFileNamed:noiseName
594 bytes:noisePx
595 width:_width
596 height:_height
597 rowBytes:_width];
598 FREE(noisePx);
599}
600
601#endif
602
603@end
604
605
606OOINLINE float Lerp(float v0, float v1, float fraction)
607{
608 // Linear interpolation - equivalent to v0 * (1.0f - fraction) + v1 * fraction.
609 return v0 + fraction * (v1 - v0);
610}
611
612
613static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
614{
615 return (FloatRGB)
616 {
617 Lerp(b.r, a.r, fraction),
618 Lerp(b.g, a.g, fraction),
619 Lerp(b.b, a.b, fraction)
620 };
621}
622
623
624static float BlendAlpha(float fraction, float a, float b)
625{
626 return Lerp(b, a, fraction);
627}
628
629
630static FloatRGBA CloudMix(OOPlanetTextureGeneratorInfo *info, float q, float nearPole)
631{
632//#define AIR_ALPHA (0.15f)
633//#define CLOUD_ALPHA (1.0f)
634// CIM: make distinction between cloud and not-cloud bigger
635#define AIR_ALPHA (0.05f)
636#define CLOUD_ALPHA (2.0f)
637
638#define POLAR_BOUNDARY (0.33f)
639#define CLOUD_BOUNDARY (0.5f)
640#define RECIP_CLOUD_BOUNDARY (1.0f / CLOUD_BOUNDARY)
641
642 FloatRGB cloudColor = info->cloudColor;
643 float alpha = info->cloudAlpha, portion = 0.0f;
644
645 q -= CLOUD_BOUNDARY * 0.5f;
646
647 if (nearPole > POLAR_BOUNDARY)
648 {
649 portion = nearPole > POLAR_BOUNDARY + 0.2f ? 1.0f : (nearPole - POLAR_BOUNDARY) * 5.0f;
650 cloudColor = Blend(portion, info->paleCloudColor, cloudColor);
651
652 portion = nearPole > POLAR_BOUNDARY + 0.625f ? 1.0f : (nearPole - POLAR_BOUNDARY) * 1.6f;
653 }
654
655 if (q <= 0.0f)
656 {
657 if (q >= -CLOUD_BOUNDARY)
658 {
659 alpha *= BlendAlpha(-q * 0.5f * RECIP_CLOUD_BOUNDARY + 0.5f, CLOUD_ALPHA, AIR_ALPHA);
660 }
661 else
662 {
663 alpha *= CLOUD_ALPHA;
664 }
665 }
666 else
667 {
668 if (q < CLOUD_BOUNDARY)
669 {
670 alpha *= BlendAlpha( q * 0.5f * RECIP_CLOUD_BOUNDARY + 0.5f, AIR_ALPHA,CLOUD_ALPHA);
671 }
672 else
673 {
674 alpha *= AIR_ALPHA;
675 }
676 }
677 // magic numbers! at the poles we have fairly thin air.
678 alpha *= BlendAlpha(portion, 0.6f, 1.0f);
679 if (alpha > 1.0)
680 {
681 alpha = 1.0;
682 }
683
684 return (FloatRGBA){ cloudColor.r, cloudColor.g, cloudColor.b, alpha };
685}
686
687
688static FloatRGBA PlanetMix(OOPlanetTextureGeneratorInfo *info, float q, float nearPole)
689{
690#define RECIP_COASTLINE_PORTION (160.0f)
691#define COASTLINE_PORTION (1.0f / RECIP_COASTLINE_PORTION)
692#define SHALLOWS (2.0f * COASTLINE_PORTION) // increased shallows area.
693#define RECIP_SHALLOWS (1.0f / SHALLOWS)
694// N.B.: DEEPS can't be more than RECIP_COASTLINE_PORTION * COASTLINE_PORTION!
695#define DEEPS (40.0f * COASTLINE_PORTION)
696#define RECIP_DEEPS (1.0f / DEEPS)
697
698 const FloatRGB white = { 1.0f, 1.0f, 1.0f };
699 FloatRGB diffuse;
700 // windows specular 'fix': 0 was showing pitch black continents when on the dark side, 0.01 shows the same shading as on Macs.
701 // TODO: a less hack-like fix.
702 float specular = 0.01f;
703
704 if (q <= 0.0f)
705 {
706 // Below datum - sea.
707 if (q > -SHALLOWS)
708 {
709 // Coastal waters.
710 diffuse = Blend(-q * RECIP_SHALLOWS, info->seaColor, info->paleSeaColor);
711 specular = 1.0f;
712 }
713 else
714 {
715 // Open sea.
716 if (q > -DEEPS) diffuse = Blend(-q * RECIP_DEEPS, info->deepSeaColor, info->seaColor);
717 else diffuse = info->deepSeaColor;
718 specular = Lerp(1.0f, 0.85f, -q);
719 }
720 }
721 else if (q < COASTLINE_PORTION)
722 {
723 // Coastline.
724 specular = q * RECIP_COASTLINE_PORTION;
725 diffuse = Blend(specular, info->landColor, info->paleSeaColor);
726 specular = 1.0f - specular;
727 }
728 else if (q > 1.0f)
729 {
730 // High up - snow-capped peaks. With overrides q can range between -2 to +2.
731 diffuse = white;
732 }
733 else if (q > info->mix_hi)
734 {
735 diffuse = Blend((q - info->mix_hi) * info->mix_ih, white, info->paleLandColor); // Snowline.
736 }
737 else
738 {
739 // Normal land.
740 diffuse = Blend((info->mix_hi - q) * info->mix_oh, info->landColor, info->paleLandColor);
741 }
742
743#if POLAR_CAPS
744 // (q > mix_polarCap + mix_polarCap - nearPole) == ((nearPole + q) / 2 > mix_polarCap)
745 float phi = info->mix_polarCap + info->mix_polarCap - nearPole;
746 if (q > phi) // (nearPole + q) / 2 > pole
747 {
748 // thinner to thicker ice.
749 specular = q > phi + 0.02f ? 1.0f : 0.2f + (q - phi) * 40.0f; // (q - phi) * 40 == ((q-phi) / 0.02) * 0.8
750 //diffuse = info->polarSeaColor;
751 diffuse = Blend(specular, info->polarSeaColor, diffuse);
752 specular = specular * 0.5f; // softer contours under ice, but still contours.
753 }
754#endif
755
756 return (FloatRGBA){ diffuse.r, diffuse.g, diffuse.b, specular };
757}
758
759
760static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key)
761{
762 OOColor *color = [dictionary objectForKey:key];
763 NSCAssert1([color isKindOfClass:[OOColor class]], @"Expected OOColor, got %@", [color class]);
764
765 return (FloatRGB){ [color redComponent] * ALBEDO_FACTOR, [color greenComponent] * ALBEDO_FACTOR, [color blueComponent] * ALBEDO_FACTOR };
766}
767
768
769OOINLINE float Hermite(float q)
770{
771 return 3.0f * q * q - 2.0f * q * q * q;
772}
773
774
775#if __BIG_ENDIAN__
776#define iman_ 1
777#else
778#define iman_ 0
779#endif
780
781 // (same behaviour as, but faster than, FLOAT->INT)
782 //Works OK for -32728 to 32727.99999236688
783OOINLINE int32_t fast_floor(double val)
784{
785 val += 68719476736.0 * 1.5;
786 return (((int32_t*)&val)[iman_] >> 16);
787}
788
789
790static BOOL GenerateFBMNoise(OOPlanetTextureGeneratorInfo *info);
791static BOOL GenerateFBMNoise3D(OOPlanetTextureGeneratorInfo *info);
792
793
794static BOOL FillFBMBuffer(OOPlanetTextureGeneratorInfo *info)
795{
796 NSCParameterAssert(info != NULL);
797
798 // Allocate result buffer.
799 info->fbmBuffer = calloc(info->width * info->height, sizeof (float));
800 if (info->fbmBuffer != NULL)
801 {
802 if (!info->perlin3d)
803 {
804 GenerateFBMNoise(info);
805 }
806 else
807 {
808 GenerateFBMNoise3D(info);
809 }
810
811 return YES;
812 }
813 return NO;
814}
815
816
817
818enum
819{
820 // Size of permutation buffer used to map integer coordinates to gradients. Must be power of two.
821 kPermutationCount = 1 << 10,
822 kPermutationMask = kPermutationCount - 1,
823
824 // Number of different gradient vectors used. The most important thing is that the gradients are evenly distributed and sum to 0.
825 kGradientCount = 12
826};
827
828
829#define LUT_DOT 1
830
831
832#if !LUT_DOT
833static const Vector kGradients[kGradientCount] =
834{
835 { 1, 1, 0 },
836 { -1, 1, 0 },
837 { 1, -1, 0 },
838 { -1, -1, 0 },
839 { 1, 0, 1 },
840 { -1, 0, 1 },
841 { 1, 0, -1 },
842 { -1, 0, -1 },
843 { 0, 1, 1 },
844 { 0, -1, 1 },
845 { 0, 1, -1 },
846 { 0, -1, -1 }
847};
848#else
849static const uint8_t kGradients[kGradientCount][3] =
850{
851 { 2, 2, 1 },
852 { 0, 2, 1 },
853 { 2, 0, 1 },
854 { 0, 0, 1 },
855 { 2, 1, 2 },
856 { 0, 1, 2 },
857 { 2, 1, 0 },
858 { 0, 1, 0 },
859 { 1, 2, 2 },
860 { 1, 0, 2 },
861 { 1, 2, 0 },
862 { 1, 0, 0 }
863};
864
865
866/* Attempted speedup that didn't pan out, but might inspire something better.
867 Since our gradient vectors' components are all -1, 0 or 1, we should be
868 able to calculate the dot product without any multiplication at all, by
869 simply summing the right combination of (x, y, z), (0, 0, 0) and (-x, -y, -z).
870
871 This turns out to be slightly slower than using multiplication, even if
872 the negations are precalculated.
873*/
874OOINLINE float TDot3(const uint8_t grad[3], float x, float y, float z)
875{
876 float xt[3] = { -x, 0.0f, x };
877 float yt[3] = { -y, 0.0f, y };
878 float zt[3] = { -z, 0.0f, z };
879
880 return xt[grad[0]] + yt[grad[1]] + zt[grad[2]];
881}
882#endif
883
884
885// Sample 3D noise function defined by kGradients and permutation table at point p.
886static float SampleNoise3D(OOPlanetTextureGeneratorInfo *info, Vector p)
887{
888 uint16_t *permutations = info->permutations;
889
890 // Split coordinates into integer and fractional parts.
891 float fx = floor(p.x);
892 float fy = floor(p.y);
893 float fz = floor(p.z);
894 int X = fx;
895 int Y = fy;
896 int Z = fz;
897 float x = p.x - fx;
898 float y = p.y - fy;
899 float z = p.z - fz;
900
901 // Select gradient for each corner.
902#define PERM(v) permutations[(v) & kPermutationMask]
903
904 unsigned PZ0 = PERM(Z);
905 unsigned PZ1 = PERM(Z + 1);
906
907 unsigned PY0Z0 = PERM(Y + PZ0);
908 unsigned PY1Z0 = PERM(Y + 1 + PZ0);
909 unsigned PY0Z1 = PERM(Y + PZ1);
910 unsigned PY1Z1 = PERM(Y + 1 + PZ1);
911
912 unsigned gi000 = PERM(X + PY0Z0);
913 unsigned gi010 = PERM(X + PY1Z0);
914 unsigned gi100 = PERM(X + 1 + PY0Z0);
915 unsigned gi110 = PERM(X + 1 + PY1Z0);
916 unsigned gi001 = PERM(X + PY0Z1);
917 unsigned gi011 = PERM(X + PY1Z1);
918 unsigned gi101 = PERM(X + 1 + PY0Z1);
919 unsigned gi111 = PERM(X + 1 + PY1Z1);
920
921#undef PERM
922
923 // Calculate noise contributions from each of the eight corners.
924#if !LUT_DOT
925#define DOT3(idx, x_, y_, z_) dot_product(kGradients[(idx) % kGradientCount], (Vector){ (x_), (y_), (z_) })
926#else
927#define DOT3(idx, x_, y_, z_) TDot3(kGradients[(idx) % kGradientCount], (x_), (y_), (z_))
928#endif
929
930 float x1 = x - 1.0f;
931 float y1 = y - 1.0f;
932 float z1 = z - 1.0f;
933 float n000 = DOT3(gi000, x , y , z );
934 float n010 = DOT3(gi010, x , y1, z );
935 float n100 = DOT3(gi100, x1, y , z );
936 float n110 = DOT3(gi110, x1, y1, z );
937 float n001 = DOT3(gi001, x , y , z1);
938 float n011 = DOT3(gi011, x , y1, z1);
939 float n101 = DOT3(gi101, x1, y , z1);
940 float n111 = DOT3(gi111, x1, y1, z1);
941
942#undef DOT3
943
944 // Compute the fade curve value for each of x, y, z
945 float u = Hermite(x);
946 float v = Hermite(y);
947 float w = Hermite(z);
948
949 // Interpolate along the contributions from each of the corners.
950 float nx00 = Lerp(n000, n100, u);
951 float nx01 = Lerp(n001, n101, u);
952 float nx10 = Lerp(n010, n110, u);
953 float nx11 = Lerp(n011, n111, u);
954
955 float nxy0 = Lerp(nx00, nx10, v);
956 float nxy1 = Lerp(nx01, nx11, v);
957
958 float nxyz = Lerp(nxy0, nxy1, w);
959
960 return nxyz;
961}
962
963
964// Noise map generator
965static BOOL MakePermutationTable(OOPlanetTextureGeneratorInfo *info)
966{
967 uint16_t *perms = malloc(sizeof *info->permutations * kPermutationCount);
968 if (EXPECT_NOT(perms == NULL)) return NO;
969
970 perms[0] = 0;
971 uint16_t n;
972 for (n = 1; n < kPermutationCount; n++)
973 {
974 perms[n] = RanrotWithSeed(&info->seed) & kPermutationMask;
975 }
976
977 info->permutations = perms;
978 return YES;
979}
980
981
982static BOOL GenerateFBMNoise3D(OOPlanetTextureGeneratorInfo *info)
983{
984 BOOL OK = NO;
985
986 FAIL_IF(!MakePermutationTable(info));
987
988 unsigned x, y, width = info->width, height = info->height;
989 float lon, lat; // Longitude and latitude in radians.
990 float dlon = 2.0f * M_PI / width;
991 float dlat = M_PI / height;
992 float *px = info->fbmBuffer;
993
994 for (y = 0, lat = -M_PI_2; y < height; y++, lat += dlat)
995 {
996 float las = sin(lat);
997 float lac = cos(lat);
998
999 for (x = 0, lon = -M_PI; x < width; x++, lon += dlon)
1000 {
1001 // FIXME: in real life, we really don't want sin and cos per pixel.
1002 // Convert spherical coordinates to vector.
1003 float los = sin(lon);
1004 float loc = cos(lon);
1005
1006 Vector p =
1007 {
1008 los * lac,
1009 las,
1010 loc * lac
1011 };
1012
1013#if 1
1014 // fBM
1015 unsigned octaveMask = 4;
1016 float octave = octaveMask;
1017 octaveMask -= 1;
1018 float scale = 0.4f;
1019 float sum = 0;
1020
1021 while ((octaveMask + 1) < height)
1022 {
1023 Vector ps = vector_multiply_scalar(p, octave);
1024 sum += scale * SampleNoise3D(info, ps);
1025
1026 octave *= 2.0f;
1027 octaveMask = (octaveMask << 1) | 1;
1028 scale *= 0.5f;
1029 }
1030#else
1031 // Single octave
1032 p = vector_multiply_scalar(p, 4.0f);
1033 float sum = 0.5f * SampleNoise3D(info, p);
1034#endif
1035
1036 *px++ = sum + 0.5f;
1037 }
1038 }
1039
1040END:
1041 FREE(info->permutations);
1042 return OK;
1043}
1044
1045
1046// Old 2D value noise.
1047
1048static void FillRandomBuffer(float *randomBuffer, RANROTSeed seed)
1049{
1050 unsigned i, len = kRandomBufferSize * kRandomBufferSize;
1051 for (i = 0; i < len; i++)
1052 {
1053 randomBuffer[i] = randfWithSeed(&seed);
1054 }
1055}
1056
1057
1058static void AddNoise(OOPlanetTextureGeneratorInfo *info, float *randomBuffer, float octave, unsigned octaveMask, float scale, float *qxBuffer, int *ixBuffer)
1059{
1060 unsigned x, y;
1061 unsigned width = info->width, height = info->height;
1062 int ix, jx, iy, jy;
1063 float rr = octave / width;
1064 float fx, fy, qx, qy, rix, rjx, rfinal;
1065 float *dst = info->fbmBuffer;
1066
1067 for (fy = 0, y = 0; y < height; fy++, y++)
1068 {
1069 qy = fy * rr;
1070 iy = fast_floor(qy);
1071 jy = (iy + 1) & octaveMask;
1072 qy = Hermite(qy - iy);
1073 iy &= (kRandomBufferSize - 1);
1074 jy &= (kRandomBufferSize - 1);
1075
1076 for (fx = 0, x = 0; x < width; fx++, x++)
1077 {
1078 if (y == 0)
1079 {
1080 // first pass: initialise buffers.
1081 qx = fx * rr;
1082 ix = fast_floor(qx);
1083 qx -= ix;
1084 ix &= (kRandomBufferSize - 1);
1085 ixBuffer[x] = ix;
1086 qxBuffer[x] = Hermite(qx);
1087 }
1088 else
1089 {
1090 // later passes: grab the stored values.
1091 ix = ixBuffer[x];
1092 qx = qxBuffer[x];
1093 }
1094
1095 jx = (ix + 1) & octaveMask;
1096 jx &= (kRandomBufferSize - 1);
1097
1098 rix = Lerp(randomBuffer[iy * kRandomBufferSize + ix], randomBuffer[iy * kRandomBufferSize + jx], qx);
1099 rjx = Lerp(randomBuffer[jy * kRandomBufferSize + ix], randomBuffer[jy * kRandomBufferSize + jx], qx);
1100 rfinal = Lerp(rix, rjx, qy);
1101
1102 *dst++ += scale * rfinal;
1103 }
1104 }
1105}
1106
1107
1108static BOOL GenerateFBMNoise(OOPlanetTextureGeneratorInfo *info)
1109{
1110 // Allocate the temporary buffers we need in one fell swoop, to avoid administrative overhead.
1111 size_t randomBufferSize = kRandomBufferSize * kRandomBufferSize * sizeof (float);
1112 size_t qxBufferSize = info->width * sizeof (float);
1113 size_t ixBufferSize = info->width * sizeof (int);
1114 char *sharedBuffer = malloc(randomBufferSize + qxBufferSize + ixBufferSize);
1115 if (sharedBuffer == NULL) return NO;
1116
1117 float *randomBuffer = (float *)sharedBuffer;
1118 float *qxBuffer = (float *)(sharedBuffer + randomBufferSize);
1119 int *ixBuffer = (int *)(sharedBuffer + randomBufferSize + qxBufferSize);
1120
1121 // Get us some value noise.
1122 FillRandomBuffer(randomBuffer, info->seed);
1123
1124 // Generate basic fBM noise.
1125 unsigned height = info->height;
1126 unsigned octaveMask = 8 * info->planetAspectRatio;
1127 float octave = octaveMask;
1128 octaveMask -= 1;
1129 float scale = 0.5f;
1130
1131 while ((octaveMask + 1) < height)
1132 {
1133 AddNoise(info, randomBuffer, octave, octaveMask, scale, qxBuffer, ixBuffer);
1134 octave *= 2.0f;
1135 octaveMask = (octaveMask << 1) | 1;
1136 scale *= 0.5f;
1137 }
1138
1139 FREE(sharedBuffer);
1140 return YES;
1141}
1142
1143
1144
1145static float QFactor(float *accbuffer, int x, int y, unsigned width, float polar_y_value, float bias, float polar_y)
1146{
1147 float q = accbuffer[y * width + x]; // 0.0 -> 1.0
1148 q += bias;
1149
1150 // Polar Y smooth.
1151 q = q * (1.0f - polar_y) + polar_y * polar_y_value;
1152
1153 return q;
1154}
1155
1156
1157static float GetQ(float *qbuffer, int x, int y, unsigned width, unsigned height, unsigned widthMask, unsigned heightMask)
1158{
1159 // Correct Y wrapping mode, unoptimised.
1160 //if (y < 0) { y = -y - 1; x += width / 2; }
1161 //else if (y >= height) { y = height - (y - height) - 1; x += width / 2; }
1162 // now let's wrap x.
1163 //x = x % width;
1164
1165 // Correct Y wrapping mode, faster method. In the following lines of code, both
1166 // width and height are assumed to be powers of 2: 512, 1024, 2048, etc...
1167 if (y & height) { y = (y ^ heightMask) & heightMask; x += width >> 1; }
1168 // x wrapping.
1169 x &= widthMask;
1170 return qbuffer[y * width + x];
1171}
1172
1173
1174static void SetMixConstants(OOPlanetTextureGeneratorInfo *info, float temperatureFraction)
1175{
1176 info->mix_hi = 0.66667f * info->landFraction;
1177 info->mix_oh = 1.0f / info->mix_hi;
1178 info->mix_ih = 1.0f / (1.0f - info->mix_hi);
1179 info->mix_polarCap = temperatureFraction * (0.28f + 0.24f * info->landFraction); // landmasses make the polar cap proportionally bigger, but not too much bigger.
1180}
1181
1182
1183@implementation OOPlanetNormalMapGenerator
1184
1185- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed
1186{
1187 // AllowCubeMap not used yet but might be in future
1188 if ((self = [super initWithPath:[NSString stringWithFormat:@"OOPlanetNormalTexture@%p", self] options:kOOTextureAllowCubeMap]))
1189 {
1190 _enqueued = NO;
1191 _cacheKey = [cacheKey copy];
1192 _seed = seed;
1193 }
1194 return self;
1195}
1196
1197
1198- (void) dealloc
1199{
1200 DESTROY(_cacheKey);
1201
1202 [super dealloc];
1203}
1204
1205
1206- (NSString *) cacheKey
1207{
1208 return _cacheKey;
1209}
1210
1211
1212- (uint32_t) textureOptions
1213{
1214 return PLANET_TEXTURE_OPTIONS;
1215}
1216
1217
1218- (BOOL) enqueue
1219{
1220 /* This generator doesn't do any work, so it doesn't need to be queued
1221 at the normal time.
1222 (The alternative would be for it to block a work thread waiting for
1223 the real generator to complete, which seemed silly.)
1224 */
1225 _enqueued = YES;
1226 return YES;
1227}
1228
1229
1230- (BOOL) enqueued
1231{
1232 return _enqueued;
1233}
1234
1235
1236- (void) loadTexture
1237{
1238 // Do nothing.
1239}
1240
1241
1242- (void) completeWithData:(void *)data_ width:(unsigned)width_ height:(unsigned)height_
1243{
1244 _data = data_;
1245 _width = width_;
1246 _height = height_;
1247 _format = kOOTextureDataRGBA;
1248
1249 // Enqueue so superclass can apply texture options and so forth.
1250 [super enqueue];
1251
1252#if DEBUG_DUMP
1253 NSString *normalName = [NSString stringWithFormat:@"planet-%u-%u-normal-new", _seed.high, _seed.low];
1254 NSString *specularName = [NSString stringWithFormat:@"planet-%u-%u-specular-new", _seed.high, _seed.low];
1255
1256 [[UNIVERSE gameView] dumpRGBAToRGBFileNamed:normalName
1257 andGrayFileNamed:specularName
1258 bytes:_data
1259 width:_width
1260 height:_height
1261 rowBytes:_width * 4];
1262#endif
1263}
1264
1265@end
1266
1267
1268@implementation OOPlanetAtmosphereGenerator
1269
1270- (id) initWithCacheKey:(NSString *)cacheKey seed:(RANROTSeed)seed andParent:(OOPlanetTextureGenerator *)parent
1271{
1272 OOLog(@"texture.planet.generate",@"Initialising atmosphere generator %@",cacheKey);
1273 // AllowCubeMap not used yet but might be in future
1274 if ((self = [super initWithPath:[NSString stringWithFormat:@"OOPlanetAtmoTexture@%p", self] options:kOOTextureAllowCubeMap]))
1275 {
1276 _cacheKey = [cacheKey copy];
1277 _seed = seed;
1278 _parent = [parent retain];
1279 _enqueued = NO;
1280 }
1281 return self;
1282}
1283
1284
1285- (void) dealloc
1286{
1287 DESTROY(_cacheKey);
1288 DESTROY(_parent);
1289 [super dealloc];
1290}
1291
1292
1293- (NSString *) cacheKey
1294{
1295 return _cacheKey;
1296}
1297
1298
1299- (uint32_t) textureOptions
1300{
1301 return PLANET_TEXTURE_OPTIONS;
1302}
1303
1304
1305- (BOOL) enqueue
1306{
1307 _enqueued = YES;
1308 return YES;
1309}
1310
1311
1312- (BOOL) enqueued
1313{
1314 return _enqueued;
1315}
1316
1317
1318- (void) loadTexture
1319{
1320 // Do nothing.
1321}
1322
1323
1324/* Because of the hack to avoid making texture loaders need to know
1325 * about multiple textures, when we call the atmosphere generator on a
1326 * planet with a from-file texture, things can occasionally go wrong
1327 * because this isn't queued until after it's ready, but might be
1328 * requested from the queue before then. So, when getResult is called,
1329 * it waits for its parent task to complete if it's not itself ready -
1330 * by the time the parent task is complete, this texture loader will
1331 * have been enqueued, and [super getResult] will then work
1332 * properly. - CIM 2014-04-05 */
1333- (BOOL) getResult:(OOPixMap *)result
1334 format:(OOTextureDataFormat *)outFormat
1335 originalWidth:(uint32_t *)outWidth
1336 originalHeight:(uint32_t *)outHeight
1337{
1338 if (!_ready)
1339 {
1341 }
1342
1343 return [super getResult:result
1344 format:outFormat
1345 originalWidth:outWidth
1346 originalHeight:outHeight];
1347}
1348
1349
1350- (void) completeWithData:(void *)data_ width:(unsigned)width_ height:(unsigned)height_
1351{
1352 OOLog(@"texture.planet.generate", @"%@", @"Completing atmosphere generator");
1353
1354 _data = data_;
1355 _width = width_;
1356 _height = height_;
1357 _format = kOOTextureDataRGBA;
1358
1359 // Enqueue so superclass can apply texture options and so forth.
1360 [super enqueue];
1361
1362#if DEBUG_DUMP
1363 NSString *rgbName = [NSString stringWithFormat:@"planet-%u-%u-atmosphere-rgb-new", _seed.high, _seed.low];
1364 NSString *alphaName = [NSString stringWithFormat:@"planet-%u-%u-atmosphere-alpha-new", _seed.high, _seed.low];
1365
1366 [[UNIVERSE gameView] dumpRGBAToRGBFileNamed:rgbName
1367 andGrayFileNamed:alphaName
1368 bytes:_data
1369 width:_width
1370 height:_height
1371 rowBytes:_width * 4];
1372#endif
1373}
1374
1375@end
1376
1377#endif // NEW_PLANETS
#define DESTROY(x)
Definition OOCocoa.h:77
#define EXPECT_NOT(x)
#define OOINLINE
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define M_PI_2
Definition OOMaths.h:76
#define M_PI
Definition OOMaths.h:73
OOPixMapFormat
Definition OOPixMap.h:39
return nil
float y
float x
@ kOOTextureDataRGBA
Definition OOTexture.h:109
@ kOOTextureAllowCubeMap
Definition OOTexture.h:61
OOGraphicsDetail
Definition OOTypes.h:243
@ DETAIL_LEVEL_SHADERS
Definition OOTypes.h:246
const Vector kBasisZVector
Definition OOVector.m:31
#define CLOUD_ALPHA
static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key)
static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
void waitForTaskToComplete:(id< OOAsyncWorkTask > task)
OOAsyncWorkManager * sharedAsyncWorkManager()
float blueComponent()
Definition OOColor.m:362
float redComponent()
Definition OOColor.m:350
float greenComponent()
Definition OOColor.m:356
id textureWithGenerator:(OOTextureGenerator *generator)
Definition OOTexture.m:217
id textureWithGenerator:enqueue:(OOTextureGenerator *generator,[enqueue] BOOL enqueue)
Definition OOTexture.m:223
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
float randfWithSeed(RANROTSeed *ioSeed)
unsigned RanrotWithSeed(RANROTSeed *ioSeed)