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