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