]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/spherefunc2skybox.c
Merge branch 'master' into divVerent/crypto2
[xonotic/xonotic.git] / misc / tools / spherefunc2skybox.c
1 #include <stdio.h>
2 #include <err.h>
3 #include <stdint.h>
4 #include <math.h>
5 #include <string.h>
6 #include <stdlib.h>
7
8 double rnd()
9 {
10         return rand() / (RAND_MAX + 1.0);
11 }
12
13 typedef void (*mapfunc_t) (double x_in, double y_in, double *x_out, double *y_out, double *z_out);
14 typedef void (*colorfunc_t) (double x, double y, double z, double *r, double *g, double *b);
15
16 void color_test(double x, double y, double z, double *r, double *g, double *b)
17 {
18         // put in a nice function here
19         *r = 0.5 + 0.5 * x;
20         *g = 0.5 + 0.5 * y;
21         *b = 0.5 + 0.5 * z;
22 }
23
24 double mandelbrot_iter(double zx, double zy, double cx, double cy, int maxiter)
25 {
26         double tmp;
27         int i;
28
29         double f, fprev;
30
31         f = 0;
32
33         for(i = 1; i < maxiter; ++i)
34         {
35                 tmp = zx;
36                 zx = zx * zx - zy * zy + cx;
37                 zy = 2 * tmp * zy + cy;
38                 fprev = f;
39                 f = zx * zx + zy * zy;
40                 if(f > 4)
41                         break;
42         }
43
44         if(i >= maxiter)
45                 return i;
46         else
47         {
48                 // f: the greater, the more in 0 direction
49                 //    the smaller, the more in 1 direction
50                 // fprev:
51                 //    the greater, the more in 0 direction
52                 return i + 1 / (f - 4 + 1); // f = 16: + 0, f = 4: + 1
53         }
54         // i.e. 0 for i=1, 1 for i=maxiter
55 }
56
57 double mandelbrot_range(double zx, double zy, double cx, double cy, int maxiter, double offset)
58 {
59         double i = mandelbrot_iter(zx, zy, cx, cy, maxiter);
60         // map linearily 1/(offset + iter) so that:
61         //   0       -> 0
62         //   maxiter -> 1
63         // i.e. solve:
64         //   f(iter) = A/(offset + iter) + B
65         // that is:
66         //   f(0)       = A/offset + B = 0
67         //   f(maxiter) = A/(offset + maxiter) + B = 1
68         // -->
69         //   1/(1/(offset + maxiter) - 1/offset) = A
70         //   B =          1 + offset / maxiter
71         //   A = -offset (1 + offset / maxiter)
72         // -->
73         //   f(iter) = -offset (1 + offset / maxiter) / (offset + iter) + 1 + offset / maxiter
74         //           = -offset (1 + offset / maxiter) / (offset + iter) + 1 + offset / maxiter
75         //           = iter (offset + maxiter)   /   maxiter (offset + iter)
76         return (i * (offset + maxiter)) / ((i + offset) * maxiter);
77 }
78
79 double color_mandelbrot_parms[13];
80 double mandelbrot_miniter = -1;
81 #define MAXITER 8192
82
83 double iter_mandelbrot_raw(double x, double y, double z)
84 {
85         z -= color_mandelbrot_parms[6];
86         x /= fabs(z);
87         y /= fabs(z);
88
89         if(z > 0)
90                 return mandelbrot_range(color_mandelbrot_parms[4], color_mandelbrot_parms[5], color_mandelbrot_parms[0] + x * color_mandelbrot_parms[2], color_mandelbrot_parms[1] + y * color_mandelbrot_parms[3], MAXITER, color_mandelbrot_parms[9]);
91         else
92                 return 0;
93 }
94
95 void iter_mandelbrot_raw_initialize_min()
96 {
97         if(mandelbrot_miniter >= 0)
98                 return;
99         // randomly sample 256 points
100         // mandelbrot them
101         // set that as miniter
102         int i = 0;
103         double x, y, z;
104         mandelbrot_miniter = MAXITER;
105         for(i = 0; i < 8192; ++i)
106         {
107                 x = rnd() * 2 - 1;
108                 y = rnd() * 2 - 1;
109                 z = rnd() * 2 - 1;
110                 double f = sqrt(x*x + y*y + z*z);
111                 x /= f;
112                 y /= f;
113                 z /= f;
114                 double a = (z - color_mandelbrot_parms[6]) / (color_mandelbrot_parms[7] - color_mandelbrot_parms[6]);
115                 a = (a - color_mandelbrot_parms[8]) / (1 - color_mandelbrot_parms[8]);
116                 if(a < 1)
117                         continue;
118                 double iterations = iter_mandelbrot_raw(x, y, z);
119                 if(iterations == 0)
120                         continue;
121                 if(iterations < mandelbrot_miniter)
122                         mandelbrot_miniter = iterations;
123         }
124 }
125
126 void color_mandelbrot(double x, double y, double z, double *r, double *g, double *b)
127 {
128         iter_mandelbrot_raw_initialize_min();
129
130         double iterations = iter_mandelbrot_raw(x, y, z);
131         //printf("iter = %f\n", iterations);
132         double a = (z - color_mandelbrot_parms[6]) / (color_mandelbrot_parms[7] - color_mandelbrot_parms[6]);
133         a = (a - color_mandelbrot_parms[8]) / (1 - color_mandelbrot_parms[8]);
134         if(a < 0)
135                 a = 0;
136         if(a > 1)
137                 a = 1;
138         iterations = iterations * a + mandelbrot_miniter * (1-a);
139         *r = pow(iterations, color_mandelbrot_parms[10]);
140         *g = pow(iterations, color_mandelbrot_parms[11]);
141         *b = pow(iterations, color_mandelbrot_parms[12]);
142 }
143
144 struct
145 {
146         int n;
147         double darkness;
148         double power;
149         double density;
150 }
151 color_starfield_parms;
152 void color_starfield(double x, double y, double z, double *r, double *g, double *b)
153 {
154         static struct
155         {
156                 double x, y, z, e;
157                 double R, G, B, A;
158         } *starfield = NULL;
159         int i;
160         double f;
161
162         if(!starfield)
163         {
164                 fprintf(stderr, "Initializing starfield...\n");
165                 starfield = malloc(sizeof(*starfield) * color_starfield_parms.n);
166                 for(i = 0; i < color_starfield_parms.n; ++i)
167                 {
168                         double r;
169                         do
170                         {
171                                 starfield[i].x = rnd() * 2 - 1;
172                                 starfield[i].y = rnd() * 2 - 1;
173                                 starfield[i].z = rnd() * 2 - 1;
174                                 r = starfield[i].x * starfield[i].x
175                                   + starfield[i].y * starfield[i].y
176                                   + starfield[i].z * starfield[i].z;
177                         }
178                         while(r > 1);
179                         r = sqrt(r);
180                         starfield[i].x /= r;
181                         starfield[i].y /= r;
182                         starfield[i].z /= r;
183
184                         starfield[i].e = color_starfield_parms.density * pow(rnd(), -color_starfield_parms.power);
185
186                         starfield[i].R = rnd();
187                         starfield[i].G = rnd();
188                         starfield[i].B = rnd();
189                         f = starfield[i].R * 0.299 + starfield[i].G * 0.587 + starfield[i].B * 0.114;
190                         starfield[i].R /= f;
191                         starfield[i].G /= f;
192                         starfield[i].B /= f;
193                         starfield[i].A = rnd();
194                 }
195                 fprintf(stderr, "Done.\n");
196         }
197
198         *r = *g = *b = 0;
199         for(i = 0; i < color_starfield_parms.n; ++i)
200         {
201                 double dot = x * starfield[i].x + y * starfield[i].y + z * starfield[i].z;
202                 if(dot <= 0)
203                         continue;
204                 double f = pow(dot, starfield[i].e) * starfield[i].A;
205                 *r += starfield[i].R * f;
206                 *g += starfield[i].G * f;
207                 *b += starfield[i].B * f;
208         }
209         // make fit in 0..1
210         *r = *r / (color_starfield_parms.darkness + *r);
211         *g = *g / (color_starfield_parms.darkness + *g);
212         *b = *b / (color_starfield_parms.darkness + *b);
213 }
214
215 void map_back(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
216 {
217         *x_out = 2 * x_in - 1;
218         *y_out = +1;
219         *z_out = 1 - 2 * y_in;
220 }
221
222 void map_right(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
223 {
224         *x_out = +1;
225         *y_out = 1 - 2 * x_in;
226         *z_out = 1 - 2 * y_in;
227 }
228
229 void map_front(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
230 {
231         *x_out = 1 - 2 * x_in;
232         *y_out = -1;
233         *z_out = 1 - 2 * y_in;
234 }
235
236 void map_left(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
237 {
238         *x_out = -1;
239         *y_out = 2 * x_in - 1;
240         *z_out = 1 - 2 * y_in;
241 }
242
243 void map_up(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
244 {
245         *x_out = 2 * y_in - 1;
246         *y_out = 1 - 2 * x_in;
247         *z_out = +1;
248 }
249
250 void map_down(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
251 {
252         *x_out = 1 - 2 * y_in;
253         *y_out = 1 - 2 * x_in;
254         *z_out = -1;
255 }
256
257 void writepic(colorfunc_t f, mapfunc_t m, const char *fn, int width, int height)
258 {
259         int x, y;
260         uint8_t tga[18];
261         int percent, p;
262
263         FILE *file = fopen(fn, "wb");
264         if(!file)
265                 err(1, "fopen %s", fn);
266
267         memset(tga, 0, sizeof(tga));
268         tga[2] = 2;          // uncompressed type
269         tga[12] = (width >> 0) & 0xFF;
270         tga[13] = (width >> 8) & 0xFF;
271         tga[14] = (height >> 0) & 0xFF;
272         tga[15] = (height >> 8) & 0xFF;
273         tga[16] = 24;        // pixel size
274
275         fwrite(&tga, sizeof(tga), 1, file);
276         percent = 0;
277         for(y = height-1; y >= 0; --y)
278         {
279                 for(x = 0; x < width; ++x)
280                 {
281                         uint8_t rgb[3];
282                         double rr, gg, bb;
283                         double xx, yy;
284                         double xxx, yyy, zzz;
285                         double r;
286                         xx = (x + 0.5) / width;
287                         yy = (y + 0.5) / height;
288                         m(xx, yy, &xxx, &yyy, &zzz);
289                         r = sqrt(xxx*xxx + yyy*yyy + zzz*zzz);
290                         xxx /= r;
291                         yyy /= r;
292                         zzz /= r;
293                         f(xxx, yyy, zzz, &rr, &gg, &bb);
294                         rgb[2] = floor(rnd() + rr * 255);
295                         rgb[1] = floor(rnd() + gg * 255);
296                         rgb[0] = floor(rnd() + bb * 255);
297                         fwrite(rgb, sizeof(rgb), 1, file);
298                 }
299                 p = (100 * (height - y)) / height;
300                 if(p != percent)
301                 {
302                         percent = p;
303                         fprintf(stderr, "%d%%\r", percent);
304                 }
305         }
306         fprintf(stderr, "\n");
307         
308         fclose(file);
309 }
310
311 void map_all(const char *fn, colorfunc_t f, int width, int height)
312 {
313         char buf[1024];
314         fprintf(stderr, "%s_bk.tga\n", fn);
315         snprintf(buf, sizeof(buf), "%s_bk.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_back, buf, width, height);
316         fprintf(stderr, "%s_ft.tga\n", fn);
317         snprintf(buf, sizeof(buf), "%s_ft.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_front, buf, width, height);
318         fprintf(stderr, "%s_rt.tga\n", fn);
319         snprintf(buf, sizeof(buf), "%s_rt.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_right, buf, width, height);
320         fprintf(stderr, "%s_lf.tga\n", fn);
321         snprintf(buf, sizeof(buf), "%s_lf.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_left, buf, width, height);
322         fprintf(stderr, "%s_up.tga\n", fn);
323         snprintf(buf, sizeof(buf), "%s_up.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_up, buf, width, height);
324         fprintf(stderr, "%s_dn.tga\n", fn);
325         snprintf(buf, sizeof(buf), "%s_dn.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_down, buf, width, height);
326 }
327
328 int main(int argc, char **argv)
329 {
330         colorfunc_t f;
331         if(argc < 4)
332                 errx(1, "usage: %s filename res func parms...", *argv);
333         int res = atoi(argv[2]);
334         if(!strcmp(argv[3], "mandel"))
335         {
336                 f = color_mandelbrot;
337                 color_mandelbrot_parms[0]  = argc<= 4 ?  -0.740 :  atof(argv[4]); // shift xy
338                 color_mandelbrot_parms[1]  = argc<= 5 ?  -0.314 :  atof(argv[5]);
339                 color_mandelbrot_parms[2]  = argc<= 6 ?  -0.003 :  atof(argv[6]); // mul xy
340                 color_mandelbrot_parms[3]  = argc<= 7 ?  -0.003 :  atof(argv[7]);
341                 color_mandelbrot_parms[4]  = argc<= 8 ?   0.420 :  atof(argv[8]); // shift z
342                 color_mandelbrot_parms[5]  = argc<= 9 ?   0.000 :  atof(argv[9]);
343                 color_mandelbrot_parms[6]  = argc<=10 ?  -0.8   : atof(argv[10]); // horizon
344                 color_mandelbrot_parms[7]  = argc<=11 ?  -0.7   : atof(argv[11]);
345                 color_mandelbrot_parms[8]  = argc<=12 ?   0.5   : atof(argv[12]);
346                 color_mandelbrot_parms[9]  = argc<=13 ? 400     : atof(argv[13]); // coloring
347                 color_mandelbrot_parms[10] = argc<=14 ?   0.6   : atof(argv[14]);
348                 color_mandelbrot_parms[11] = argc<=15 ?   0.5   : atof(argv[15]);
349                 color_mandelbrot_parms[12] = argc<=16 ?   0.2   : atof(argv[16]);
350         }
351         else if(!strcmp(argv[3], "starfield"))
352         {
353                 f = color_starfield;
354                 color_starfield_parms.n = argc<= 4 ? 8192 : atoi(argv[4]);
355                 color_starfield_parms.darkness = argc<= 5 ? 0.4 : atof(argv[5]);
356                 color_starfield_parms.power = argc<= 6 ? 2.5 : atof(argv[6]);
357                 color_starfield_parms.density = argc<= 7 ? 60000 : atof(argv[7]);
358         }
359         else
360         {
361                 f = color_test;
362         }
363         map_all(argv[1], f, res, res);
364         return 0;
365 }