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