Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
TextureStore.m
Go to the documentation of this file.
1/*
2
3TextureStore.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "OOCocoa.h"
26#import "TextureStore.h"
27#if !NEW_PLANETS
28
29#import "OOMaths.h"
30
31#ifndef NDEBUG
32#import "Universe.h"
33#import "MyOpenGLView.h"
34#else
35#import "OOColor.h"
36#endif
37
39
40#define DEBUG_DUMP ( 0 && OOLITE_DEBUG)
41
42
43static NSString * const kOOLogPlanetTextureGen = @"texture.planet.generate";
44
45
46#import "OOTextureGenerator.h" // For FloatRGB
47
48
49static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key)
50{
51 OOColor *color = [dictionary objectForKey:key];
52 if (color == nil)
53 {
54 // could not get a color from the dicitionary, return white color instead of hitting the assert below
55 color = [OOColor colorWithDescription:@"whiteColor"];
56 OOLog(@"textureStore.FloatRGBFromDictColor.nilColor", @"Expected color for key \"%@\" in dictionary %@, got nil. Setting color to %@", key, dictionary, [color rgbaDescription]);
57 }
58 NSCAssert1([color isKindOfClass:[OOColor class]], @"Expected OOColor, got %@", [color class]);
59
60 return (FloatRGB){ [color redComponent], [color greenComponent], [color blueComponent] };
61}
62
63
64static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
65{
66 return (FloatRGB)
67 {
68 OOLerp(a.r, b.r, fraction),
69 OOLerp(a.g, b.g, fraction),
70 OOLerp(a.b, b.b, fraction)
71 };
72}
73
74
75static FloatRGB PlanetTextureColor(float q, float impress, float bias, FloatRGB seaColor, FloatRGB paleSeaColor, FloatRGB landColor, FloatRGB paleLandColor)
76{
77 const FloatRGB kWhite = { 1.0, 1.0, 1.0 };
78 float maxq = impress + bias;
79
80 float hi = 0.66667 * maxq;
81 float oh = 1.0 / hi;
82 float ih = 1.0 / (1.0 - hi);
83
84 if (q <= 0.0)
85 {
86 return seaColor;
87 }
88 if (q > 1.0)
89 {
90 return (FloatRGB){ 1.0f, 1.0f, 1.0f };
91 }
92 if (q < 0.01)
93 {
94 return Blend(q * 100.0f, paleSeaColor, landColor);
95 }
96 if (q > hi)
97 {
98 return Blend((q - hi) * ih, paleLandColor, kWhite); // snow capped peaks
99 }
100
101 return Blend((hi - q) * oh, paleLandColor, landColor);
102}
103
104
105static void fillSquareImageDataWithCloudTexture(unsigned char * imageBuffer, int width, OOColor* cloudcolor, float impress, float bias);
106static void fillSquareImageWithPlanetTex(unsigned char * imageBuffer, int width, float impress, float bias, FloatRGB seaColor, FloatRGB paleSeaColor, FloatRGB landColor, FloatRGB paleLandColor);
107
108
109@implementation TextureStore
110
111
112#define PROC_TEXTURE_SIZE 512
113
114+ (BOOL) getPlanetTextureNameFor:(NSDictionary *)planetInfo intoData:(unsigned char **)textureData width:(GLuint *)textureWidth height:(GLuint *)textureHeight
115{
116 int texture_h = PROC_TEXTURE_SIZE;
117 int texture_w = PROC_TEXTURE_SIZE;
118
119 int tex_bytes = texture_w * texture_h * 4;
120
121 NSParameterAssert(textureData != NULL && textureWidth != NULL && textureHeight != NULL);
122
123 unsigned char *imageBuffer = malloc(tex_bytes);
124 if (imageBuffer == NULL) return NO;
125
126 *textureData = imageBuffer;
127 *textureWidth = texture_w;
128 *textureHeight = texture_h;
129
130 float land_fraction = [[planetInfo objectForKey:@"land_fraction"] floatValue];
131 float sea_bias = land_fraction - 1.0;
132
133 OOLog(kOOLogPlanetTextureGen, @"genning texture for land_fraction %.5f", land_fraction);
134
135 FloatRGB land_color = FloatRGBFromDictColor(planetInfo, @"land_color");
136 FloatRGB sea_color = FloatRGBFromDictColor(planetInfo, @"sea_color");
137 FloatRGB polar_land_color = FloatRGBFromDictColor(planetInfo, @"polar_land_color");
138 FloatRGB polar_sea_color = FloatRGBFromDictColor(planetInfo, @"polar_sea_color");
139
140 // Pale sea colour gives a better transition between land and sea., Backported from the new planets code.
141 FloatRGB pale_sea_color = Blend(0.45, polar_sea_color, Blend(0.7, sea_color, land_color));
142
143 fillSquareImageWithPlanetTex(imageBuffer, texture_w, 1.0, sea_bias,
144 sea_color,
145 pale_sea_color,
146 land_color,
147 polar_land_color);
148
149 return YES;
150}
151
152
153+ (BOOL) getCloudTextureNameFor:(OOColor*)color :(GLfloat)impress :(GLfloat)bias intoData:(unsigned char **)textureData width:(GLuint *)textureWidth height:(GLuint *)textureHeight
154{
155 int texture_h = PROC_TEXTURE_SIZE;
156 int texture_w = PROC_TEXTURE_SIZE;
157 int tex_bytes;
158
159 tex_bytes = texture_w * texture_h * 4;
160
161 NSParameterAssert(textureData != NULL && textureWidth != NULL && textureHeight != NULL);
162
163 unsigned char *imageBuffer = malloc(tex_bytes);
164 if (imageBuffer == NULL) return NO;
165
166 *textureData = imageBuffer;
167 *textureWidth = texture_w;
168 *textureHeight = texture_h;
169
170 fillSquareImageDataWithCloudTexture( imageBuffer, texture_w, color, impress, bias);
171
172 return YES;
173}
174
175@end
176
177
179static float ranNoiseBuffer[128 * 128];
180
182{
184
185 int i;
186 for (i = 0; i < 16384; i++)
187 ranNoiseBuffer[i] = randf();
188}
189
190
191static void addNoise(float * buffer, int p, int n, float scale)
192{
193 int x, y;
194
195 float r = (float)p / (float)n;
196 for (y = 0; y < p; y++) for (x = 0; x < p; x++)
197 {
198 int ix = floor( (float)x / r);
199 int jx = (ix + 1) % n;
200 int iy = floor( (float)y / r);
201 int jy = (iy + 1) % n;
202 float qx = x / r - ix;
203 float qy = y / r - iy;
204 ix &= 127;
205 iy &= 127;
206 jx &= 127;
207 jy &= 127;
208 float rix = OOLerp(ranNoiseBuffer[iy * 128 + ix], ranNoiseBuffer[iy * 128 + jx], qx);
209 float rjx = OOLerp(ranNoiseBuffer[jy * 128 + ix], ranNoiseBuffer[jy * 128 + jx], qx);
210 float rfinal = scale * OOLerp(rix, rjx, qy);
211
212 buffer[y * p + x] += rfinal;
213 }
214}
215
216
217static float q_factor(float* accbuffer, int x, int y, int width, BOOL polar_y_smooth, float polar_y_value, BOOL polar_x_smooth, float polar_x_value, float impress, float bias)
218{
219 while ( x < 0 ) x+= width;
220 while ( y < 0 ) y+= width;
221 while ( x >= width ) x-= width;
222 while ( y >= width ) y-= width;
223
224 float q = accbuffer[ y * width + x]; // 0.0 -> 1.0
225
226 q *= impress; // impress
227 q += bias; // + bias
228
229 float polar_y = (2.0f * y - width) / (float) width;
230 float polar_x = (2.0f * x - width) / (float) width;
231
232 polar_x *= polar_x;
233 polar_y *= polar_y;
234
235 if (polar_x_smooth)
236 q = q * (1.0 - polar_x) + polar_x * polar_x_value;
237 if (polar_y_smooth)
238 q = q * (1.0 - polar_y) + polar_y * polar_y_value;
239
240 if (q > 1.0) q = 1.0;
241 if (q < 0.0) q = 0.0;
242
243 return q;
244}
245
246
247static void fillSquareImageDataWithCloudTexture(unsigned char * imageBuffer, int width, OOColor* cloudcolor, float impress, float bias)
248{
249 NSCParameterAssert(width > 0);
250
251 float accbuffer[width * width];
252 memset(accbuffer, 0, sizeof accbuffer);
253 int x, y;
254
255 GLfloat rgba[4];
256 rgba[0] = [cloudcolor redComponent];
257 rgba[1] = [cloudcolor greenComponent];
258 rgba[2] = [cloudcolor blueComponent];
259 rgba[3] = [cloudcolor alphaComponent];
260
261 int octave = 8;
262 float scale = 0.5;
263 while (octave < width)
264 {
265 addNoise(accbuffer, width, octave, scale);
266 octave *= 2;
267 scale *= 0.5;
268 }
269
270 float pole_value = (impress * accbuffer[0] - bias < 0.0)? 0.0: 1.0;
271
272 for (y = 0; y < width; y++) for (x = 0; x < width; x++)
273 {
274 float q = q_factor(accbuffer, x, y, width, YES, pole_value, NO, 0.0, impress, bias);
275
276 imageBuffer[0 + 4 * (y * width + x) ] = 255 * rgba[0];
277 imageBuffer[1 + 4 * (y * width + x) ] = 255 * rgba[1];
278 imageBuffer[2 + 4 * (y * width + x) ] = 255 * rgba[2];
279 imageBuffer[3 + 4 * (y * width + x) ] = 255 * rgba[3] * q;
280 }
281#if DEBUG_DUMP
282 NSString *name = [NSString stringWithFormat:@"atmosphere-%u-%u-old", sNoiseSeed.high, sNoiseSeed.low];
283 OOLog(@"planetTex.dump", [NSString stringWithFormat:@"Saving generated texture to file %@.", name]);
284
285 [[UNIVERSE gameView] dumpRGBAToFileNamed:name
286 bytes:imageBuffer
287 width:width
288 height:width
289 rowBytes:width * 4];
290#endif
291}
292
293static void fillSquareImageWithPlanetTex(unsigned char * imageBuffer, int width, float impress, float bias,
294 FloatRGB seaColor,
295 FloatRGB paleSeaColor,
296 FloatRGB landColor,
297 FloatRGB paleLandColor)
298{
299 float accbuffer[width * width];
300 memset(accbuffer, 0, sizeof accbuffer);
301
302 int octave = 8;
303 float scale = 0.5;
304 while (octave < width)
305 {
306 addNoise(accbuffer, width, octave, scale);
307 octave *= 2;
308 scale *= 0.5;
309 }
310
311 float pole_value = (impress + bias > 0.5)? 0.5 * (impress + bias) : 0.0;
312
313 int x, y;
314 for (y = 0; y < width; y++) for (x = 0; x < width; x++)
315 {
316 float q = q_factor(accbuffer, x, y, width, YES, pole_value, NO, 0.0, impress, bias);
317
318 float yN = q_factor(accbuffer, x, y - 1, width, YES, pole_value, NO, 0.0, impress, bias);
319 float yS = q_factor(accbuffer, x, y + 1, width, YES, pole_value, NO, 0.0, impress, bias);
320 float yW = q_factor(accbuffer, x - 1, y, width, YES, pole_value, NO, 0.0, impress, bias);
321 float yE = q_factor(accbuffer, x + 1, y, width, YES, pole_value, NO, 0.0, impress, bias);
322
323 Vector norm = make_vector( 24.0 * (yW - yE), 24.0 * (yS - yN), 2.0);
324
325 norm = vector_normal(norm);
326
327 GLfloat shade = pow(norm.z, 3.2);
328
329 FloatRGB color = PlanetTextureColor(q, impress, bias, seaColor, paleSeaColor, landColor, paleLandColor);
330
331 color.r *= shade;
332 color.g *= shade;
333 color.b *= shade;
334
335 imageBuffer[0 + 4 * (y * width + x)] = 255 * color.r;
336 imageBuffer[1 + 4 * (y * width + x)] = 255 * color.g;
337 imageBuffer[2 + 4 * (y * width + x)] = 255 * color.b;
338 imageBuffer[3 + 4 * (y * width + x)] = 255;
339 }
340#if DEBUG_DUMP
341 OOLog(@"planetTex.dump", [NSString stringWithFormat:@"Saving generated texture to file planet-%u-%u-old.", sNoiseSeed.high, sNoiseSeed.low]);
342
343 [[UNIVERSE gameView] dumpRGBAToFileNamed:[NSString stringWithFormat:@"planet-%u-%u-old", sNoiseSeed.high, sNoiseSeed.low]
344 bytes:imageBuffer
345 width:width
346 height:width
347 rowBytes:width * 4];
348#endif
349}
350
351#endif // !NEW_PLANETS
#define OOLog(class, format,...)
Definition OOLogging.h:88
return nil
float y
float x
static RANROTSeed sNoiseSeed
static FloatRGB PlanetTextureColor(float q, float impress, float bias, FloatRGB seaColor, FloatRGB paleSeaColor, FloatRGB landColor, FloatRGB paleLandColor)
static float ranNoiseBuffer[128 *128]
static FloatRGB FloatRGBFromDictColor(NSDictionary *dictionary, NSString *key)
static float q_factor(float *accbuffer, int x, int y, int width, BOOL polar_y_smooth, float polar_y_value, BOOL polar_x_smooth, float polar_x_value, float impress, float bias)
static void fillSquareImageDataWithCloudTexture(unsigned char *imageBuffer, int width, OOColor *cloudcolor, float impress, float bias)
static FloatRGB Blend(float fraction, FloatRGB a, FloatRGB b)
static void fillSquareImageWithPlanetTex(unsigned char *imageBuffer, int width, float impress, float bias, FloatRGB seaColor, FloatRGB paleSeaColor, FloatRGB landColor, FloatRGB paleLandColor)
static void addNoise(float *buffer, int p, int n, float scale)
#define PROC_TEXTURE_SIZE
void fillRanNoiseBuffer()
static NSString *const kOOLogPlanetTextureGen
float alphaComponent()
Definition OOColor.m:486
float blueComponent()
Definition OOColor.m:362
OOColor * colorWithDescription:(id description)
Definition OOColor.m:127
float redComponent()
Definition OOColor.m:350
float greenComponent()
Definition OOColor.m:356
float randf(void)
RANROTSeed RANROTGetFullSeed(void)
uint32_t low
uint32_t high