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