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