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