1 //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: imglib.cpp 4206 2010-04-03 16:32:33Z dj_jl $
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 "cmdlib.h"
29 #include "imglib.h"
30 
31 namespace VavoomUtils {
32 
33 // MACROS ------------------------------------------------------------------
34 
35 // TYPES -------------------------------------------------------------------
36 
37 #pragma pack(push, 1)
38 
39 struct pcx_t
40 {
41 	char			manufacturer;
42 	char			version;
43 	char			encoding;
44 	char			bits_per_pixel;
45 
46 	unsigned short	xmin;
47 	unsigned short	ymin;
48 	unsigned short	xmax;
49 	unsigned short	ymax;
50 
51 	unsigned short	hres;
52 	unsigned short	vres;
53 
54 	unsigned char	palette[48];
55 
56 	char			reserved;
57 	char			colour_planes;
58 	unsigned short	bytes_per_line;
59 	unsigned short	palette_type;
60 
61 	char			filler[58];
62 	unsigned char	data;		// unbounded
63 };
64 
65 struct tgaHeader_t
66 {
67 	vuint8		id_length;
68 	vuint8		pal_type;
69 	vuint8		img_type;
70 	vuint16		first_colour;
71 	vuint16		pal_colours;
72 	vuint8		pal_entry_size;
73 	vuint16		left;
74 	vuint16		top;
75 	vuint16		width;
76 	vuint16		height;
77 	vuint8		bpp;
78 	vuint8		descriptor_bits;
79 };
80 
81 #pragma pack(pop)
82 
83 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
84 
85 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
86 
87 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
88 
89 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
90 
91 // PUBLIC DATA DEFINITIONS -------------------------------------------------
92 
93 int				ImgWidth;
94 int				ImgHeight;
95 int				ImgBPP;
96 vuint8*			ImgData;
97 rgb_t			ImgPal[256];
98 
99 // PRIVATE DATA DEFINITIONS ------------------------------------------------
100 
101 // CODE --------------------------------------------------------------------
102 
LoadPCX(const char * filename)103 static void LoadPCX(const char *filename)
104 {
105 	int			c;
106 	int			bytes_per_line;
107 	int			x, y;
108 	char		ch;
109 	pcx_t		*pcx;
110 	vuint8		*data;
111 
112 	LoadFile(filename, (void**)&pcx);
113 
114 	if (pcx->bits_per_pixel != 8)
115 	{
116 		// we like 8 bit colour planes
117 		Error("No 8-bit planes\n");
118 	}
119 	if (pcx->colour_planes != 1)
120 	{
121 		Error("Not 8 bpp\n");
122 	}
123 
124 	ImgWidth = LittleShort(pcx->xmax) - LittleShort(pcx->xmin) + 1;
125 	ImgHeight = LittleShort(pcx->ymax) - LittleShort(pcx->ymin) + 1;
126 	ImgBPP = 8;
127 
128 	bytes_per_line = LittleShort(pcx->bytes_per_line);
129 
130 	ImgData = new vuint8[ImgWidth * ImgHeight];
131 
132 	data = &pcx->data;
133 
134 	for (y = 0; y < ImgHeight; y++)
135 	{
136 		// decompress RLE encoded PCX data
137 		x = 0;
138 
139 		while (x < bytes_per_line)
140 		{
141 			ch = *data++;
142 			if ((ch & 0xC0) == 0xC0)
143 			{
144 				c = (ch & 0x3F);
145 				ch = *data++;
146 			}
147 			else
148 			{
149 				c = 1;
150 			}
151 
152 			while (c--)
153 			{
154 				if (x < ImgWidth)
155 					ImgData[y * ImgWidth + x] = ch;
156 				x++;
157 			}
158 		}
159 	}
160 
161 	if (*data == 12)
162 	{
163 		data++;
164 		for (c = 0; c < 256; c++)
165 		{
166 			ImgPal[c].r = *data++;
167 			ImgPal[c].g = *data++;
168 			ImgPal[c].b = *data++;
169 		}
170 	}
171 
172 	Z_Free(pcx);
173 }
174 
175 //==========================================================================
176 //
177 //	LoadTGA
178 //
179 //==========================================================================
180 
LoadTGA(const char * filename)181 static void LoadTGA(const char *filename)
182 {
183 	tgaHeader_t *hdr;
184 	vuint8* data;
185 	int col;
186 	int count;
187 	int c;
188 
189 	LoadFile(filename, (void**)&hdr);
190 
191 	ImgWidth = LittleShort(hdr->width);
192 	ImgHeight = LittleShort(hdr->height);
193 
194 	data = (vuint8*)(hdr + 1) + hdr->id_length;
195 
196 	for (int i = 0; i < hdr->pal_colours; i++)
197 	{
198 		switch (hdr->pal_entry_size)
199 		{
200 		case 16:
201 			col = *(vuint16*)data;
202 			ImgPal[i].r = (col & 0x1F) << 3;
203 			ImgPal[i].g = ((col >> 5) & 0x1F) << 3;
204 			ImgPal[i].b = ((col >> 10) & 0x1F) << 3;
205 			//ImgPal[i].a = 255;
206 			break;
207 		case 24:
208 			ImgPal[i].b = data[0];
209 			ImgPal[i].g = data[1];
210 			ImgPal[i].r = data[2];
211 			//ImgPal[i].a = 255;
212 			break;
213 		case 32:
214 			ImgPal[i].b = data[0];
215 			ImgPal[i].g = data[1];
216 			ImgPal[i].r = data[2];
217 			//ImgPal[i].a = data[3];
218 			break;
219 		}
220 		data += (hdr->pal_entry_size >> 3);
221 	}
222 
223 	/* Image type:
224 	 *    0 = no image data
225 	 *    1 = uncompressed colour mapped
226 	 *    2 = uncompressed true colour
227 	 *    3 = grayscale
228 	 *    9 = RLE colour mapped
229 	 *   10 = RLE true colour
230 	 *   11 = RLE grayscale
231 	 */
232 
233 	if (hdr->img_type == 1 || hdr->img_type == 3 ||
234 		hdr->img_type == 9 || hdr->img_type == 11)
235 	{
236 		ImgBPP = 8;
237 		ImgData = (vuint8*)Z_Malloc(ImgWidth * ImgHeight);
238 	}
239 	else
240 	{
241 		ImgBPP = 32;
242 		ImgData = (vuint8*)Z_Malloc(ImgWidth * ImgHeight * 4);
243 	}
244 
245 	if (hdr->img_type == 1 && hdr->bpp == 8 && hdr->pal_type == 1)
246 	{
247 		// 8-bit, uncompressed
248 		for (int y = ImgHeight; y; y--)
249 		{
250 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
251 			vuint8* dst = ImgData + yc * ImgWidth;
252 
253 			memcpy(dst, data, ImgWidth);
254 			data += ImgWidth;
255 		}
256 	}
257 	else if (hdr->img_type == 2 && hdr->pal_type == 0 && hdr->bpp == 16)
258 	{
259 		// 16-bit uncompressed
260 		for (int y = ImgHeight; y; y--)
261 		{
262 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
263 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
264 
265 			for (int x = 0; x < ImgWidth; x++, dst++, data += 2)
266 			{
267 				col = *(vuint16*)data;
268 				dst->r = ((col >> 10) & 0x1F) << 3;
269 				dst->g = ((col >> 5) & 0x1F) << 3;
270 				dst->b = (col & 0x1F) << 3;
271 				dst->a = 255;
272 			}
273 		}
274 	}
275 	else if (hdr->img_type == 2 && hdr->pal_type == 0 && hdr->bpp == 24)
276 	{
277 		// 24-bit uncompressed
278 		for (int y = ImgHeight; y; y--)
279 		{
280 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
281 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
282 
283 			for (int x = 0; x < ImgWidth; x++, dst++, data += 3)
284 			{
285 				dst->b = data[0];
286 				dst->g = data[1];
287 				dst->r = data[2];
288 				dst->a = 255;
289 			}
290 		}
291 	}
292 	else if (hdr->img_type == 2 && hdr->pal_type == 0 && hdr->bpp == 32)
293 	{
294 		// 32-bit uncompressed
295 		for (int y = ImgHeight; y; y--)
296 		{
297 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
298 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
299 
300 			for (int x = 0; x < ImgWidth; x++, dst++, data += 4)
301 			{
302 				dst->b = data[0];
303 				dst->g = data[1];
304 				dst->r = data[2];
305 				dst->a = data[3];
306 			}
307 		}
308 	}
309 	else if (hdr->img_type == 3 && hdr->bpp == 8 && hdr->pal_type == 1)
310 	{
311 		// Grayscale uncompressed
312 		for (int i = 0; i < 256; i++)
313 		{
314 			ImgPal[i].r = i;
315 			ImgPal[i].g = i;
316 			ImgPal[i].b = i;
317 			//ImgPal[i].a = 255;
318 		}
319 		for (int y = ImgHeight; y; y--)
320 		{
321 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
322 			vuint8* dst = ImgData + yc * ImgWidth;
323 
324 			memcpy(dst, data, ImgWidth);
325 			data += ImgWidth;
326 		}
327 	}
328 	else if (hdr->img_type == 9 && hdr->bpp == 8 && hdr->pal_type == 1)
329 	{
330 		// 8-bit RLE compressed
331 		for (int y = ImgHeight; y; y--)
332 		{
333 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
334 			vuint8* dst = ImgData + yc * ImgWidth;
335 			c = 0;
336 
337 			do
338 			{
339 				count = *data++;
340 				if (count & 0x80)
341 				{
342 					count = (count & 0x7F) + 1;
343 					c += count;
344 					while (count--)
345 						*(dst++) = *data;
346 					data++;
347 				}
348 				else
349 				{
350 					count++;
351 					c += count;
352 					memcpy(dst, data, count);
353 					data += count;
354 					dst += count;
355 				}
356 			}
357 			while (c < ImgWidth);
358 		}
359 	}
360 	else if (hdr->img_type == 10 && hdr->pal_type == 0 && hdr->bpp == 16)
361 	{
362 		// 16-bit RLE compressed
363 		for (int y = ImgHeight; y; y--)
364 		{
365 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
366 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
367 			c = 0;
368 
369 			do
370 			{
371 				count = *data++;
372 				if (count & 0x80)
373 				{
374 					count = (count & 0x7F) + 1;
375 					c += count;
376 					col = *(vuint16*)data;
377 					while (count--)
378 					{
379 						dst->r = ((col >> 10) & 0x1F) << 3;
380 						dst->g = ((col >> 5) & 0x1F) << 3;
381 						dst->b = (col & 0x1F) << 3;
382 						dst->a = 255;
383 						dst++;
384 					}
385 					data += 2;
386 				}
387 				else
388 				{
389 					count++;
390 					c += count;
391 					while (count--)
392 					{
393 						col = *(vuint16*)data;
394 						dst->r = ((col >> 10) & 0x1F) << 3;
395 						dst->g = ((col >> 5) & 0x1F) << 3;
396 						dst->b = (col & 0x1F) << 3;
397 						dst->a = 255;
398 						data += 2;
399 						dst++;
400 					}
401 				}
402 			}
403 			while (c < ImgWidth);
404 		}
405 	}
406 	else if (hdr->img_type == 10 && hdr->pal_type == 0 && hdr->bpp == 24)
407 	{
408 		// 24-bit REL compressed
409 		for (int y = ImgHeight; y; y--)
410 		{
411 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
412 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
413 			c = 0;
414 
415 			do
416 			{
417 				count = *data++;
418 				if (count & 0x80)
419 				{
420 					count = (count & 0x7F) + 1;
421 					c += count;
422 					while (count--)
423 					{
424 						dst->r = data[2];
425 						dst->g = data[1];
426 						dst->b = data[0];
427 						dst->a = 255;
428 						dst++;
429 					}
430 					data += 3;
431 				}
432 				else
433 				{
434 					count++;
435 					c += count;
436 					while (count--)
437 					{
438 						dst->r = data[2];
439 						dst->g = data[1];
440 						dst->b = data[0];
441 						dst->a = 255;
442 						data += 3;
443 						dst++;
444 					}
445 				}
446 			}
447 			while (c < ImgWidth);
448 		}
449 	}
450 	else if (hdr->img_type == 10 && hdr->pal_type == 0 && hdr->bpp == 32)
451 	{
452 		// 32-bit RLE compressed
453 		for (int y = ImgHeight; y; y--)
454 		{
455 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
456 			rgba_t *dst = (rgba_t*)(ImgData + yc * ImgWidth * 4);
457 			c = 0;
458 
459 			do
460 			{
461 				count = *data++;
462 				if (count & 0x80)
463 				{
464 					count = (count & 0x7F) + 1;
465 					c += count;
466 					while (count--)
467 					{
468 						dst->r = data[2];
469 						dst->g = data[1];
470 						dst->b = data[0];
471 						dst->a = data[3];
472 						dst++;
473 					}
474 					data += 4;
475 				}
476 				else
477 				{
478 					count++;
479 					c += count;
480 					while (count--)
481 					{
482 						dst->r = data[2];
483 						dst->g = data[1];
484 						dst->b = data[0];
485 						dst->a = data[3];
486 						data += 4;
487 						dst++;
488 					}
489 				}
490 			}
491 			while (c < ImgWidth);
492 		}
493 	}
494 	else if (hdr->img_type == 11 && hdr->bpp == 8 && hdr->pal_type == 1)
495 	{
496 		// Grayscale RLE compressed
497 		for (int i = 0; i < 256; i++)
498 		{
499 			ImgPal[i].r = i;
500 			ImgPal[i].g = i;
501 			ImgPal[i].b = i;
502 			//ImgPal[i].a = 255;
503 		}
504 		for (int y = ImgHeight; y; y--)
505 		{
506 			int yc = hdr->descriptor_bits & 0x20 ? ImgHeight - y : y - 1;
507 			vuint8* dst = ImgData + yc * ImgWidth;
508 			c = 0;
509 
510 			do
511 			{
512 				count = *data++;
513 				if (count & 0x80)
514 				{
515 					count = (count & 0x7F) + 1;
516 					c += count;
517 					while (count--)
518 						*(dst++) = *data;
519 					data++;
520 				}
521 				else
522 				{
523 					count++;
524 					c += count;
525 					memcpy(dst, data, count);
526 					data += count;
527 					dst += count;
528 				}
529 			}
530 			while (c < ImgWidth);
531 		}
532 	}
533 	else
534 	{
535 		Error("Nonsupported tga format");
536 	}
537 
538 
539 	Z_Free(hdr);
540 }
541 
542 //==========================================================================
543 //
544 //	LoadImage
545 //
546 //==========================================================================
547 
LoadImage(const char * name)548 void LoadImage(const char *name)
549 {
550 	char	ext[8];
551 
552 	ExtractFileExtension(name, ext);
553 	if (!strcmp(ext, "pcx"))
554 		LoadPCX(name);
555 	else if (!strcmp(ext, "tga"))
556 		LoadTGA(name);
557 	else
558 		Error("Unknown extension");
559 }
560 
561 //==========================================================================
562 //
563 //	ConvertImageTo32Bit
564 //
565 //==========================================================================
566 
ConvertImageTo32Bit()567 void ConvertImageTo32Bit()
568 {
569 	if (ImgBPP == 8)
570 	{
571 		rgba_t *NewData = (rgba_t *)Z_Malloc(ImgWidth * ImgHeight * 4);
572 		for (int i = 0; i < ImgWidth * ImgHeight; i++)
573 		{
574 			NewData[i].r = ImgPal[ImgData[i]].r;
575 			NewData[i].g = ImgPal[ImgData[i]].g;
576 			NewData[i].b = ImgPal[ImgData[i]].b;
577 			NewData[i].a = 255;
578 		}
579 		Z_Free(ImgData);
580 		ImgData = (vuint8*)NewData;
581 		ImgBPP = 32;
582 	}
583 }
584 
585 //==========================================================================
586 //
587 //	DestroyImage
588 //
589 //==========================================================================
590 
DestroyImage()591 void DestroyImage()
592 {
593 	if (ImgData)
594 	{
595 		delete ImgData;
596 		ImgData = NULL;
597 	}
598 }
599 
600 } // namespace
601