33#define DEBUG_DUMP ( 0 && OOLITE_DEBUG)
34#define DEBUG_DUMP_RAW ( 1 && DEBUG_DUMP)
36#define ALBEDO_FACTOR 0.7f
42#ifndef TEXGEN_TEST_RIG
48#import "MyOpenGLView.h"
52#define FREE(x) do { if (0) { void *x__ = x; x__ = x__; } void **x_ = (void **)&(x); free(*x_); *x_ = NULL; } while (0)
55#define PLANET_TEXTURE_OPTIONS (kOOTextureMinFilterLinear | kOOTextureMagFilterLinear | kOOTextureRepeatS | kOOTextureNoShrink)
60 kRandomBufferSize = 128
64@interface OOStandaloneAtmosphereGenerator (Private)
67- (void) dumpNoiseBuffer:(
float *)noise;
76static float QFactor(
float *accbuffer,
int x,
int y,
unsigned width,
float polar_y_value,
float bias,
float polar_y);
77static float BlendAlpha(
float fraction,
float a,
float b);
83 kPlanetScale256x256 = 1,
85 kPlanetScale1024x1024,
86 kPlanetScale2048x2048,
87 kPlanetScale4096x4096,
89 kPlanetScaleReducedDetail = kPlanetScale512x512,
90 kPlanetScaleFullDetail = kPlanetScale1024x1024
96- (id) initWithPlanetInfo:(NSDictionary *)planetInfo
98 OOLog(
@"texture.planet.generate",
@"%@",
@"Initialising standalone atmosphere generator");
101 if ((
self = [super initWithPath:[NSString stringWithFormat:
@"OOStandaloneAtmosphereTexture@%p",
self] options:
kOOTextureAllowCubeMap]))
103 OOLog(
@"texture.planet.generate",
@"Extracting parameters for generator %@",
self);
104 [[planetInfo objectForKey:@"noise_map_seed"] getValue:&_info.seed];
105 OOLog(
@"texture.planet.generate",
@"%@",
@"Extracting atmosphere parameters");
107 _info.cloudAlpha = [planetInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0f];
108 _info.cloudFraction = OOClamp_0_1_f([planetInfo oo_floatForKey:
@"cloud_fraction" defaultValue:0.3]);
114#ifndef TEXGEN_TEST_RIG
117 _planetScale = kPlanetScaleReducedDetail;
121 _planetScale = kPlanetScaleFullDetail;
124 _planetScale = kPlanetScale4096x4096;
126 _info.perlin3d = [planetInfo oo_boolForKey:@"perlin_3d" defaultValue:detailLevel > DETAIL_LEVEL_SHADERS];
127 _info.planetAspectRatio = _info.perlin3d ? 2 : 1;
128 _info.planetScaleOffset = 8 - _info.planetAspectRatio;
135+ (
OOTexture *) planetTextureWithInfo:(NSDictionary *)planetInfo
139 if (generator !=
nil)
149+ (BOOL) generateAtmosphereTexture:(
OOTexture **)texture withInfo:(NSDictionary *)planetInfo
151 NSParameterAssert(texture != NULL);
154 if (atmoGen ==
nil)
return NO;
158 return *texture !=
nil;
168- (NSString *) descriptionComponents
170 return [NSString stringWithFormat:@"seed: %u,%u", _info.seed.high, _info.seed.low];
174- (uint32_t) textureOptions
176 return PLANET_TEXTURE_OPTIONS;
180- (NSString *) cacheKey
182 return [NSString stringWithFormat:@"OOStandaloneAtmosphereGenerator-@%u\n%u,%u/%u,%u/%f/%f/%f,%f,%f/%f,%f,%f/%f,%f,%f",
184 _info.width, _info.height, _info.seed.high, _info.seed.low,
185 _info.cloudAlpha, _info.cloudFraction,
186 _info.airColor.r, _info.airColor.g, _info.airColor.b,
187 _info.cloudColor.r, _info.cloudColor.g, _info.cloudColor.b,
188 _info.paleCloudColor.r, _info.paleCloudColor.g, _info.paleCloudColor.b
194- (BOOL)getResult:(
OOPixMap *)outData
196 width:(uint32_t *)outWidth
197 height:(uint32_t *)outHeight
203 OOLog(
@"texture.planet.generate.wait",
@"%s generator %@",
"Waiting for",
self);
206 BOOL result = [
super getResult:outData format:outFormat originalWidth:outWidth originalHeight:outHeight];
210 OOLog(
@"texture.planet.generate.dequeue",
@"%s generator %@", result ?
"Dequeued" :
"Failed to dequeue",
self);
214 OOLog(
@"texture.planet.generate.dequeue",
@"%s generator %@ without waiting.", result ?
"Dequeued" :
"Failed to dequeue",
self);
224 OOLog(
@"texture.planet.generate.begin",
@"Started generator %@",
self);
228 uint8_t *aBuffer = NULL, *apx = NULL;
229 float *randomBuffer = NULL;
231 _height = _info.height = 1 << (_planetScale + _info.planetScaleOffset);
232 _width = _info.width = _height * _info.planetAspectRatio;
234#define FAIL_IF(cond) do { if (EXPECT_NOT(cond)) goto END; } while (0)
235#define FAIL_IF_NULL(x) FAIL_IF((x) == NULL)
237 aBuffer = malloc(4 * _width * _height);
238 FAIL_IF_NULL(aBuffer);
241 FAIL_IF(!FillFBMBuffer(&_info));
243 [
self dumpNoiseBuffer:_info.fbmBuffer];
246 float paleClouds = (_info.cloudFraction * _info.fbmBuffer[0] < 1.0f - _info.cloudFraction) ? 0.0f : 1.0f;
251 float rHeight = 1.0f / _height;
252 float fy, fHeight = _height;
254 float cloudFraction = _info.cloudFraction;
256 for (
y = (
int)_height - 1, fy = (
float)
y;
y >= 0;
y--, fy--)
258 nearPole = (2.0f * fy - fHeight) * rHeight;
259 nearPole *= nearPole;
261 for (
x = (
int)_width - 1;
x >= 0;
x--)
263 q = QFactor(_info.fbmBuffer,
x,
y, _width, paleClouds, cloudFraction, nearPole);
264 color = CloudMix(&_info, q, nearPole);
265 *apx++ = 255.0f * color.r;
266 *apx++ = 255.0f * color.g;
267 *apx++ = 255.0f * color.b;
268 *apx++ = 255.0f * color.a * _info.cloudAlpha;
276 FREE(_info.fbmBuffer);
287 OOLog(
@"texture.planet.generate.complete",
@"Completed generator %@ %@successfully",
self, success ?
@"" :
@"un");
292 NSString *diffuseName = [NSString stringWithFormat:@"atmosphere-%u-%u-diffuse-new", _info.seed.high, _info.seed.low];
293 NSString *lightsName = [NSString stringWithFormat:@"atmosphere-%u-%u-alpha-new", _info.seed.high, _info.seed.low];
295 [[UNIVERSE gameView] dumpRGBAToRGBFileNamed:diffuseName
296 andGrayFileNamed:lightsName
300 rowBytes:_width * 4];
308- (void) dumpNoiseBuffer:(
float *)noise
310 NSString *noiseName = [NSString stringWithFormat:@"atmosphere-%u-%u-noise-new", _info.seed.high, _info.seed.low];
312 uint8_t *noisePx = malloc(_width * _height);
314 for (
y = 0;
y < _height;
y++)
316 for (
x = 0;
x < _width;
x++)
318 noisePx[y * _width + x] = 255.0f * noise[y * _width + x];
322 [[UNIVERSE gameView] dumpGrayToFileNamed:noiseName
335OOINLINE float Lerp(
float v0,
float v1,
float fraction)
338 return v0 + fraction * (v1 - v0);
346 Lerp(b.
r, a.
r, fraction),
347 Lerp(b.
g, a.
g, fraction),
348 Lerp(b.
b, a.
b, fraction)
353static float BlendAlpha(
float fraction,
float a,
float b)
355 return Lerp(b, a, fraction);
364#define AIR_ALPHA (0.05f)
365#define CLOUD_ALPHA (2.0f)
367#define POLAR_BOUNDARY (0.33f)
368#define CLOUD_BOUNDARY (0.5f)
369#define RECIP_CLOUD_BOUNDARY (1.0f / CLOUD_BOUNDARY)
372 float alpha = info->
cloudAlpha, portion = 0.0f;
374 q -= CLOUD_BOUNDARY * 0.5f;
376 if (nearPole > POLAR_BOUNDARY)
378 portion = nearPole > POLAR_BOUNDARY + 0.2f ? 1.0f : (nearPole - POLAR_BOUNDARY) * 5.0f;
381 portion = nearPole > POLAR_BOUNDARY + 0.625f ? 1.0f : (nearPole - POLAR_BOUNDARY) * 1.6f;
386 if (q >= -CLOUD_BOUNDARY)
388 alpha *= BlendAlpha(-q * 0.5f * RECIP_CLOUD_BOUNDARY + 0.5f,
CLOUD_ALPHA, AIR_ALPHA);
397 if (q < CLOUD_BOUNDARY)
399 alpha *= BlendAlpha( q * 0.5f * RECIP_CLOUD_BOUNDARY + 0.5f, AIR_ALPHA,
CLOUD_ALPHA);
407 alpha *= BlendAlpha(portion, 0.6f, 1.0f);
413 return (
FloatRGBA){ cloudColor.
r, cloudColor.
g, cloudColor.
b, alpha };
419 OOColor *color = [dictionary objectForKey:key];
420 NSCAssert1([color isKindOfClass:[
OOColor class]],
@"Expected OOColor, got %@", [color
class]);
428 return 3.0f * q * q - 2.0f * q * q * q;
440OOINLINE int32_t fast_floor(
double val)
442 val += 68719476736.0 * 1.5;
443 return (((int32_t*)&val)[iman_] >> 16);
453 NSCParameterAssert(info != NULL);
461 GenerateFBMNoise(info);
465 GenerateFBMNoise3D(info);
479 kPermutationCount = 1 << 10,
480 kPermutationMask = kPermutationCount - 1,
491static const Vector kGradients[kGradientCount] =
507static const uint8_t kGradients[kGradientCount][3] =
532OOINLINE float TDot3(
const uint8_t grad[3],
float x,
float y,
float z)
534 float xt[3] = { -
x, 0.0f,
x };
535 float yt[3] = { -
y, 0.0f,
y };
536 float zt[3] = { -z, 0.0f, z };
538 return xt[grad[0]] + yt[grad[1]] + zt[grad[2]];
549 float fx = floor(p.x);
550 float fy = floor(p.y);
551 float fz = floor(p.z);
560#define PERM(v) permutations[(v) & kPermutationMask]
562 unsigned PZ0 = PERM(Z);
563 unsigned PZ1 = PERM(Z + 1);
565 unsigned PY0Z0 = PERM(Y + PZ0);
566 unsigned PY1Z0 = PERM(Y + 1 + PZ0);
567 unsigned PY0Z1 = PERM(Y + PZ1);
568 unsigned PY1Z1 = PERM(Y + 1 + PZ1);
570 unsigned gi000 = PERM(X + PY0Z0);
571 unsigned gi010 = PERM(X + PY1Z0);
572 unsigned gi100 = PERM(X + 1 + PY0Z0);
573 unsigned gi110 = PERM(X + 1 + PY1Z0);
574 unsigned gi001 = PERM(X + PY0Z1);
575 unsigned gi011 = PERM(X + PY1Z1);
576 unsigned gi101 = PERM(X + 1 + PY0Z1);
577 unsigned gi111 = PERM(X + 1 + PY1Z1);
583#define DOT3(idx, x_, y_, z_) dot_product(kGradients[(idx) % kGradientCount], (Vector){ (x_), (y_), (z_) })
585#define DOT3(idx, x_, y_, z_) TDot3(kGradients[(idx) % kGradientCount], (x_), (y_), (z_))
591 float n000 = DOT3(gi000,
x ,
y , z );
592 float n010 = DOT3(gi010,
x , y1, z );
593 float n100 = DOT3(gi100, x1,
y , z );
594 float n110 = DOT3(gi110, x1, y1, z );
595 float n001 = DOT3(gi001,
x ,
y , z1);
596 float n011 = DOT3(gi011,
x , y1, z1);
597 float n101 = DOT3(gi101, x1,
y , z1);
598 float n111 = DOT3(gi111, x1, y1, z1);
603 float u = Hermite(
x);
604 float v = Hermite(
y);
605 float w = Hermite(z);
608 float nx00 = Lerp(n000, n100, u);
609 float nx01 = Lerp(n001, n101, u);
610 float nx10 = Lerp(n010, n110, u);
611 float nx11 = Lerp(n011, n111, u);
613 float nxy0 = Lerp(nx00, nx10, v);
614 float nxy1 = Lerp(nx01, nx11, v);
616 float nxyz = Lerp(nxy0, nxy1, w);
630 uint16_t *perms = malloc(
sizeof *info->
permutations * kPermutationCount);
640 uint16_t *curr = perms;
642 for (n = 1; n < kPermutationCount; n++)
658 FAIL_IF(!MakePermutationTable(info));
662 float dlon = 2.0f *
M_PI / width;
663 float dlat =
M_PI / height;
666 for (
y = 0, lat = -
M_PI_2;
y < height;
y++, lat += dlat)
668 float las = sin(lat);
669 float lac = cos(lat);
671 for (
x = 0, lon = -
M_PI;
x < width;
x++, lon += dlon)
675 float los = sin(lon);
676 float loc = cos(lon);
687 unsigned octaveMask = 4;
688 float octave = octaveMask;
693 while ((octaveMask + 1) < height)
695 Vector ps = vector_multiply_scalar(p, octave);
696 sum += scale * SampleNoise3D(info, ps);
699 octaveMask = (octaveMask << 1) | 1;
704 p = vector_multiply_scalar(p, 4.0f);
705 float sum = 0.5f * SampleNoise3D(info, p);
719static void FillRandomBuffer(
float *randomBuffer,
RANROTSeed seed)
721 unsigned i, len = kRandomBufferSize * kRandomBufferSize;
722 for (i = 0; i < len; i++)
732 unsigned width = info->
width, height = info->
height;
734 float rr = octave / width;
735 float fx, fy, qx, qy, rix, rjx, rfinal;
738 for (fy = 0,
y = 0;
y < height; fy++,
y++)
742 jy = (iy + 1) & octaveMask;
743 qy = Hermite(qy - iy);
744 iy &= (kRandomBufferSize - 1);
745 jy &= (kRandomBufferSize - 1);
747 for (fx = 0,
x = 0;
x < width; fx++,
x++)
755 ix &= (kRandomBufferSize - 1);
757 qxBuffer[x] = Hermite(qx);
766 jx = (ix + 1) & octaveMask;
767 jx &= (kRandomBufferSize - 1);
769 rix = Lerp(randomBuffer[iy * kRandomBufferSize + ix], randomBuffer[iy * kRandomBufferSize + jx], qx);
770 rjx = Lerp(randomBuffer[jy * kRandomBufferSize + ix], randomBuffer[jy * kRandomBufferSize + jx], qx);
771 rfinal = Lerp(rix, rjx, qy);
773 *dst++ += scale * rfinal;
782 size_t randomBufferSize = kRandomBufferSize * kRandomBufferSize *
sizeof (float);
783 size_t qxBufferSize = info->
width *
sizeof (float);
784 size_t ixBufferSize = info->
width *
sizeof (
int);
785 char *sharedBuffer = malloc(randomBufferSize + qxBufferSize + ixBufferSize);
786 if (sharedBuffer == NULL)
return NO;
788 float *randomBuffer = (
float *)sharedBuffer;
789 float *qxBuffer = (
float *)(sharedBuffer + randomBufferSize);
790 int *ixBuffer = (
int *)(sharedBuffer + randomBufferSize + qxBufferSize);
793 FillRandomBuffer(randomBuffer, info->
seed);
796 unsigned height = info->
height;
798 float octave = octaveMask;
802 while ((octaveMask + 1) < height)
804 AddNoise(info, randomBuffer, octave, octaveMask, scale, qxBuffer, ixBuffer);
806 octaveMask = (octaveMask << 1) | 1;
816static float QFactor(
float *accbuffer,
int x,
int y,
unsigned width,
float polar_y_value,
float bias,
float polar_y)
818 float q = accbuffer[y * width + x];
822 q = q * (1.0f - polar_y) + polar_y * polar_y_value;
#define OOLog(class, format,...)
static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key)
static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
id textureWithGenerator:(OOTextureGenerator *generator)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
float randfWithSeed(RANROTSeed *ioSeed)
unsigned RanrotWithSeed(RANROTSeed *ioSeed)
unsigned planetAspectRatio