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