]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/spherefunc2skybox.c
an attempt at a "starfield" skybox generator. Renders something entirely different...
[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 }
148 color_starfield_parms;
149 void color_starfield(double x, double y, double z, double *r, double *g, double *b)
150 {
151         static struct
152         {
153                 double x, y, z, e;
154                 double R, G, B, A;
155         } *starfield = NULL;
156         int i;
157
158         if(!starfield)
159         {
160                 fprintf(stderr, "Initializing starfield...\n");
161                 starfield = malloc(sizeof(*starfield) * color_starfield_parms.n);
162                 for(i = 0; i < color_starfield_parms.n; ++i)
163                 {
164                         double r;
165                         do
166                         {
167                                 starfield[i].x = rnd() * 2 - 1;
168                                 starfield[i].y = rnd() * 2 - 1;
169                                 starfield[i].z = rnd() * 2 - 1;
170                                 r = starfield[i].x * starfield[i].x
171                                   + starfield[i].y * starfield[i].y
172                                   + starfield[i].z * starfield[i].z;
173                         }
174                         while(r > 1);
175                         r = sqrt(r);
176                         starfield[i].x /= r;
177                         starfield[i].y /= r;
178                         starfield[i].z /= r;
179
180                         starfield[i].e = rnd() * 100 + 5;
181
182                         starfield[i].R = rnd();
183                         starfield[i].G = rnd();
184                         starfield[i].B = rnd();
185                         starfield[i].A = rnd();
186                 }
187                 fprintf(stderr, "Done.\n");
188         }
189
190         *r = *g = *b = 0;
191         for(i = 0; i < color_starfield_parms.n; ++i)
192         {
193                 double dot = x * starfield[i].x + y * starfield[i].y + z * starfield[i].z;
194                 if(dot <= 0)
195                         continue;
196                 double f = pow(dot, starfield[i].e) * starfield[i].A;
197                 *r += starfield[i].R * f;
198                 *g += starfield[i].G * f;
199                 *b += starfield[i].B * f;
200         }
201 }
202
203 void map_back(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
204 {
205         *x_out = 2 * x_in - 1;
206         *y_out = +1;
207         *z_out = 1 - 2 * y_in;
208 }
209
210 void map_right(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
211 {
212         *x_out = +1;
213         *y_out = 1 - 2 * x_in;
214         *z_out = 1 - 2 * y_in;
215 }
216
217 void map_front(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
218 {
219         *x_out = 1 - 2 * x_in;
220         *y_out = -1;
221         *z_out = 1 - 2 * y_in;
222 }
223
224 void map_left(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
225 {
226         *x_out = -1;
227         *y_out = 2 * x_in - 1;
228         *z_out = 1 - 2 * y_in;
229 }
230
231 void map_up(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
232 {
233         *x_out = 2 * y_in - 1;
234         *y_out = 1 - 2 * x_in;
235         *z_out = +1;
236 }
237
238 void map_down(double x_in, double y_in, double *x_out, double *y_out, double *z_out)
239 {
240         *x_out = 1 - 2 * y_in;
241         *y_out = 1 - 2 * x_in;
242         *z_out = -1;
243 }
244
245 void writepic(colorfunc_t f, mapfunc_t m, const char *fn, int width, int height)
246 {
247         int x, y;
248         uint8_t tga[18];
249
250         FILE *file = fopen(fn, "wb");
251         if(!file)
252                 err(1, "fopen %s", fn);
253
254         memset(tga, 0, sizeof(tga));
255         tga[2] = 2;          // uncompressed type
256         tga[12] = (width >> 0) & 0xFF;
257         tga[13] = (width >> 8) & 0xFF;
258         tga[14] = (height >> 0) & 0xFF;
259         tga[15] = (height >> 8) & 0xFF;
260         tga[16] = 24;        // pixel size
261
262         fwrite(&tga, sizeof(tga), 1, file);
263         for(y = height-1; y >= 0; --y)
264                 for(x = 0; x < width; ++x)
265                 {
266                         uint8_t rgb[3];
267                         double rr, gg, bb;
268                         double xx, yy;
269                         double xxx, yyy, zzz;
270                         double r;
271                         xx = (x + 0.5) / width;
272                         yy = (y + 0.5) / height;
273                         m(xx, yy, &xxx, &yyy, &zzz);
274                         r = sqrt(xxx*xxx + yyy*yyy + zzz*zzz);
275                         xxx /= r;
276                         yyy /= r;
277                         zzz /= r;
278                         f(xxx, yyy, zzz, &rr, &gg, &bb);
279                         rgb[2] = floor(rnd() + rr * 255);
280                         rgb[1] = floor(rnd() + gg * 255);
281                         rgb[0] = floor(rnd() + bb * 255);
282                         fwrite(rgb, sizeof(rgb), 1, file);
283                 }
284         
285         fclose(file);
286 }
287
288 void map_all(const char *fn, colorfunc_t f, int width, int height)
289 {
290         char buf[1024];
291         snprintf(buf, sizeof(buf), "%s_bk.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_back, buf, width, height);
292         snprintf(buf, sizeof(buf), "%s_ft.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_front, buf, width, height);
293         snprintf(buf, sizeof(buf), "%s_rt.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_right, buf, width, height);
294         snprintf(buf, sizeof(buf), "%s_lf.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_left, buf, width, height);
295         snprintf(buf, sizeof(buf), "%s_up.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_up, buf, width, height);
296         snprintf(buf, sizeof(buf), "%s_dn.tga", fn); buf[sizeof(buf) - 1] = 0; writepic(f, map_down, buf, width, height);
297 }
298
299 int main(int argc, char **argv)
300 {
301         colorfunc_t f;
302         if(argc < 4)
303                 errx(1, "usage: %s filename res func parms...", *argv);
304         int res = atoi(argv[2]);
305         if(!strcmp(argv[3], "mandel"))
306         {
307                 f = color_mandelbrot;
308                 color_mandelbrot_parms[0]  = argc<= 4 ?  -0.740 :  atof(argv[4]); // shift xy
309                 color_mandelbrot_parms[1]  = argc<= 5 ?  -0.314 :  atof(argv[5]);
310                 color_mandelbrot_parms[2]  = argc<= 6 ?  -0.003 :  atof(argv[6]); // mul xy
311                 color_mandelbrot_parms[3]  = argc<= 7 ?  -0.003 :  atof(argv[7]);
312                 color_mandelbrot_parms[4]  = argc<= 8 ?   0.420 :  atof(argv[8]); // shift z
313                 color_mandelbrot_parms[5]  = argc<= 9 ?   0.000 :  atof(argv[9]);
314                 color_mandelbrot_parms[6]  = argc<=10 ?  -0.8   : atof(argv[10]); // horizon
315                 color_mandelbrot_parms[7]  = argc<=11 ?  -0.7   : atof(argv[11]);
316                 color_mandelbrot_parms[8]  = argc<=12 ?   0.5   : atof(argv[12]);
317                 color_mandelbrot_parms[9]  = argc<=13 ? 400     : atof(argv[13]); // coloring
318                 color_mandelbrot_parms[10] = argc<=14 ?   0.6   : atof(argv[14]);
319                 color_mandelbrot_parms[11] = argc<=15 ?   0.5   : atof(argv[15]);
320                 color_mandelbrot_parms[12] = argc<=16 ?   0.2   : atof(argv[16]);
321         }
322         else if(!strcmp(argv[3], "starfield"))
323         {
324                 f = color_starfield;
325                 color_starfield_parms.n = argc<= 4 ? 1024 : atoi(argv[4]);
326         }
327         else
328         {
329                 f = color_test;
330         }
331         map_all(argv[1], f, res, res);
332         return 0;
333 }