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