1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 2008 Ludwig Nussel
5
6 This file is part of Quake III Arena source code.
7
8 Quake III Arena source code is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 Quake III Arena source code is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Quake III Arena source code; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ===========================================================================
22 */
23
24 #include "tr_local.h"
25
26 /*
27 ========================================================================
28
29 PCX files are used for 8 bit images
30
31 ========================================================================
32 */
33
34 typedef struct {
35 char manufacturer;
36 char version;
37 char encoding;
38 char bits_per_pixel;
39 unsigned short xmin,ymin,xmax,ymax;
40 unsigned short hres,vres;
41 unsigned char palette[48];
42 char reserved;
43 char color_planes;
44 unsigned short bytes_per_line;
45 unsigned short palette_type;
46 unsigned short hscreensize, vscreensize;
47 char filler[54];
48 unsigned char data[];
49 } pcx_t;
50
R_LoadPCX(const char * filename,byte ** pic,int * width,int * height)51 void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height)
52 {
53 union {
54 byte *b;
55 void *v;
56 } raw;
57 byte *end;
58 pcx_t *pcx;
59 int len;
60 unsigned char dataByte = 0, runLength = 0;
61 byte *out, *pix;
62 unsigned short w, h;
63 byte *pic8;
64 byte *palette;
65 int i;
66 unsigned size = 0;
67
68 if (width)
69 *width = 0;
70 if (height)
71 *height = 0;
72 *pic = NULL;
73
74 //
75 // load the file
76 //
77 len = ri.FS_ReadFile( ( char * ) filename, &raw.v);
78 if (!raw.b || len < 0) {
79 return;
80 }
81
82 if((unsigned)len < sizeof(pcx_t))
83 {
84 ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename);
85 ri.FS_FreeFile (raw.v);
86 return;
87 }
88
89 //
90 // parse the PCX file
91 //
92 pcx = (pcx_t *)raw.b;
93 end = raw.b+len;
94
95 w = LittleShort(pcx->xmax)+1;
96 h = LittleShort(pcx->ymax)+1;
97 size = w*h;
98
99 if (pcx->manufacturer != 0x0a
100 || pcx->version != 5
101 || pcx->encoding != 1
102 || pcx->color_planes != 1
103 || pcx->bits_per_pixel != 8
104 || w >= 1024
105 || h >= 1024)
106 {
107 ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel);
108 return;
109 }
110
111 pix = pic8 = ri.Z_Malloc ( size );
112
113 raw.b = pcx->data;
114 // FIXME: should use bytes_per_line but original q3 didn't do that either
115 while(pix < pic8+size)
116 {
117 if(runLength > 0) {
118 *pix++ = dataByte;
119 --runLength;
120 continue;
121 }
122
123 if(raw.b+1 > end)
124 break;
125 dataByte = *raw.b++;
126
127 if((dataByte & 0xC0) == 0xC0)
128 {
129 if(raw.b+1 > end)
130 break;
131 runLength = dataByte & 0x3F;
132 dataByte = *raw.b++;
133 }
134 else
135 runLength = 1;
136 }
137
138 if(pix < pic8+size)
139 {
140 ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename);
141 ri.FS_FreeFile (pcx);
142 ri.Free (pic8);
143 }
144
145 if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c)
146 {
147 ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename);
148 ri.FS_FreeFile (pcx);
149 ri.Free (pic8);
150 return;
151 }
152
153 palette = end-768;
154
155 pix = out = ri.Z_Malloc(4 * size );
156 for (i = 0 ; i < size ; i++)
157 {
158 unsigned char p = pic8[i];
159 pix[0] = palette[p*3];
160 pix[1] = palette[p*3 + 1];
161 pix[2] = palette[p*3 + 2];
162 pix[3] = 255;
163 pix += 4;
164 }
165
166 if (width)
167 *width = w;
168 if (height)
169 *height = h;
170
171 *pic = out;
172
173 ri.FS_FreeFile (pcx);
174 ri.Free (pic8);
175 }
176