1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: r_tex_tga.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "r_tex.h"
30
31 // MACROS ------------------------------------------------------------------
32
33 // TYPES -------------------------------------------------------------------
34
35 struct tgaHeader_t
36 {
37 vuint8 id_length;
38 vuint8 pal_type;
39 vuint8 img_type;
40 vuint16 first_colour;
41 vuint16 pal_colours;
42 vuint8 pal_entry_size;
43 vuint16 left;
44 vuint16 top;
45 vuint16 width;
46 vuint16 height;
47 vuint8 bpp;
48 vuint8 descriptor_bits;
49
operator <<(VStream & Strm,tgaHeader_t & h)50 friend VStream& operator<<(VStream& Strm, tgaHeader_t& h)
51 {
52 return Strm << h.id_length << h.pal_type << h.img_type
53 << h.first_colour << h.pal_colours << h.pal_entry_size << h.left
54 << h.top << h.width << h.height << h.bpp << h.descriptor_bits;
55 }
56 };
57
58 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
59
60 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
61
62 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
63
64 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
65
66 // PUBLIC DATA DEFINITIONS -------------------------------------------------
67
68 // PRIVATE DATA DEFINITIONS ------------------------------------------------
69
70 // CODE --------------------------------------------------------------------
71
72 //==========================================================================
73 //
74 // VTgaTexture::Create
75 //
76 //==========================================================================
77
Create(VStream & Strm,int LumpNum)78 VTexture* VTgaTexture::Create(VStream& Strm, int LumpNum)
79 {
80 guard(VTgaTexture::Create);
81 if (Strm.TotalSize() < 18)
82 {
83 // File is too small.
84 return NULL;
85 }
86
87 tgaHeader_t Hdr;
88 Strm.Seek(0);
89 Strm << Hdr;
90
91 if ((Hdr.pal_type != 0 && Hdr.pal_type != 1) || Hdr.width <= 0 ||
92 Hdr.height <= 0 || Hdr.width > 2048 || Hdr.height > 2048 ||
93 (Hdr.pal_type == 0 && Hdr.bpp != 15 && Hdr.bpp != 16 &&
94 Hdr.bpp != 24 && Hdr.bpp != 32) ||
95 (Hdr.pal_type == 1 && Hdr.bpp != 8) ||
96 (Hdr.pal_type == 0 && Hdr.img_type != 2 && Hdr.img_type != 10) ||
97 (Hdr.pal_type == 1 && Hdr.img_type != 1 && Hdr.img_type != 3 &&
98 Hdr.img_type != 9 && Hdr.img_type != 11) ||
99 (Hdr.pal_type == 1 && Hdr.pal_entry_size != 16 &&
100 Hdr.pal_entry_size != 24 && Hdr.pal_entry_size != 32) ||
101 (Hdr.descriptor_bits & 16) != 0)
102 {
103 return NULL;
104 }
105 return new VTgaTexture(LumpNum, Hdr);
106 unguard;
107 }
108
109 //==========================================================================
110 //
111 // VTgaTexture::VTgaTexture
112 //
113 //==========================================================================
114
VTgaTexture(int ALumpNum,tgaHeader_t & Hdr)115 VTgaTexture::VTgaTexture(int ALumpNum, tgaHeader_t& Hdr)
116 : Pixels(0)
117 , Palette(0)
118 {
119 SourceLump = ALumpNum;
120 Name = W_LumpName(SourceLump);
121 Width = Hdr.width;
122 Height = Hdr.height;
123 }
124
125 //==========================================================================
126 //
127 // VTgaTexture::~VTgaTexture
128 //
129 //==========================================================================
130
~VTgaTexture()131 VTgaTexture::~VTgaTexture()
132 {
133 guard(VTgaTexture::~VTgaTexture);
134 if (Pixels)
135 {
136 delete[] Pixels;
137 Pixels = NULL;
138 }
139 if (Palette)
140 {
141 delete[] Palette;
142 Palette = NULL;
143 }
144 unguard;
145 }
146
147 //==========================================================================
148 //
149 // VTgaTexture::GetPixels
150 //
151 //==========================================================================
152
GetPixels()153 vuint8* VTgaTexture::GetPixels()
154 {
155 guard(VTgaTexture::GetPixels);
156 // If we already have loaded pixels, return them.
157 if (Pixels)
158 {
159 return Pixels;
160 }
161
162 // Load texture.
163 int count;
164 int c;
165
166 VStream* Strm = W_CreateLumpReaderNum(SourceLump);
167 if (!Strm)
168 {
169 Sys_Error("Couldn't find file %s", *Name);
170 }
171
172 tgaHeader_t hdr;
173 *Strm << hdr;
174
175 Width = hdr.width;
176 Height = hdr.height;
177
178 Strm->Seek(Strm->Tell() + hdr.id_length);
179
180 if (hdr.pal_type == 1)
181 {
182 Palette = new rgba_t[256];
183 for (int i = 0; i < hdr.pal_colours; i++)
184 {
185 vuint16 col;
186 switch (hdr.pal_entry_size)
187 {
188 case 16:
189 *Strm << col;
190 Palette[i].r = (col & 0x1F) << 3;
191 Palette[i].g = ((col >> 5) & 0x1F) << 3;
192 Palette[i].b = ((col >> 10) & 0x1F) << 3;
193 Palette[i].a = 255;
194 break;
195 case 24:
196 *Strm << Palette[i].b
197 << Palette[i].g
198 << Palette[i].r;
199 Palette[i].a = 255;
200 break;
201 case 32:
202 *Strm << Palette[i].b
203 << Palette[i].g
204 << Palette[i].r
205 << Palette[i].a;
206 break;
207 }
208 }
209 }
210
211 /* Image type:
212 * 0 = no image data
213 * 1 = uncompressed colour mapped
214 * 2 = uncompressed true colour
215 * 3 = grayscale
216 * 9 = RLE colour mapped
217 * 10 = RLE true colour
218 * 11 = RLE grayscale
219 */
220
221 if (hdr.img_type == 1 || hdr.img_type == 3 ||
222 hdr.img_type == 9 || hdr.img_type == 11)
223 {
224 Format = TEXFMT_8Pal;
225 Pixels = new vuint8[Width * Height];
226 }
227 else
228 {
229 Format = TEXFMT_RGBA;
230 Pixels = new vuint8[Width * Height * 4];
231 }
232
233 if (hdr.img_type == 1 && hdr.bpp == 8 && hdr.pal_type == 1)
234 {
235 // 8-bit, uncompressed
236 for (int y = Height; y; y--)
237 {
238 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
239 vuint8* dst = Pixels + yc * Width;
240
241 Strm->Serialise(dst, Width);
242 }
243 }
244 else if (hdr.img_type == 2 && hdr.pal_type == 0 && hdr.bpp == 16)
245 {
246 // 16-bit uncompressed
247 for (int y = Height; y; y--)
248 {
249 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
250 rgba_t *dst = (rgba_t*)(Pixels + yc * Width * 4);
251
252 for (int x = 0; x < Width; x++, dst++)
253 {
254 vuint16 col;
255 *Strm << col;
256 dst->r = ((col >> 10) & 0x1F) << 3;
257 dst->g = ((col >> 5) & 0x1F) << 3;
258 dst->b = (col & 0x1F) << 3;
259 dst->a = 255;
260 }
261 }
262 }
263 else if (hdr.img_type == 2 && hdr.pal_type == 0 && hdr.bpp == 24)
264 {
265 // 24-bit uncompressed
266 for (int y = Height; y; y--)
267 {
268 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
269 rgba_t *dst = (rgba_t*)(Pixels + yc * Width * 4);
270
271 for (int x = 0; x < Width; x++, dst++)
272 {
273 *Strm << dst->b
274 << dst->g
275 << dst->r;
276 dst->a = 255;
277 }
278 }
279 }
280 else if (hdr.img_type == 2 && hdr.pal_type == 0 && hdr.bpp == 32)
281 {
282 // 32-bit uncompressed
283 for (int y = Height; y; y--)
284 {
285 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
286 rgba_t *dst = (rgba_t*)(Pixels + yc * Width * 4);
287
288 for (int x = 0; x < Width; x++, dst++)
289 {
290 *Strm << dst->b
291 << dst->g
292 << dst->r
293 << dst->a;
294 }
295 }
296 }
297 else if (hdr.img_type == 3 && hdr.bpp == 8 && hdr.pal_type == 1)
298 {
299 // Grayscale uncompressed
300 for (int i = 0; i < 256; i++)
301 {
302 Palette[i].r = i;
303 Palette[i].g = i;
304 Palette[i].b = i;
305 Palette[i].a = 255;
306 }
307 for (int y = Height; y; y--)
308 {
309 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
310 byte *dst = Pixels + yc * Width;
311
312 Strm->Serialise(dst, Width);
313 }
314 }
315 else if (hdr.img_type == 9 && hdr.bpp == 8 && hdr.pal_type == 1)
316 {
317 // 8-bit RLE compressed
318 for (int y = Height; y; y--)
319 {
320 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
321 vuint8* dst = Pixels + yc * Width;
322 c = 0;
323
324 do
325 {
326 count = Streamer<vuint8>(*Strm);
327 if (count & 0x80)
328 {
329 count = (count & 0x7F) + 1;
330 c += count;
331 vuint8 col;
332 *Strm << col;
333 while (count--)
334 *(dst++) = col;
335 }
336 else
337 {
338 count++;
339 c += count;
340 Strm->Serialise(dst, count);
341 dst += count;
342 }
343 }
344 while (c < Width);
345 }
346 }
347 else if (hdr.img_type == 10 && hdr.pal_type == 0 && hdr.bpp == 16)
348 {
349 // 16-bit RLE compressed
350 for (int y = Height; y; y--)
351 {
352 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
353 rgba_t *dst = (rgba_t*)(Pixels + yc * Width * 4);
354 c = 0;
355
356 do
357 {
358 count = Streamer<vuint8>(*Strm);
359 if (count & 0x80)
360 {
361 count = (count & 0x7F) + 1;
362 c += count;
363 vuint16 col;
364 *Strm << col;
365 while (count--)
366 {
367 dst->r = ((col >> 10) & 0x1F) << 3;
368 dst->g = ((col >> 5) & 0x1F) << 3;
369 dst->b = (col & 0x1F) << 3;
370 dst->a = 255;
371 dst++;
372 }
373 }
374 else
375 {
376 count++;
377 c += count;
378 while (count--)
379 {
380 vuint16 col;
381 *Strm << col;
382 dst->r = ((col >> 10) & 0x1F) << 3;
383 dst->g = ((col >> 5) & 0x1F) << 3;
384 dst->b = (col & 0x1F) << 3;
385 dst->a = 255;
386 dst++;
387 }
388 }
389 }
390 while (c < Width);
391 }
392 }
393 else if (hdr.img_type == 10 && hdr.pal_type == 0 && hdr.bpp == 24)
394 {
395 // 24-bit REL compressed
396 for (int y = Height; y; y--)
397 {
398 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
399 rgba_t *dst = (rgba_t*)(Pixels + yc * Width * 4);
400 c = 0;
401
402 do
403 {
404 count = Streamer<vuint8>(*Strm);
405 if (count & 0x80)
406 {
407 count = (count & 0x7F) + 1;
408 c += count;
409 rgba_t col;
410 *Strm << col.b << col.g << col.r;
411 col.a = 255;
412 while (count--)
413 {
414 *dst = col;
415 dst++;
416 }
417 }
418 else
419 {
420 count++;
421 c += count;
422 while (count--)
423 {
424 *Strm << dst->b
425 << dst->g
426 << dst->r;
427 dst->a = 255;
428 dst++;
429 }
430 }
431 }
432 while (c < Width);
433 }
434 }
435 else if (hdr.img_type == 10 && hdr.pal_type == 0 && hdr.bpp == 32)
436 {
437 // 32-bit RLE compressed
438 for (int y = Height; y; y--)
439 {
440 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
441 rgba_t* dst = (rgba_t*)(Pixels + yc * Width * 4);
442 c = 0;
443
444 do
445 {
446 count = Streamer<vuint8>(*Strm);
447 if (count & 0x80)
448 {
449 count = (count & 0x7F) + 1;
450 c += count;
451 rgba_t col;
452 *Strm << col.b << col.g << col.r << col.a;
453 while (count--)
454 {
455 *dst = col;
456 dst++;
457 }
458 }
459 else
460 {
461 count++;
462 c += count;
463 while (count--)
464 {
465 *Strm << dst->b
466 << dst->g
467 << dst->r
468 << dst->a;
469 dst++;
470 }
471 }
472 }
473 while (c < Width);
474 }
475 }
476 else if (hdr.img_type == 11 && hdr.bpp == 8 && hdr.pal_type == 1)
477 {
478 // Grayscale RLE compressed
479 for (int i = 0; i < 256; i++)
480 {
481 Palette[i].r = i;
482 Palette[i].g = i;
483 Palette[i].b = i;
484 Palette[i].a = 255;
485 }
486 for (int y = Height; y; y--)
487 {
488 int yc = hdr.descriptor_bits & 0x20 ? Height - y : y - 1;
489 byte *dst = Pixels + yc * Width;
490 c = 0;
491
492 do
493 {
494 count = Streamer<vuint8>(*Strm);
495 if (count & 0x80)
496 {
497 count = (count & 0x7F) + 1;
498 c += count;
499 vuint8 col;
500 *Strm << col;
501 while (count--)
502 *(dst++) = col;
503 }
504 else
505 {
506 count++;
507 c += count;
508 Strm->Serialise(dst, count);
509 dst += count;
510 }
511 }
512 while (c < Width);
513 }
514 }
515 else
516 {
517 Sys_Error("Nonsupported tga format");
518 }
519
520 delete Strm;
521 Strm = NULL;
522
523 // For 8-bit textures remap colour 0.
524 if (Format == TEXFMT_8Pal)
525 {
526 FixupPalette(Pixels, Palette);
527 }
528 return Pixels;
529 unguard;
530 }
531
532 //==========================================================================
533 //
534 // VTgaTexture::GetPalette
535 //
536 //==========================================================================
537
GetPalette()538 rgba_t* VTgaTexture::GetPalette()
539 {
540 guardSlow(VTgaTexture::GetPalette);
541 return Palette;
542 unguardSlow;
543 }
544
545 //==========================================================================
546 //
547 // VTgaTexture::Unload
548 //
549 //==========================================================================
550
Unload()551 void VTgaTexture::Unload()
552 {
553 guard(VTgaTexture::Unload);
554 if (Pixels)
555 {
556 delete[] Pixels;
557 Pixels = NULL;
558 }
559 if (Palette)
560 {
561 delete[] Palette;
562 Palette = NULL;
563 }
564 unguard;
565 }
566
567 //==========================================================================
568 //
569 // WriteTGA
570 //
571 //==========================================================================
572
573 #ifdef CLIENT
WriteTGA(char * filename,void * data,int width,int height,int bpp,bool bot2top)574 void WriteTGA(char* filename, void* data, int width, int height, int bpp,
575 bool bot2top)
576 {
577 guard(WriteTGA);
578 VStream* Strm = FL_OpenFileWrite(filename);
579 if (!Strm)
580 {
581 GCon->Log("Couldn't write tga");
582 return;
583 }
584
585 tgaHeader_t hdr;
586 hdr.id_length = 0;
587 hdr.pal_type = (bpp == 8) ? 1 : 0;
588 hdr.img_type = (bpp == 8) ? 1 : 2;
589 hdr.first_colour = 0;
590 hdr.pal_colours = (bpp == 8) ? 256 : 0;
591 hdr.pal_entry_size = (bpp == 8) ? 24 : 0;
592 hdr.left = 0;
593 hdr.top = 0;
594 hdr.width = width;
595 hdr.height = height;
596 hdr.bpp = bpp;
597 hdr.descriptor_bits = bot2top ? 0 : 0x20;
598 *Strm << hdr;
599
600 if (bpp == 8)
601 {
602 for (int i = 0; i < 256; i++)
603 {
604 *Strm << r_palette[i].b
605 << r_palette[i].g
606 << r_palette[i].r;
607 }
608 }
609
610 if (bpp == 8)
611 {
612 Strm->Serialise(data, width * height);
613 }
614 else if (bpp == 24)
615 {
616 rgb_t *src = (rgb_t *)data;
617 for (int i = 0; i < width * height; i++, src++)
618 {
619 *Strm << src->b
620 << src->g
621 << src->r;
622 }
623 }
624
625 delete Strm;
626 Strm = NULL;
627 unguard;
628 }
629 #endif
630