Too many fixes to mention. (sys_ticrate now controls packet rates, and other stuff)
[divverent/darkplaces.git] / image.c
1
2 #include "quakedef.h"
3
4 int             image_width;
5 int             image_height;
6
7 /*
8 =================================================================
9
10   PCX Loading
11
12 =================================================================
13 */
14
15 typedef struct
16 {
17     char        manufacturer;
18     char        version;
19     char        encoding;
20     char        bits_per_pixel;
21     unsigned short      xmin,ymin,xmax,ymax;
22     unsigned short      hres,vres;
23     unsigned char       palette[48];
24     char        reserved;
25     char        color_planes;
26     unsigned short      bytes_per_line;
27     unsigned short      palette_type;
28     char        filler[58];
29     unsigned    data;                   // unbounded
30 } pcx_t;
31
32 /*
33 ============
34 LoadPCX
35 ============
36 */
37 byte* LoadPCX (FILE *f, int matchwidth, int matchheight)
38 {
39         pcx_t   *pcx, pcxbuf;
40         byte    palette[768];
41         byte    *pix, *image_rgba;
42         int             x, y;
43         int             dataByte, runLength;
44         int             count;
45
46 //
47 // parse the PCX file
48 //
49         fread (&pcxbuf, 1, sizeof(pcxbuf), f);
50
51         pcx = &pcxbuf;
52
53         if (pcx->manufacturer != 0x0a
54                 || pcx->version != 5
55                 || pcx->encoding != 1
56                 || pcx->bits_per_pixel != 8
57                 || pcx->xmax >= 320
58                 || pcx->ymax >= 256)
59         {
60                 Con_Printf ("Bad pcx file\n");
61                 return NULL;
62         }
63
64         if (matchwidth && (pcx->xmax+1) != matchwidth)
65                 return NULL;
66         if (matchheight && (pcx->ymax+1) != matchheight)
67                 return NULL;
68
69         // seek to palette
70         fseek (f, -768, SEEK_END);
71         fread (palette, 1, 768, f);
72
73         fseek (f, sizeof(pcxbuf) - 4, SEEK_SET);
74
75         count = (pcx->xmax+1) * (pcx->ymax+1);
76         image_rgba = malloc( count * 4);
77
78         for (y=0 ; y<=pcx->ymax ; y++)
79         {
80                 pix = image_rgba + 4*y*(pcx->xmax+1);
81                 for (x=0 ; x<=pcx->xmax ; )
82                 {
83                         dataByte = fgetc(f);
84
85                         if((dataByte & 0xC0) == 0xC0)
86                         {
87                                 runLength = dataByte & 0x3F;
88                                 dataByte = fgetc(f);
89                         }
90                         else
91                                 runLength = 1;
92
93                         while(runLength-- > 0)
94                         {
95                                 pix[0] = palette[dataByte*3];
96                                 pix[1] = palette[dataByte*3+1];
97                                 pix[2] = palette[dataByte*3+2];
98                                 pix[3] = 255;
99                                 pix += 4;
100                                 x++;
101                         }
102                 }
103         }
104         image_width = pcx->xmax+1;
105         image_height = pcx->ymax+1;
106         return image_rgba;
107 }
108
109 /*
110 =========================================================
111
112 TARGA LOADING
113
114 =========================================================
115 */
116
117 typedef struct _TargaHeader {
118         unsigned char   id_length, colormap_type, image_type;
119         unsigned short  colormap_index, colormap_length;
120         unsigned char   colormap_size;
121         unsigned short  x_origin, y_origin, width, height;
122         unsigned char   pixel_size, attributes;
123 } TargaHeader;
124
125
126 TargaHeader             targa_header;
127
128 int fgetLittleShort (FILE *f)
129 {
130         byte    b1, b2;
131
132         b1 = fgetc(f);
133         b2 = fgetc(f);
134
135         return (short)(b1 + b2*256);
136 }
137
138 int fgetLittleLong (FILE *f)
139 {
140         byte    b1, b2, b3, b4;
141
142         b1 = fgetc(f);
143         b2 = fgetc(f);
144         b3 = fgetc(f);
145         b4 = fgetc(f);
146
147         return b1 + (b2<<8) + (b3<<16) + (b4<<24);
148 }
149
150
151 /*
152 =============
153 LoadTGA
154 =============
155 */
156 byte* LoadTGA (FILE *fin, int matchwidth, int matchheight)
157 {
158         int                             columns, rows, numPixels;
159         byte                    *pixbuf;
160         int                             row, column;
161         byte                    *image_rgba;
162
163         targa_header.id_length = fgetc(fin);
164         targa_header.colormap_type = fgetc(fin);
165         targa_header.image_type = fgetc(fin);
166         
167         targa_header.colormap_index = fgetLittleShort(fin);
168         targa_header.colormap_length = fgetLittleShort(fin);
169         targa_header.colormap_size = fgetc(fin);
170         targa_header.x_origin = fgetLittleShort(fin);
171         targa_header.y_origin = fgetLittleShort(fin);
172         targa_header.width = fgetLittleShort(fin);
173         targa_header.height = fgetLittleShort(fin);
174         if (matchwidth && targa_header.width != matchwidth)
175                 return NULL;
176         if (matchheight && targa_header.height != matchheight)
177                 return NULL;
178         targa_header.pixel_size = fgetc(fin);
179         targa_header.attributes = fgetc(fin);
180
181         if (targa_header.image_type!=2 
182                 && targa_header.image_type!=10) 
183                 Host_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
184
185         if (targa_header.colormap_type !=0 
186                 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
187                 Host_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
188
189         columns = targa_header.width;
190         rows = targa_header.height;
191         numPixels = columns * rows;
192
193         image_rgba = malloc (numPixels*4);
194         
195         if (targa_header.id_length != 0)
196                 fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
197         
198         if (targa_header.image_type==2) {  // Uncompressed, RGB images
199                 for(row=rows-1; row>=0; row--) {
200                         pixbuf = image_rgba + row*columns*4;
201                         for(column=0; column<columns; column++) {
202                                 unsigned char red,green,blue,alphabyte;
203                                 switch (targa_header.pixel_size) {
204                                         case 24:
205                                                         
206                                                         blue = getc(fin);
207                                                         green = getc(fin);
208                                                         red = getc(fin);
209                                                         *pixbuf++ = red;
210                                                         *pixbuf++ = green;
211                                                         *pixbuf++ = blue;
212                                                         *pixbuf++ = 255;
213                                                         break;
214                                         case 32:
215                                                         blue = getc(fin);
216                                                         green = getc(fin);
217                                                         red = getc(fin);
218                                                         alphabyte = getc(fin);
219                                                         *pixbuf++ = red;
220                                                         *pixbuf++ = green;
221                                                         *pixbuf++ = blue;
222                                                         *pixbuf++ = alphabyte;
223                                                         break;
224                                 }
225                         }
226                 }
227         }
228         else if (targa_header.image_type==10) {   // Runlength encoded RGB images
229                 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
230                 for(row=rows-1; row>=0; row--) {
231                         pixbuf = image_rgba + row*columns*4;
232                         for(column=0; column<columns; ) {
233                                 packetHeader=getc(fin);
234                                 packetSize = 1 + (packetHeader & 0x7f);
235                                 if (packetHeader & 0x80) {        // run-length packet
236                                         switch (targa_header.pixel_size) {
237                                                 case 24:
238                                                                 blue = getc(fin);
239                                                                 green = getc(fin);
240                                                                 red = getc(fin);
241                                                                 alphabyte = 255;
242                                                                 break;
243                                                 case 32:
244                                                                 blue = getc(fin);
245                                                                 green = getc(fin);
246                                                                 red = getc(fin);
247                                                                 alphabyte = getc(fin);
248                                                                 break;
249                                         }
250         
251                                         for(j=0;j<packetSize;j++) {
252                                                 *pixbuf++=red;
253                                                 *pixbuf++=green;
254                                                 *pixbuf++=blue;
255                                                 *pixbuf++=alphabyte;
256                                                 column++;
257                                                 if (column==columns) { // run spans across rows
258                                                         column=0;
259                                                         if (row>0)
260                                                                 row--;
261                                                         else
262                                                                 goto breakOut;
263                                                         pixbuf = image_rgba + row*columns*4;
264                                                 }
265                                         }
266                                 }
267                                 else {                            // non run-length packet
268                                         for(j=0;j<packetSize;j++) {
269                                                 switch (targa_header.pixel_size) {
270                                                         case 24:
271                                                                         blue = getc(fin);
272                                                                         green = getc(fin);
273                                                                         red = getc(fin);
274                                                                         *pixbuf++ = red;
275                                                                         *pixbuf++ = green;
276                                                                         *pixbuf++ = blue;
277                                                                         *pixbuf++ = 255;
278                                                                         break;
279                                                         case 32:
280                                                                         blue = getc(fin);
281                                                                         green = getc(fin);
282                                                                         red = getc(fin);
283                                                                         alphabyte = getc(fin);
284                                                                         *pixbuf++ = red;
285                                                                         *pixbuf++ = green;
286                                                                         *pixbuf++ = blue;
287                                                                         *pixbuf++ = alphabyte;
288                                                                         break;
289                                                 }
290                                                 column++;
291                                                 if (column==columns) { // pixel packet run spans across rows
292                                                         column=0;
293                                                         if (row>0)
294                                                                 row--;
295                                                         else
296                                                                 goto breakOut;
297                                                         pixbuf = image_rgba + row*columns*4;
298                                                 }                                               
299                                         }
300                                 }
301                         }
302                         breakOut:;
303                 }
304         }
305         
306         fclose(fin);
307         image_width = columns;
308         image_height = rows;
309         return image_rgba;
310 }
311
312 byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight)
313 {
314         FILE    *f;
315         char    basename[128], name[128];
316         byte    *image_rgba;
317         COM_StripExtension(filename, basename); // strip the extension to allow TGA skins on Q2 models despite the .pcx in the skin name
318         sprintf (name, "textures/%s.tga", basename);
319         COM_FOpenFile (name, &f, true);
320         if (f)
321                 return LoadTGA (f, matchwidth, matchheight);
322         sprintf (name, "textures/%s.pcx", basename);
323         COM_FOpenFile (name, &f, true);
324         if (f)
325                 return LoadPCX (f, matchwidth, matchheight);
326         sprintf (name, "%s.tga", basename);
327         COM_FOpenFile (name, &f, true);
328         if (f)
329                 return LoadTGA (f, matchwidth, matchheight);
330         sprintf (name, "%s.pcx", basename);
331         COM_FOpenFile (name, &f, true);
332         if (f)
333                 return LoadPCX (f, matchwidth, matchheight);
334         if (image_rgba = W_GetTexture(basename, matchwidth, matchheight))
335                 return image_rgba;
336         if (complain)
337                 Con_Printf ("Couldn't load %s.tga or .pcx\n", filename);
338         return NULL;
339 }
340
341 int loadtextureimage (int texnum, char* filename, qboolean complain, int matchwidth, int matchheight)
342 {
343         byte *data;
344         if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight)))
345                 return 0;
346         if (texnum >= 0) // specific texnum, not cached
347         {
348                 glBindTexture(GL_TEXTURE_2D, texnum);
349                 GL_Upload32 (data, image_width, image_height, true, true);
350                 free(data);
351                 return texnum;
352         }
353         else // any texnum, cached
354         {
355                 texnum = GL_LoadTexture (filename, image_width, image_height, data, true, true, 4);
356                 free(data);
357                 return texnum;
358         }
359 }