1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     Tga.cpp
4 
5   Copyright (C)2009-2012 Nintendo Co., Ltd.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Rev: 46365 $
14  *---------------------------------------------------------------------------*/
15 
16 /*
17  *------------------------------------------------------------
18  * Copyright(c) 2009-2010 by Digital Media Professionals Inc.
19  * All rights reserved.
20  *------------------------------------------------------------
21  * This source code is the confidential and proprietary
22  * of Digital Media Professionals Inc.
23  *------------------------------------------------------------
24  */
25 #include <string.h>
26 #include <cstdlib>
27 #include "Tga.h"
28 #include "Memory.h"
29 
30 #define _TGA_HEADER_SIZE    18
31 
32 /*
33  * TGA image header
34  */
35 typedef struct {
36     unsigned char   id_len;
37     unsigned char   colormap_type;
38     unsigned char   image_type;
39     unsigned char   padding0;
40 
41     unsigned short  colormap_first;
42     unsigned short  colormap_len;
43     unsigned char   colormap_entry;
44     unsigned char   padding1;
45 
46     unsigned short  x, y;
47     unsigned short  width, height;
48     unsigned char   depth;
49     unsigned char   descriptor;
50 
51     /* */
52 
53     unsigned int    bpp;
54 } _TGA_HEADER;
55 
_setTGAHeader(unsigned char data[_TGA_HEADER_SIZE],_TGA_HEADER * tga)56 static void _setTGAHeader(
57     unsigned char data[_TGA_HEADER_SIZE],
58     _TGA_HEADER *tga)
59 {
60     tga->id_len         = data[0];
61     tga->colormap_type  = data[1];
62     tga->image_type     = data[2];
63 
64     tga->colormap_first = data[4] * 256 + data[3];
65     tga->colormap_len   = data[6] * 256 + data[5];
66     tga->colormap_entry = data[7];
67 
68     tga->x              = data[9] * 256 + data[8];
69     tga->y              = data[11] * 256 + data[10];
70     tga->width          = data[13] * 256 + data[12];
71     tga->height         = data[15] * 256 + data[14];
72     tga->depth          = data[16];
73     tga->descriptor     = data[17];
74 
75     tga->bpp = tga->depth / 8;
76 }
77 
78 #if 0
79 static void _getTGAHeader(
80     unsigned char data[_TGA_HEADER_SIZE],
81     _TGA_HEADER *tga)
82 {
83     data[0] = tga->id_len;
84     data[1] = tga->colormap_type;
85     data[2] = tga->image_type;
86 
87     data[3] = tga->colormap_first & 0xff;
88     data[4] = (tga->colormap_first & 0xff00) >> 8;
89     data[5] = tga->colormap_len & 0xff;
90     data[6] = (tga->colormap_len & 0xff00) >> 8;
91     data[7] = tga->colormap_entry;
92 
93     data[8] = tga->x & 0xff;
94     data[9] = (tga->x & 0xff00) >> 8;
95     data[10] = tga->y & 0xff;
96     data[11] = (tga->y & 0xff00) >> 8;
97     data[12] = tga->width & 0xff;
98     data[13] = (tga->width & 0xff00) >> 8;
99     data[14] = tga->height & 0xff;
100     data[15] = (tga->height & 0xff00) >> 8;
101     data[16] = tga->depth;
102     data[17] = tga->descriptor;
103 }
104 #endif
105 
_LoadTGAScanline(_TGA_HEADER * tga,unsigned char * dst,unsigned char * src)106 static unsigned int _LoadTGAScanline(
107     _TGA_HEADER *tga,
108     unsigned char *dst,
109     unsigned char *src)
110 {
111     int x;
112     unsigned int l;
113 
114     l = 0;
115     for(x = 0; x < tga->width; x++) {
116         if (tga->bpp == 3) {
117             dst[0] = src[2];
118             dst[1] = src[1];
119             dst[2] = src[0];
120         } else {
121             /* 32BIT */
122             dst[0] = src[2];
123             dst[1] = src[1];
124             dst[2] = src[0];
125             dst[3] = src[3];
126         }
127         src += tga->bpp;
128         dst += tga->bpp;
129         l += tga->bpp;
130     }
131 
132     return l;
133 }
134 
_LoadTGAScanlineRLE(_TGA_HEADER * tga,unsigned char * dst,unsigned char * src)135 static unsigned int _LoadTGAScanlineRLE(
136     _TGA_HEADER *tga,
137     unsigned char *dst,
138     unsigned char *src)
139 {
140     int x;
141     unsigned int l;
142     int errFlag;
143 
144 
145     l = 0;
146     x = 0;
147     errFlag = 0;
148     while(x < tga->width && !errFlag) {
149         int count = (*src & 0x7f) + 1;
150         if (*src & 0x80) {
151             int i;
152 
153             src++;
154             l++;
155             for(i = 0; i < count; i++) {
156                 if (x >= tga->width) {
157                     errFlag = 1;
158                     break;
159                 }
160                 if (tga->bpp == 3) {
161                     dst[0] = src[2];
162                     dst[1] = src[1];
163                     dst[2] = src[0];
164                 } else {
165                     /* 32BIT */
166                     dst[0] = src[2];
167                     dst[1] = src[1];
168                     dst[2] = src[0];
169                     dst[3] = src[3];
170                 }
171                 dst += tga->bpp;
172                 x++;
173             }
174             src += tga->bpp;
175             l += tga->bpp;
176         } else {
177             int i;
178 
179             src++;
180             l++;
181             for (i = 0; i < count; i++) {
182                 if (x >= tga->width) {
183                     errFlag = 1;
184                     break;
185                 }
186                 if (tga->bpp == 3) {
187                     dst[0] = src[2];
188                     dst[1] = src[1];
189                     dst[2] = src[0];
190                 } else {
191                     /* 32BIT */
192                     dst[0] = src[2];
193                     dst[1] = src[1];
194                     dst[2] = src[0];
195                     dst[3] = src[3];
196                 }
197                 src += tga->bpp;
198                 l += tga->bpp;
199                 dst += tga->bpp;
200                 x++;
201             }
202         }
203     }
204 
205     if (errFlag) {
206         return 0;
207     }
208 
209     return l;
210 }
211 
212 // Avoid compiler bugs
213 #pragma push
214 #pragma Ospace
dmpLoadTGA(const char * filename,unsigned int * width,unsigned int * height,unsigned int * format,unsigned int * type,unsigned int * orientation)215 void *dmpLoadTGA(
216     const char *filename,
217     unsigned int *width,
218     unsigned int *height,
219     unsigned int *format,
220     unsigned int *type,
221     unsigned int *orientation)
222 {
223     unsigned char *header = NULL;
224     unsigned char *pixels = NULL;
225     long long int filesize = 0;
226     _TGA_HEADER tga;
227     unsigned int _rle = 0;
228     unsigned int _upper = 0;
229     int y;
230     unsigned char *src, *srchead, *dst;
231     nn::fs::FileReader file;
232 
233     src = srchead = dst = NULL;
234 
235     /* Init */
236     if (width) {
237         *width = 0;     /* unknown */
238     }
239     if (height) {
240         *height = 0;    /* unknown */
241     }
242     if (format) {
243         *format = IMAGE_UNKNOWN;
244     }
245     if (type) {
246         *type = IMAGE_UNSIGNED_BYTE;
247     }
248     if (orientation) {
249         *orientation = IMAGE_LOWER_LEFT;
250     }
251 
252     /* open */
253     wchar_t* wfilename = static_cast<wchar_t*>(malloc( (strlen(filename)+1)*2 ));
254     (void)std::mbstowcs( wfilename, filename, strlen(filename)+1 );
255     file.Initialize(wfilename);
256 
257     filesize = file.GetSize();
258     if (filesize < _TGA_HEADER_SIZE) {
259         /* ERROR */
260         free(wfilename);
261         return NULL;
262     }
263 
264     header = static_cast<unsigned char*>(malloc(filesize));
265     file.Read(header, _TGA_HEADER_SIZE);
266 
267     _setTGAHeader(header, &tga);
268 
269     free(header);
270     free(wfilename);
271 
272     _upper = tga.descriptor & 0x20 ? 1 : 0;
273 
274     if (tga.depth == 24 && (tga.descriptor & 0x0f) == 0x00) {
275         /* 24BIT */
276     } else if (tga.depth == 32 && (tga.descriptor & 0x0f) == 0x08) {
277         /* 32BIT */
278     } else if (tga.depth == 32 && (tga.descriptor & 0x0f) == 0x00) {
279         /* 32BIT */
280     } else {
281         /* ERROR */
282         file.Finalize();
283         return NULL;
284     }
285 
286     if (tga.colormap_type == 0x00 && tga.image_type == 0x02) {
287         /* TRUE-COLOR IMAGE */
288         _rle = 0;
289     } else if (tga.colormap_type == 0x00 && tga.image_type == 0x0a) {
290         /* RLE TRUE-COLOR IMAGE */
291         _rle = 1;
292     } else {
293         /* ERROR */
294         file.Finalize();
295         return NULL;
296     }
297 
298 
299     if ((pixels = static_cast<unsigned char*>(malloc(tga.width * tga.height * tga.bpp))) == NULL) {
300         /* ERROR */
301         file.Finalize();
302         return NULL;
303     }
304 
305     if ((srchead = static_cast<unsigned char *>(malloc(filesize - _TGA_HEADER_SIZE))) == NULL)
306     {
307         file.Finalize();
308         return NULL;
309     }
310 
311     src = srchead;
312     file.Read(src, filesize - _TGA_HEADER_SIZE);
313     for(y = 0; y < tga.height; y++) {
314         unsigned int l;
315 
316         dst = pixels + tga.width * tga.bpp *
317                 (_upper ? tga.height - y - 1 : y);
318 
319         if (!_rle) {
320             if ((l = _LoadTGAScanline(&tga, dst, src)) == 0) {
321                 /* ERROR */
322                 file.Finalize();
323                 free(srchead);
324                 free(pixels);
325                 return NULL;
326             }
327         } else {
328             if ((l = _LoadTGAScanlineRLE(&tga, dst, src)) == 0) {
329                 /* ERROR */
330                 file.Finalize();
331                 free(srchead);
332                 free(pixels);
333                 return NULL;
334             }
335         }
336         src += l;
337     }
338 
339     file.Finalize();
340     free(srchead);
341 
342     if (width) {
343         *width = tga.width;
344     }
345     if (height) {
346         *height = tga.height;
347     }
348     if (format) {
349         if (tga.depth == 24) {
350             *format = IMAGE_RGB;
351         } else {
352             *format = IMAGE_RGBA;
353         }
354     }
355 
356     return (void *)pixels;
357 }
358 #pragma pop
359 
360 #if 0
361 static int _cmpPixel(
362     _TGA_HEADER *tga,
363     unsigned char *p1,
364     unsigned char *p2)
365 {
366     int cmp = 1;
367 
368     if (p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2]) {
369         if (tga->depth == 32) {
370             if (p1[3] == p2[3]) {
371                 cmp = 0;
372             }
373         } else {
374             cmp = 0;
375         }
376     }
377 
378     return cmp;
379 }
380 
381 static int _cmpLine(
382     _TGA_HEADER *tga,
383     unsigned char *data,
384     int maxSize,
385     int maxHit)
386 {
387     int i;
388     int count = 0;
389 
390     for(i = 1; i < maxSize; i++) {
391         if (!_cmpPixel(tga, data, data + tga->bpp * i)) {
392             count++;
393             if (count == maxHit) {
394                 break;
395             }
396         } else {
397             break;
398         }
399     }
400 
401     return count;
402 }
403 
404 static int _uncmpLine(
405     _TGA_HEADER *tga,
406     unsigned char *data,
407     int maxSize,
408     int maxHit)
409 {
410     int i;
411     int count = 0;
412 
413     for(i = 1; i < maxSize; i++) {
414         if (_cmpPixel(tga, data + tga->bpp * (i - 1), data + tga->bpp * i)) {
415             count++;
416             if (count > maxHit + 1) {
417                 break;
418             }
419         } else {
420             if (count - 1 >= 0) {
421                 count--;
422             }
423             break;
424         }
425     }
426 
427     if (count > maxHit) {
428         count = maxHit;
429     }
430 
431     return count;
432 }
433 
434 static unsigned int _SaveTGAScanlineRLE(
435     _TGA_HEADER *tga,
436     unsigned char *data,
437     unsigned char *fbuf)
438 {
439     /* fbuf is buffer to write file, return value is the incremented size. */
440     int x;
441     unsigned char *p1;
442     unsigned ret = 0;
443 
444     p1 = data;
445     x = 0;
446     while(x < tga->width) {
447         int mode;
448         int count;
449         unsigned char code;
450 
451         if (x == tga->width - 1) {
452             mode = 1;
453             count = 0;
454         } else {
455             mode = 0;
456             count = _cmpLine(tga, p1, tga->width - x, 127);
457 
458             if (count == 0) {
459                 mode = 1;
460                 count = _uncmpLine(tga, p1, tga->width - x, 127);
461             }
462         }
463 
464         code = (unsigned char)(count + (mode ? 0x00 : 0x80));
465         memcpy(&fbuf[ret], &code, 1);
466         ret += 1;
467 
468         if (!mode) {
469             memcpy(&fbuf[ret], p1, tga->bpp);
470             ret += tga->bpp;
471         } else {
472             memcpy(&fbuf[ret], p1, tga->bpp * (count + 1));
473             ret += tga->bpp * (count + 1);
474         }
475 
476         p1 += (count + 1) * tga->bpp;
477         x += count + 1;
478     }
479 
480     return ret;
481 }
482 #endif
483