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