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