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