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