]> git.xonotic.org Git - xonotic/xonotic.git/blob - misc/tools/fft-normalmap-to-heightmap.c
78e7e020f0f295f5cdedb4af98ee740437ad6f62
[xonotic/xonotic.git] / misc / tools / fft-normalmap-to-heightmap.c
1 /*
2  *  FFT based normalmap to heightmap converter
3  *  Copyright (C) 2010  Rudolf Polzer
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #undef C99
21 #if __STDC_VERSION__ >= 199901L
22 #define C99
23 #endif
24
25 #ifdef C99
26 #include <complex.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #include <fftw3.h>
35
36 #define TWO_PI (4*atan2(1,1) * 2)
37
38 void nmap_to_hmap(unsigned char *map, const unsigned char *refmap, int w, int h, double scale, double offset, const double *filter, int filterw, int filterh, int renormalize)
39 {
40         int x, y;
41         int i, j;
42         double fx, fy;
43         double ffx, ffy;
44         double nx, ny, nz;
45         double v, vmin, vmax;
46 #ifndef C99
47         double save;
48 #endif
49
50         fftw_complex *imgspace1 = fftw_malloc(w*h * sizeof(fftw_complex));
51         fftw_complex *imgspace2 = fftw_malloc(w*h * sizeof(fftw_complex));
52         fftw_complex *freqspace1 = fftw_malloc(w*h * sizeof(fftw_complex));
53         fftw_complex *freqspace2 = fftw_malloc(w*h * sizeof(fftw_complex));
54         fftw_plan i12f1 = fftw_plan_dft_2d(h, w, imgspace1, freqspace1, FFTW_FORWARD, FFTW_ESTIMATE);
55         fftw_plan i22f2 = fftw_plan_dft_2d(h, w, imgspace2, freqspace2, FFTW_FORWARD, FFTW_ESTIMATE);
56         fftw_plan f12i1 = fftw_plan_dft_2d(h, w, freqspace1, imgspace1, FFTW_BACKWARD, FFTW_ESTIMATE);
57
58         for(y = 0; y < h; ++y)
59         for(x = 0; x < w; ++x)
60         {
61                 /*
62                  * unnormalized normals:
63                  * n_x = -dh/dx
64                  * n_y = -dh/dy
65                  * n_z = -dh/dh = -1
66                  * BUT: darkplaces uses inverted normals, n_y actually is dh/dy by image pixel coordinates
67                  */
68                 nx = ((int)map[(w*y+x)*4+2] - 127.5) / 128;
69                 ny = ((int)map[(w*y+x)*4+1] - 127.5) / 128;
70                 nz = ((int)map[(w*y+x)*4+0] - 127.5) / 128;
71
72                 /* reconstruct the derivatives from here */
73 #ifdef C99
74                 imgspace1[(w*y+x)] =  nx / nz * w; /* = dz/dx */
75                 imgspace2[(w*y+x)] = -ny / nz * h; /* = dz/dy */
76 #else
77                 imgspace1[(w*y+x)][0] =  nx / nz * w; /* = dz/dx */
78                 imgspace1[(w*y+x)][1] = 0;
79                 imgspace2[(w*y+x)][0] = -ny / nz * h; /* = dz/dy */
80                 imgspace2[(w*y+x)][1] = 0;
81 #endif
82
83                 if(renormalize)
84                 {
85                         double v = nx * nx + ny * ny + nz * nz;
86                         if(v > 0)
87                         {
88                                 v = sqrt(v);
89                                 nx /= v;
90                                 ny /= v;
91                                 nz /= v;
92                                 map[(w*y+x)*4+2] = floor(nx * 127.5 + 128);
93                                 map[(w*y+x)*4+1] = floor(ny * 127.5 + 128);
94                                 map[(w*y+x)*4+0] = floor(nz * 127.5 + 128);
95                         }
96                 }
97         }
98
99         /* see http://www.gamedev.net/community/forums/topic.asp?topic_id=561430 */
100
101         fftw_execute(i12f1);
102         fftw_execute(i22f2);
103         
104         for(y = 0; y < h; ++y)
105         for(x = 0; x < w; ++x)
106         {
107                 fx = x * 1.0 / w;
108                 fy = y * 1.0 / h;
109                 if(filter)
110                 {
111                         // discontinous case
112                         // we must invert whatever "filter" would do on (x, y)!
113 #ifdef C99
114                         fftw_complex response_x = 0;
115                         fftw_complex response_y = 0;
116                         double sum;
117                         for(i = -filterh / 2; i <= filterh / 2; ++i)
118                                 for(j = -filterw / 2; j <= filterw / 2; ++j)
119                                 {
120                                         response_x += filter[(i + filterh / 2) * filterw + j + filterw / 2] * cexp(-_Complex_I * TWO_PI * (j * fx + i * fy));
121                                         response_y += filter[(i + filterh / 2) * filterw + j + filterw / 2] * cexp(-_Complex_I * TWO_PI * (i * fx + j * fy));
122                                 }
123
124                         // we know:
125                         //   fourier(df/dx)_xy = fourier(f)_xy * response_x
126                         //   fourier(df/dy)_xy = fourier(f)_xy * response_y
127                         // mult by conjugate of response_x, response_y:
128                         //   conj(response_x) * fourier(df/dx)_xy = fourier(f)_xy * |response_x^2|
129                         //   conj(response_y) * fourier(df/dy)_xy = fourier(f)_xy * |response_y^2|
130                         // and
131                         //   fourier(f)_xy = (conj(response_x) * fourier(df/dx)_xy + conj(response_y) * fourier(df/dy)_xy) / (|response_x|^2 + |response_y|^2)
132
133                         sum = cabs(response_x) * cabs(response_x) + cabs(response_y) * cabs(response_y);
134
135                         if(sum > 0)
136                                 freqspace1[(w*y+x)] = (conj(response_x) * freqspace1[(w*y+x)] + conj(response_y) * freqspace2[(w*y+x)]) / sum;
137                         else
138                                 freqspace1[(w*y+x)] = 0;
139 #else
140                         fftw_complex response_x = {0, 0};
141                         fftw_complex response_y = {0, 0};
142                         double sum;
143                         for(i = -filterh / 2; i <= filterh / 2; ++i)
144                                 for(j = -filterw / 2; j <= filterw / 2; ++j)
145                                 {
146                                         response_x[0] += filter[(i + filterh / 2) * filterw + j + filterw / 2] * cos(-TWO_PI * (j * fx + i * fy));
147                                         response_x[1] += filter[(i + filterh / 2) * filterw + j + filterw / 2] * sin(-TWO_PI * (j * fx + i * fy));
148                                         response_y[0] += filter[(i + filterh / 2) * filterw + j + filterw / 2] * cos(-TWO_PI * (i * fx + j * fy));
149                                         response_y[1] += filter[(i + filterh / 2) * filterw + j + filterw / 2] * sin(-TWO_PI * (i * fx + j * fy));
150                                 }
151
152                         sum = response_x[0] * response_x[0] + response_x[1] * response_x[1]
153                             + response_y[0] * response_y[0] + response_y[1] * response_y[1];
154
155                         if(sum > 0)
156                         {
157                                 double s = freqspace1[(w*y+x)][0];
158                                 freqspace1[(w*y+x)][0] = (response_x[0] * s                      + response_x[1] * freqspace1[(w*y+x)][1] + response_y[0] * freqspace2[(w*y+x)][0] + response_y[1] * freqspace2[(w*y+x)][1]) / sum;
159                                 freqspace1[(w*y+x)][1] = (response_x[0] * freqspace1[(w*y+x)][1] - response_x[1] * s                      + response_y[0] * freqspace2[(w*y+x)][1] - response_y[1] * freqspace2[(w*y+x)][0]) / sum;
160                         }
161                         else
162                         {
163                                 freqspace1[(w*y+x)][0] = 0;
164                                 freqspace1[(w*y+x)][1] = 0;
165                         }
166 #endif
167                 }
168                 else
169                 {
170                         // continuous integration case
171                         if(fx > 0.5)
172                                 fx -= 1;
173                         if(fy > 0.5)
174                                 fy -= 1;
175                         /* these must have the same sign as fx and fy (so ffx*fx + ffy*fy is nonzero), otherwise do not matter */
176                         /* it basically decides how artifacts are distributed */
177                         ffx = fx;
178                         ffy = fy;
179 #ifdef C99
180                         if(fx||fy)
181                                 freqspace1[(w*y+x)] = _Complex_I * (ffx * freqspace1[(w*y+x)] + ffy * freqspace2[(w*y+x)]) / (ffx*fx + ffy*fy) / TWO_PI;
182                         else
183                                 freqspace1[(w*y+x)] = 0;
184 #else
185                         if(fx||fy)
186                         {
187                                 save = freqspace1[(w*y+x)][0];
188                                 freqspace1[(w*y+x)][0] = -(ffx * freqspace1[(w*y+x)][1] + ffy * freqspace2[(w*y+x)][1]) / (ffx*fx + ffy*fy) / TWO_PI;
189                                 freqspace1[(w*y+x)][1] =  (ffx * save + ffy * freqspace2[(w*y+x)][0]) / (ffx*fx + ffy*fy) / TWO_PI;
190                         }
191                         else
192                         {
193                                 freqspace1[(w*y+x)][0] = 0;
194                                 freqspace1[(w*y+x)][1] = 0;
195                         }
196 #endif
197                 }
198         }
199
200         fftw_execute(f12i1);
201
202         /* renormalize, find min/max */
203         vmin = vmax = 0;
204         for(y = 0; y < h; ++y)
205         for(x = 0; x < w; ++x)
206         {
207 #ifdef C99
208                 v = creal(imgspace1[(w*y+x)] /= pow(w*h, 1.5));
209 #else
210                 v = (imgspace1[(w*y+x)][0] /= pow(w*h, 1.5));
211                 // imgspace1[(w*y+x)][1] /= pow(w*h, 1.5);
212                 // this value is never used
213 #endif
214                 if(v < vmin || (x == 0 && y == 0))
215                         vmin = v;
216                 if(v > vmax || (x == 0 && y == 0))
217                         vmax = v;
218         }
219
220         if(refmap)
221         {
222                 double f, a;
223                 double o, s;
224                 double sa, sfa, sffa, sfva, sva;
225                 double mi, ma;
226                 sa = sfa = sffa = sfva = sva = 0;
227                 mi = 1;
228                 ma = -1;
229                 for(y = 0; y < h; ++y)
230                 for(x = 0; x < w; ++x)
231                 {
232                         a = (int)refmap[(w*y+x)*4+3];
233                         v = (refmap[(w*y+x)*4+0]*0.114 + refmap[(w*y+x)*4+1]*0.587 + refmap[(w*y+x)*4+2]*0.299);
234                         v = (v - 128.0) / 127.0;
235 #ifdef C99
236                         f = creal(imgspace1[(w*y+x)]);
237 #else
238                         f = imgspace1[(w*y+x)][0];
239 #endif
240                         if(a <= 0)
241                                 continue;
242                         if(v < mi)
243                                 mi = v;
244                         if(v > ma)
245                                 ma = v;
246                         sa += a;
247                         sfa += f*a;
248                         sffa += f*f*a;
249                         sfva += f*v*a;
250                         sva += v*a;
251                 }
252                 if(mi < ma)
253                 {
254                         /* linear regression ftw */
255                         o = (sfa*sfva - sffa*sva) / (sfa*sfa-sa*sffa);
256                         s = (sfa*sva - sa*sfva) / (sfa*sfa-sa*sffa);
257                 }
258                 else /* all values of v are equal, so we cannot get scale; we can still get offset */
259                 {
260                         o = ((sva - sfa) / sa);
261                         s = 1;
262                 }
263
264                 /*
265                  * now apply user-given offset and scale to these values
266                  * (x * s + o) * scale + offset
267                  * x * s * scale + o * scale + offset
268                  */
269                 offset += o * scale;
270                 scale *= s;
271         }
272         else if(scale == 0)
273         {
274                 /*
275                  * map vmin to -1
276                  * map vmax to +1
277                  */
278                 scale = 2 / (vmax - vmin);
279                 offset = -(vmax + vmin) / (vmax - vmin);
280         }
281
282         printf("Min: %f\nAvg: %f\nMax: %f\nScale: %f\nOffset: %f\nScaled-Min: %f\nScaled-Avg: %f\nScaled-Max: %f\n", 
283                 vmin, 0.0, vmax, scale, offset, vmin * scale + offset, offset, vmax * scale + offset);
284
285         for(y = 0; y < h; ++y)
286         for(x = 0; x < w; ++x)
287         {
288 #ifdef C99
289                 v = creal(imgspace1[(w*y+x)]);
290 #else
291                 v = imgspace1[(w*y+x)][0];
292 #endif
293                 v = v * scale + offset;
294                 if(v < -1)
295                         v = -1;
296                 if(v > 1)
297                         v = 1;
298                 map[(w*y+x)*4+3] = floor(128.5 + 127 * v);
299         }
300
301         fftw_destroy_plan(i12f1);
302         fftw_destroy_plan(i22f2);
303         fftw_destroy_plan(f12i1);
304
305         fftw_free(freqspace2);
306         fftw_free(freqspace1);
307         fftw_free(imgspace2);
308         fftw_free(imgspace1);
309 }
310
311 void hmap_to_nmap(unsigned char *map, int w, int h, int src_chan, double scale)
312 {
313         int x, y;
314         double fx, fy;
315         double nx, ny, nz;
316         double v;
317 #ifndef C99
318         double save;
319 #endif
320
321         fftw_complex *imgspace1 = fftw_malloc(w*h * sizeof(fftw_complex));
322         fftw_complex *imgspace2 = fftw_malloc(w*h * sizeof(fftw_complex));
323         fftw_complex *freqspace1 = fftw_malloc(w*h * sizeof(fftw_complex));
324         fftw_complex *freqspace2 = fftw_malloc(w*h * sizeof(fftw_complex));
325         fftw_plan i12f1 = fftw_plan_dft_2d(h, w, imgspace1, freqspace1, FFTW_FORWARD, FFTW_ESTIMATE);
326         fftw_plan f12i1 = fftw_plan_dft_2d(h, w, freqspace1, imgspace1, FFTW_BACKWARD, FFTW_ESTIMATE);
327         fftw_plan f22i2 = fftw_plan_dft_2d(h, w, freqspace2, imgspace2, FFTW_BACKWARD, FFTW_ESTIMATE);
328
329         for(y = 0; y < h; ++y)
330         for(x = 0; x < w; ++x)
331         {
332                 switch(src_chan)
333                 {
334                         case 0:
335                         case 1:
336                         case 2:
337                         case 3:
338                                 v = map[(w*y+x)*4+src_chan];
339                                 break;
340                         case 4:
341                                 v = (map[(w*y+x)*4+0] + map[(w*y+x)*4+1] + map[(w*y+x)*4+2]) / 3;
342                                 break;
343                         default:
344                         case 5:
345                                 v = (map[(w*y+x)*4+0]*0.114 + map[(w*y+x)*4+1]*0.587 + map[(w*y+x)*4+2]*0.299);
346                                 break;
347                 }
348 #ifdef C99
349                 imgspace1[(w*y+x)] = (v - 128.0) / 127.0;
350 #else
351                 imgspace1[(w*y+x)][0] = (v - 128.0) / 127.0;
352                 imgspace1[(w*y+x)][1] = 0;
353 #endif
354                 if(v < 1)
355                         v = 1; /* do not write alpha zero */
356                 map[(w*y+x)*4+3] = floor(v + 0.5);
357         }
358
359         /* see http://www.gamedev.net/community/forums/topic.asp?topic_id=561430 */
360
361         fftw_execute(i12f1);
362         
363         for(y = 0; y < h; ++y)
364         for(x = 0; x < w; ++x)
365         {
366                 fx = x;
367                 fy = y;
368                 if(fx > w/2)
369                         fx -= w;
370                 if(fy > h/2)
371                         fy -= h;
372 #ifdef DISCONTINUOUS
373                 fx = sin(fx * TWO_PI / w);
374                 fy = sin(fy * TWO_PI / h);
375 #else
376 #ifdef C99
377                 /* a lowpass to prevent the worst */
378                 freqspace1[(w*y+x)] *= 1 - pow(abs(fx) / (double)(w/2), 1);
379                 freqspace1[(w*y+x)] *= 1 - pow(abs(fy) / (double)(h/2), 1);
380 #else
381                 /* a lowpass to prevent the worst */
382                 freqspace1[(w*y+x)][0] *= 1 - pow(abs(fx) / (double)(w/2), 1);
383                 freqspace1[(w*y+x)][1] *= 1 - pow(abs(fx) / (double)(w/2), 1);
384                 freqspace1[(w*y+x)][0] *= 1 - pow(abs(fy) / (double)(h/2), 1);
385                 freqspace1[(w*y+x)][1] *= 1 - pow(abs(fy) / (double)(h/2), 1);
386 #endif
387 #endif
388 #ifdef C99
389                 freqspace2[(w*y+x)] = TWO_PI*_Complex_I * fy * freqspace1[(w*y+x)]; /* y derivative */
390                 freqspace1[(w*y+x)] = TWO_PI*_Complex_I * fx * freqspace1[(w*y+x)]; /* x derivative */
391 #else
392                 freqspace2[(w*y+x)][0] = -TWO_PI * fy * freqspace1[(w*y+x)][1]; /* y derivative */
393                 freqspace2[(w*y+x)][1] =  TWO_PI * fy * freqspace1[(w*y+x)][0];
394                 save = freqspace1[(w*y+x)][0];
395                 freqspace1[(w*y+x)][0] = -TWO_PI * fx * freqspace1[(w*y+x)][1]; /* x derivative */
396                 freqspace1[(w*y+x)][1] =  TWO_PI * fx * save;
397 #endif
398         }
399
400         fftw_execute(f12i1);
401         fftw_execute(f22i2);
402
403         scale /= (w*h);
404
405         for(y = 0; y < h; ++y)
406         for(x = 0; x < w; ++x)
407         {
408 #ifdef C99
409                 nx = creal(imgspace1[(w*y+x)]);
410                 ny = creal(imgspace2[(w*y+x)]);
411 #else
412                 nx = imgspace1[(w*y+x)][0];
413                 ny = imgspace2[(w*y+x)][0];
414 #endif
415                 nx /= w;
416                 ny /= h;
417                 nz = -1 / scale;
418                 v = -sqrt(nx*nx + ny*ny + nz*nz);
419                 nx /= v;
420                 ny /= v;
421                 nz /= v;
422                 ny = -ny; /* DP inverted normals */
423                 map[(w*y+x)*4+2] = floor(128 + 127.5 * nx);
424                 map[(w*y+x)*4+1] = floor(128 + 127.5 * ny);
425                 map[(w*y+x)*4+0] = floor(128 + 127.5 * nz);
426         }
427
428         fftw_destroy_plan(i12f1);
429         fftw_destroy_plan(f12i1);
430         fftw_destroy_plan(f22i2);
431
432         fftw_free(freqspace2);
433         fftw_free(freqspace1);
434         fftw_free(imgspace2);
435         fftw_free(imgspace1);
436 }
437
438 void hmap_to_nmap_local(unsigned char *map, int w, int h, int src_chan, double scale, const double *filter, int filterw, int filterh)
439 {
440         int x, y;
441         double nx, ny, nz;
442         double v;
443         int i, j;
444         double *img_reduced = malloc(w*h * sizeof(double));
445
446         for(y = 0; y < h; ++y)
447         for(x = 0; x < w; ++x)
448         {
449                 switch(src_chan)
450                 {
451                         case 0:
452                         case 1:
453                         case 2:
454                         case 3:
455                                 v = map[(w*y+x)*4+src_chan];
456                                 break;
457                         case 4:
458                                 v = (map[(w*y+x)*4+0] + map[(w*y+x)*4+1] + map[(w*y+x)*4+2]) / 3;
459                                 break;
460                         default:
461                         case 5:
462                                 v = (map[(w*y+x)*4+0]*0.114 + map[(w*y+x)*4+1]*0.587 + map[(w*y+x)*4+2]*0.299);
463                                 break;
464                 }
465                 img_reduced[(w*y+x)] = (v - 128.0) / 127.0;
466                 if(v < 1)
467                         v = 1; /* do not write alpha zero */
468                 map[(w*y+x)*4+3] = floor(v + 0.5);
469         }
470
471         for(y = 0; y < h; ++y)
472         for(x = 0; x < w; ++x)
473         {
474                 nz = -1 / scale;
475                 nx = ny = 0;
476
477                 for(i = -filterh / 2; i <= filterh / 2; ++i)
478                         for(j = -filterw / 2; j <= filterw / 2; ++j)
479                         {
480                                 nx += img_reduced[w*((y+i+h)%h)+(x+j+w)%w] * filter[(i + filterh / 2) * filterw + j + filterw / 2];
481                                 ny += img_reduced[w*((y+j+h)%h)+(x+i+w)%w] * filter[(i + filterh / 2) * filterw + j + filterw / 2];
482                         }
483
484                 v = -sqrt(nx*nx + ny*ny + nz*nz);
485                 nx /= v;
486                 ny /= v;
487                 nz /= v;
488                 ny = -ny; /* DP inverted normals */
489                 map[(w*y+x)*4+2] = floor(128 + 127.5 * nx);
490                 map[(w*y+x)*4+1] = floor(128 + 127.5 * ny);
491                 map[(w*y+x)*4+0] = floor(128 + 127.5 * nz);
492         }
493
494         free(img_reduced);
495 }
496
497 unsigned char *FS_LoadFile(const char *fn, int *len)
498 {
499         unsigned char *buf = NULL;
500         int n;
501         FILE *f = fopen(fn, "rb");
502         *len = 0;
503         if(!f)
504                 return NULL;
505         for(;;)
506         {
507                 buf = realloc(buf, *len + 65536);
508                 if(!buf)
509                 {
510                         fclose(f);
511                         free(buf);
512                         *len = 0;
513                         return NULL;
514                 }
515                 n = fread(buf + *len, 1, 65536, f);
516                 if(n < 0)
517                 {
518                         fclose(f);
519                         free(buf);
520                         *len = 0;
521                         return NULL;
522                 }
523                 *len += n;
524                 if(n < 65536)
525                         break;
526         }
527         return buf;
528 }
529
530 int FS_WriteFile(const char *fn, unsigned char *data, int len)
531 {
532         FILE *f = fopen(fn, "wb");
533         if(!f)
534                 return 0;
535         if(fwrite(data, len, 1, f) != 1)
536         {
537                 fclose(f);
538                 return 0;
539         }
540         if(fclose(f))
541                 return 0;
542         return 1;
543 }
544
545 /* START stuff that originates from image.c in DarkPlaces */
546 int image_width, image_height;
547
548 typedef struct _TargaHeader
549 {
550         unsigned char   id_length, colormap_type, image_type;
551         unsigned short  colormap_index, colormap_length;
552         unsigned char   colormap_size;
553         unsigned short  x_origin, y_origin, width, height;
554         unsigned char   pixel_size, attributes;
555 }
556 TargaHeader;
557
558 void PrintTargaHeader(TargaHeader *t)
559 {
560         printf("TargaHeader:\nuint8 id_length = %i;\nuint8 colormap_type = %i;\nuint8 image_type = %i;\nuint16 colormap_index = %i;\nuint16 colormap_length = %i;\nuint8 colormap_size = %i;\nuint16 x_origin = %i;\nuint16 y_origin = %i;\nuint16 width = %i;\nuint16 height = %i;\nuint8 pixel_size = %i;\nuint8 attributes = %i;\n", t->id_length, t->colormap_type, t->image_type, t->colormap_index, t->colormap_length, t->colormap_size, t->x_origin, t->y_origin, t->width, t->height, t->pixel_size, t->attributes);
561 }
562
563 unsigned char *LoadTGA_BGRA (const unsigned char *f, int filesize)
564 {
565         int x, y, pix_inc, row_inci, runlen, alphabits;
566         unsigned char *image_buffer;
567         unsigned int *pixbufi;
568         const unsigned char *fin, *enddata;
569         TargaHeader targa_header;
570         unsigned int palettei[256];
571         union
572         {
573                 unsigned int i;
574                 unsigned char b[4];
575         }
576         bgra;
577
578         if (filesize < 19)
579                 return NULL;
580
581         enddata = f + filesize;
582
583         targa_header.id_length = f[0];
584         targa_header.colormap_type = f[1];
585         targa_header.image_type = f[2];
586
587         targa_header.colormap_index = f[3] + f[4] * 256;
588         targa_header.colormap_length = f[5] + f[6] * 256;
589         targa_header.colormap_size = f[7];
590         targa_header.x_origin = f[8] + f[9] * 256;
591         targa_header.y_origin = f[10] + f[11] * 256;
592         targa_header.width = image_width = f[12] + f[13] * 256;
593         targa_header.height = image_height = f[14] + f[15] * 256;
594         targa_header.pixel_size = f[16];
595         targa_header.attributes = f[17];
596
597         if (image_width > 32768 || image_height > 32768 || image_width <= 0 || image_height <= 0)
598         {
599                 printf("LoadTGA: invalid size\n");
600                 PrintTargaHeader(&targa_header);
601                 return NULL;
602         }
603
604         /* advance to end of header */
605         fin = f + 18;
606
607         /* skip TARGA image comment (usually 0 bytes) */
608         fin += targa_header.id_length;
609
610         /* read/skip the colormap if present (note: according to the TARGA spec it */
611         /* can be present even on 1color or greyscale images, just not used by */
612         /* the image data) */
613         if (targa_header.colormap_type)
614         {
615                 if (targa_header.colormap_length > 256)
616                 {
617                         printf("LoadTGA: only up to 256 colormap_length supported\n");
618                         PrintTargaHeader(&targa_header);
619                         return NULL;
620                 }
621                 if (targa_header.colormap_index)
622                 {
623                         printf("LoadTGA: colormap_index not supported\n");
624                         PrintTargaHeader(&targa_header);
625                         return NULL;
626                 }
627                 if (targa_header.colormap_size == 24)
628                 {
629                         for (x = 0;x < targa_header.colormap_length;x++)
630                         {
631                                 bgra.b[0] = *fin++;
632                                 bgra.b[1] = *fin++;
633                                 bgra.b[2] = *fin++;
634                                 bgra.b[3] = 255;
635                                 palettei[x] = bgra.i;
636                         }
637                 }
638                 else if (targa_header.colormap_size == 32)
639                 {
640                         memcpy(palettei, fin, targa_header.colormap_length*4);
641                         fin += targa_header.colormap_length * 4;
642                 }
643                 else
644                 {
645                         printf("LoadTGA: Only 32 and 24 bit colormap_size supported\n");
646                         PrintTargaHeader(&targa_header);
647                         return NULL;
648                 }
649         }
650
651         /* check our pixel_size restrictions according to image_type */
652         switch (targa_header.image_type & ~8)
653         {
654         case 2:
655                 if (targa_header.pixel_size != 24 && targa_header.pixel_size != 32)
656                 {
657                         printf("LoadTGA: only 24bit and 32bit pixel sizes supported for type 2 and type 10 images\n");
658                         PrintTargaHeader(&targa_header);
659                         return NULL;
660                 }
661                 break;
662         case 3:
663                 /* set up a palette to make the loader easier */
664                 for (x = 0;x < 256;x++)
665                 {
666                         bgra.b[0] = bgra.b[1] = bgra.b[2] = x;
667                         bgra.b[3] = 255;
668                         palettei[x] = bgra.i;
669                 }
670                 /* fall through to colormap case */
671         case 1:
672                 if (targa_header.pixel_size != 8)
673                 {
674                         printf("LoadTGA: only 8bit pixel size for type 1, 3, 9, and 11 images supported\n");
675                         PrintTargaHeader(&targa_header);
676                         return NULL;
677                 }
678                 break;
679         default:
680                 printf("LoadTGA: Only type 1, 2, 3, 9, 10, and 11 targa RGB images supported, image_type = %i\n", targa_header.image_type);
681                 PrintTargaHeader(&targa_header);
682                 return NULL;
683         }
684
685         if (targa_header.attributes & 0x10)
686         {
687                 printf("LoadTGA: origin must be in top left or bottom left, top right and bottom right are not supported\n");
688                 return NULL;
689         }
690
691         /* number of attribute bits per pixel, we only support 0 or 8 */
692         alphabits = targa_header.attributes & 0x0F;
693         if (alphabits != 8 && alphabits != 0)
694         {
695                 printf("LoadTGA: only 0 or 8 attribute (alpha) bits supported\n");
696                 return NULL;
697         }
698
699         image_buffer = (unsigned char *)malloc(image_width * image_height * 4);
700         if (!image_buffer)
701         {
702                 printf("LoadTGA: not enough memory for %i by %i image\n", image_width, image_height);
703                 return NULL;
704         }
705
706         /* If bit 5 of attributes isn't set, the image has been stored from bottom to top */
707         if ((targa_header.attributes & 0x20) == 0)
708         {
709                 pixbufi = (unsigned int*)image_buffer + (image_height - 1)*image_width;
710                 row_inci = -image_width*2;
711         }
712         else
713         {
714                 pixbufi = (unsigned int*)image_buffer;
715                 row_inci = 0;
716         }
717
718         x = 0;
719         y = 0;
720         pix_inc = 1;
721         if ((targa_header.image_type & ~8) == 2)
722                 pix_inc = (targa_header.pixel_size + 7) / 8;
723         switch (targa_header.image_type)
724         {
725         case 1: /* colormapped, uncompressed */
726         case 3: /* greyscale, uncompressed */
727                 if (fin + image_width * image_height * pix_inc > enddata)
728                         break;
729                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
730                         for (x = 0;x < image_width;x++)
731                                 *pixbufi++ = palettei[*fin++];
732                 break;
733         case 2:
734                 /* BGR or BGRA, uncompressed */
735                 if (fin + image_width * image_height * pix_inc > enddata)
736                         break;
737                 if (targa_header.pixel_size == 32 && alphabits)
738                 {
739                         for (y = 0;y < image_height;y++)
740                                 memcpy(pixbufi + y * (image_width + row_inci), fin + y * image_width * pix_inc, image_width*4);
741                 }
742                 else
743                 {
744                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
745                         {
746                                 for (x = 0;x < image_width;x++, fin += pix_inc)
747                                 {
748                                         bgra.b[0] = fin[0];
749                                         bgra.b[1] = fin[1];
750                                         bgra.b[2] = fin[2];
751                                         bgra.b[3] = 255;
752                                         *pixbufi++ = bgra.i;
753                                 }
754                         }
755                 }
756                 break;
757         case 9: /* colormapped, RLE */
758         case 11: /* greyscale, RLE */
759                 for (y = 0;y < image_height;y++, pixbufi += row_inci)
760                 {
761                         for (x = 0;x < image_width;)
762                         {
763                                 if (fin >= enddata)
764                                         break; /* error - truncated file */
765                                 runlen = *fin++;
766                                 if (runlen & 0x80)
767                                 {
768                                         /* RLE - all pixels the same color */
769                                         runlen += 1 - 0x80;
770                                         if (fin + pix_inc > enddata)
771                                                 break; /* error - truncated file */
772                                         if (x + runlen > image_width)
773                                                 break; /* error - line exceeds width */
774                                         bgra.i = palettei[*fin++];
775                                         for (;runlen--;x++)
776                                                 *pixbufi++ = bgra.i;
777                                 }
778                                 else
779                                 {
780                                         /* uncompressed - all pixels different color */
781                                         runlen++;
782                                         if (fin + pix_inc * runlen > enddata)
783                                                 break; /* error - truncated file */
784                                         if (x + runlen > image_width)
785                                                 break; /* error - line exceeds width */
786                                         for (;runlen--;x++)
787                                                 *pixbufi++ = palettei[*fin++];
788                                 }
789                         }
790
791                         if (x != image_width)
792                         {
793                                 /* pixbufi is useless now */
794                                 printf("LoadTGA: corrupt file\n");
795                                 break;
796                         }
797                 }
798                 break;
799         case 10:
800                 /* BGR or BGRA, RLE */
801                 if (targa_header.pixel_size == 32 && alphabits)
802                 {
803                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
804                         {
805                                 for (x = 0;x < image_width;)
806                                 {
807                                         if (fin >= enddata)
808                                                 break; /* error - truncated file */
809                                         runlen = *fin++;
810                                         if (runlen & 0x80)
811                                         {
812                                                 /* RLE - all pixels the same color */
813                                                 runlen += 1 - 0x80;
814                                                 if (fin + pix_inc > enddata)
815                                                         break; /* error - truncated file */
816                                                 if (x + runlen > image_width)
817                                                         break; /* error - line exceeds width */
818                                                 bgra.b[0] = fin[0];
819                                                 bgra.b[1] = fin[1];
820                                                 bgra.b[2] = fin[2];
821                                                 bgra.b[3] = fin[3];
822                                                 fin += pix_inc;
823                                                 for (;runlen--;x++)
824                                                         *pixbufi++ = bgra.i;
825                                         }
826                                         else
827                                         {
828                                                 /* uncompressed - all pixels different color */
829                                                 runlen++;
830                                                 if (fin + pix_inc * runlen > enddata)
831                                                         break; /* error - truncated file */
832                                                 if (x + runlen > image_width)
833                                                         break; /* error - line exceeds width */
834                                                 for (;runlen--;x++)
835                                                 {
836                                                         bgra.b[0] = fin[0];
837                                                         bgra.b[1] = fin[1];
838                                                         bgra.b[2] = fin[2];
839                                                         bgra.b[3] = fin[3];
840                                                         fin += pix_inc;
841                                                         *pixbufi++ = bgra.i;
842                                                 }
843                                         }
844                                 }
845
846                                 if (x != image_width)
847                                 {
848                                         /* pixbufi is useless now */
849                                         printf("LoadTGA: corrupt file\n");
850                                         break;
851                                 }
852                         }
853                 }
854                 else
855                 {
856                         for (y = 0;y < image_height;y++, pixbufi += row_inci)
857                         {
858                                 for (x = 0;x < image_width;)
859                                 {
860                                         if (fin >= enddata)
861                                                 break; /* error - truncated file */
862                                         runlen = *fin++;
863                                         if (runlen & 0x80)
864                                         {
865                                                 /* RLE - all pixels the same color */
866                                                 runlen += 1 - 0x80;
867                                                 if (fin + pix_inc > enddata)
868                                                         break; /* error - truncated file */
869                                                 if (x + runlen > image_width)
870                                                         break; /* error - line exceeds width */
871                                                 bgra.b[0] = fin[0];
872                                                 bgra.b[1] = fin[1];
873                                                 bgra.b[2] = fin[2];
874                                                 bgra.b[3] = 255;
875                                                 fin += pix_inc;
876                                                 for (;runlen--;x++)
877                                                         *pixbufi++ = bgra.i;
878                                         }
879                                         else
880                                         {
881                                                 /* uncompressed - all pixels different color */
882                                                 runlen++;
883                                                 if (fin + pix_inc * runlen > enddata)
884                                                         break; /* error - truncated file */
885                                                 if (x + runlen > image_width)
886                                                         break; /* error - line exceeds width */
887                                                 for (;runlen--;x++)
888                                                 {
889                                                         bgra.b[0] = fin[0];
890                                                         bgra.b[1] = fin[1];
891                                                         bgra.b[2] = fin[2];
892                                                         bgra.b[3] = 255;
893                                                         fin += pix_inc;
894                                                         *pixbufi++ = bgra.i;
895                                                 }
896                                         }
897                                 }
898
899                                 if (x != image_width)
900                                 {
901                                         /* pixbufi is useless now */
902                                         printf("LoadTGA: corrupt file\n");
903                                         break;
904                                 }
905                         }
906                 }
907                 break;
908         default:
909                 /* unknown image_type */
910                 break;
911         }
912
913         return image_buffer;
914 }
915
916 int Image_WriteTGABGRA (const char *filename, int width, int height, const unsigned char *data)
917 {
918         int y;
919         unsigned char *buffer, *out;
920         const unsigned char *in, *end;
921         int ret;
922
923         buffer = (unsigned char *)malloc(width*height*4 + 18);
924
925         memset (buffer, 0, 18);
926         buffer[2] = 2;          /* uncompressed type */
927         buffer[12] = (width >> 0) & 0xFF;
928         buffer[13] = (width >> 8) & 0xFF;
929         buffer[14] = (height >> 0) & 0xFF;
930         buffer[15] = (height >> 8) & 0xFF;
931
932         for (y = 3;y < width*height*4;y += 4)
933                 if (data[y] < 255)
934                         break;
935
936         if (y < width*height*4)
937         {
938                 /* save the alpha channel */
939                 buffer[16] = 32;        /* pixel size */
940                 buffer[17] = 8; /* 8 bits of alpha */
941
942                 /* flip upside down */
943                 out = buffer + 18;
944                 for (y = height - 1;y >= 0;y--)
945                 {
946                         memcpy(out, data + y * width * 4, width * 4);
947                         out += width*4;
948                 }
949         }
950         else
951         {
952                 /* save only the color channels */
953                 buffer[16] = 24;        /* pixel size */
954                 buffer[17] = 0; /* 8 bits of alpha */
955
956                 /* truncate bgra to bgr and flip upside down */
957                 out = buffer + 18;
958                 for (y = height - 1;y >= 0;y--)
959                 {
960                         in = data + y * width * 4;
961                         end = in + width * 4;
962                         for (;in < end;in += 4)
963                         {
964                                 *out++ = in[0];
965                                 *out++ = in[1];
966                                 *out++ = in[2];
967                         }
968                 }
969         }
970         ret = FS_WriteFile (filename, buffer, out - buffer);
971
972         free(buffer);
973
974         return ret;
975 }
976 /* START stuff that originates from image.c in DarkPlaces */
977
978 int usage(const char *me)
979 {
980         printf("Usage: %s <infile_norm.tga> <outfile_normandheight.tga> filtertype [<scale> [<offset> [<infile_ref.tga>]]] (get heightmap from normalmap)\n", me);
981         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -1 [<scale>] (read from B)\n", me);
982         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -2 [<scale>] (read from G)\n", me);
983         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -3 [<scale>] (read from R)\n", me);
984         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -4 [<scale>] (read from A)\n", me);
985         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -5 [<scale>] (read from (R+G+B)/3)\n", me);
986         printf("or:    %s <infile_height.tga> <outfile_normandheight.tga> filtertype -6 [<scale>] (read from Y)\n", me);
987         return 1;
988 }
989
990 static const double filter_scharr3[3][3] = {
991         {  -3/32.0, 0,  3/32.0 },
992         { -10/32.0, 0, 10/32.0 },
993         {  -3/32.0, 0,  3/32.0 }
994 };
995
996 static const double filter_prewitt3[3][3] = {
997         { -1/6.0, 0, 1/6.0 },
998         { -1/6.0, 0, 1/6.0 },
999         { -1/6.0, 0, 1/6.0 }
1000 };
1001
1002 // pathologic for inverting
1003 static const double filter_sobel3[3][3] = {
1004         { -1/8.0, 0, 1/8.0 },
1005         { -2/8.0, 0, 2/8.0 },
1006         { -1/8.0, 0, 1/8.0 }
1007 };
1008
1009 // pathologic for inverting
1010 static const double filter_sobel5[5][5] = {
1011         { -1/128.0,  -2/128.0, 0,  2/128.0, 1/128.0 },
1012         { -4/128.0,  -8/128.0, 0,  8/128.0, 4/128.0 },
1013         { -6/128.0, -12/128.0, 0, 12/128.0, 6/128.0 },
1014         { -4/128.0,  -8/128.0, 0,  8/128.0, 4/128.0 },
1015         { -1/128.0,  -2/128.0, 0,  2/128.0, 1/128.0 }
1016 };
1017
1018 // pathologic for inverting
1019 static const double filter_prewitt5[5][5] = {
1020         { -1/40.0, -2/40.0, 0, 2/40.0, 1/40.0 },
1021         { -1/40.0, -2/40.0, 0, 2/40.0, 1/40.0 },
1022         { -1/40.0, -2/40.0, 0, 2/40.0, 1/40.0 },
1023         { -1/40.0, -2/40.0, 0, 2/40.0, 1/40.0 },
1024         { -1/40.0, -2/40.0, 0, 2/40.0, 1/40.0 }
1025 };
1026
1027 static const double filter_trivial[1][3] = {
1028         { -0.5, 0, 0.5 }
1029 };
1030
1031 int main(int argc, char **argv)
1032 {
1033         const char *infile, *outfile, *reffile;
1034         double scale, offset;
1035         int nmaplen, w, h;
1036         int renormalize = 0;
1037         unsigned char *nmapdata, *nmap, *refmap;
1038         const char *filtertype;
1039         const double *filter = NULL;
1040         int filterw = 0, filterh = 0;
1041 #define USE_FILTER(f) \
1042         do \
1043         { \
1044                 filterw = sizeof(*(f)) / sizeof(**(f)); \
1045                 filterh = sizeof((f)) / sizeof(*(f)); \
1046                 filter = &(f)[0][0]; \
1047         } \
1048         while(0)
1049
1050         if(argc > 1)
1051                 infile = argv[1];
1052         else
1053                 return usage(*argv);
1054
1055         if(argc > 2)
1056                 outfile = argv[2];
1057         else
1058                 return usage(*argv);
1059         
1060         if(argc > 3)
1061                 filtertype = argv[3];
1062         else
1063                 return usage(*argv);
1064         
1065         if(argc > 4)
1066                 scale = atof(argv[4]);
1067         else
1068                 scale = 0;
1069
1070         if(argc > 5)
1071                 offset = atof(argv[5]);
1072         else
1073                 offset = (scale<0) ? 1 : 0;
1074
1075         if(argc > 6)
1076                 reffile = argv[6];
1077         else
1078                 reffile = NULL;
1079
1080         if(getenv("FFT_NORMALMAP_TO_HEIGHTMAP_RENORMALIZE"))
1081                 renormalize = atoi(getenv("FFT_NORMALMAP_TO_HEIGHTMAP_RENORMALIZE"));
1082
1083         nmapdata = FS_LoadFile(infile, &nmaplen);
1084         if(!nmapdata)
1085         {
1086                 printf("FS_LoadFile failed\n");
1087                 return 2;
1088         }
1089         nmap = LoadTGA_BGRA(nmapdata, nmaplen);
1090         free(nmapdata);
1091         if(!nmap)
1092         {
1093                 printf("LoadTGA_BGRA failed\n");
1094                 return 2;
1095         }
1096         w = image_width;
1097         h = image_height;
1098
1099         if(reffile)
1100         {
1101                 nmapdata = FS_LoadFile(reffile, &nmaplen);
1102                 if(!nmapdata)
1103                 {
1104                         printf("FS_LoadFile failed\n");
1105                         return 2;
1106                 }
1107                 refmap = LoadTGA_BGRA(nmapdata, nmaplen);
1108                 free(nmapdata);
1109                 if(!refmap)
1110                 {
1111                         printf("LoadTGA_BGRA failed\n");
1112                         return 2;
1113                 }
1114                 if(image_width != w || image_height != h)
1115                 {
1116                         printf("reference map must have same size as input normalmap\n");
1117                         return 2;
1118                 }
1119         }
1120         else
1121                 refmap = NULL;
1122
1123         if(!strcmp(filtertype, "trivial"))
1124                 USE_FILTER(filter_trivial);
1125         if(!strcmp(filtertype, "prewitt3"))
1126                 USE_FILTER(filter_prewitt3);
1127         if(!strcmp(filtertype, "scharr3"))
1128                 USE_FILTER(filter_scharr3);
1129         if(!strcmp(filtertype, "sobel3"))
1130                 USE_FILTER(filter_sobel3);
1131         if(!strcmp(filtertype, "prewitt5"))
1132                 USE_FILTER(filter_prewitt5);
1133         if(!strcmp(filtertype, "sobel5"))
1134                 USE_FILTER(filter_sobel5);
1135
1136         if(scale < 0)
1137         {
1138                 if(filter)
1139                         hmap_to_nmap_local(nmap, image_width, image_height, -scale-1, offset, filter, filterw, filterh);
1140                 else
1141                         hmap_to_nmap(nmap, image_width, image_height, -scale-1, offset);
1142         }
1143         else
1144                 nmap_to_hmap(nmap, refmap, image_width, image_height, scale, offset, filter, filterw, filterh, renormalize);
1145
1146         if(!Image_WriteTGABGRA(outfile, image_width, image_height, nmap))
1147         {
1148                 printf("Image_WriteTGABGRA failed\n");
1149                 free(nmap);
1150                 return 2;
1151         }
1152         free(nmap);
1153         return 0;
1154 }