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