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