Skip to content

Commit f37189d

Browse files
erysdrentomkidd
authored andcommitted
Improve PVR image support
1 parent 9630f86 commit f37189d

1 file changed

Lines changed: 256 additions & 32 deletions

File tree

code/renderercommon/tr_image_pvr.c

Lines changed: 256 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,37 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2222

2323
#include "tr_common.h"
2424

25+
typedef struct gbix {
26+
unsigned int magic;
27+
unsigned int len;
28+
} gbix_t;
29+
2530
typedef struct pvr {
26-
unsigned char magic[4];
31+
unsigned int magic;
2732
unsigned int len_file;
2833
unsigned int type;
2934
unsigned short width;
3035
unsigned short height;
31-
unsigned short codebook[1024];
32-
unsigned char indices[1];
3336
} pvr_t;
3437

38+
typedef unsigned int (*pvr_pixel_func_t)(unsigned short color);
39+
typedef byte *(*pvr_image_func_t)(pvr_t *pvr, int offset, qboolean detwiddle, pvr_pixel_func_t pixel_func);
40+
41+
enum {
42+
PVR_PIXEL_TYPE_ARGB1555 = 0,
43+
PVR_PIXEL_TYPE_RGB565 = 1,
44+
PVR_PIXEL_TYPE_ARGB4444 = 2
45+
};
46+
47+
enum {
48+
PVR_IMAGE_TYPE_TWIDDLED = 1,
49+
PVR_IMAGE_TYPE_TWIDDLED_MM = 2,
50+
PVR_IMAGE_TYPE_VQ = 3,
51+
PVR_IMAGE_TYPE_VQ_MM = 4,
52+
PVR_IMAGE_TYPE_RECTANGULAR = 9,
53+
PVR_IMAGE_TYPE_RECTANGULAR_MM = 10
54+
};
55+
3556
static int log2approx(int x)
3657
{
3758
switch (x)
@@ -48,7 +69,7 @@ static int log2approx(int x)
4869
}
4970
}
5071

51-
static int from_xy(int x, int y, int w, int h)
72+
static int pvr_detwiddle(int x, int y, int w, int h)
5273
{
5374
int wmax, hmax;
5475
int i, idx = 0;
@@ -83,7 +104,17 @@ static int from_xy(int x, int y, int w, int h)
83104
return idx;
84105
}
85106

86-
static unsigned int rgb565_to_rgba24(unsigned short color)
107+
static unsigned int argb1555_to_rgba8888(unsigned short color)
108+
{
109+
unsigned char r, g, b, a;
110+
r = ((color >> 10) & 31) << 4;
111+
g = ((color >> 5) & 31) << 4;
112+
b = ((color >> 0) & 31) << 4;
113+
a = ((color >> 15) & 1) * 255;
114+
return (a << 24) | (b << 16) | (g << 8) | r;
115+
}
116+
117+
static unsigned int rgb565_to_rgba8888(unsigned short color)
87118
{
88119
unsigned char r, g, b, a;
89120
r = ((color >> 11) & 31) << 3;
@@ -93,13 +124,153 @@ static unsigned int rgb565_to_rgba24(unsigned short color)
93124
return (a << 24) | (b << 16) | (g << 8) | r;
94125
}
95126

127+
static unsigned int argb4444_to_rgba8888(unsigned short color)
128+
{
129+
unsigned char r, g, b, a;
130+
r = ((color >> 8) & 15) << 4;
131+
g = ((color >> 4) & 15) << 4;
132+
b = ((color >> 0) & 15) << 4;
133+
a = ((color >> 12) & 15) | 0xF;
134+
return (a << 24) | (b << 16) | (g << 8) | r;
135+
}
136+
137+
static int mm_offset(int w)
138+
{
139+
switch (w)
140+
{
141+
case 1: return 0x00006;
142+
case 2: return 0x00008;
143+
case 4: return 0x00010;
144+
case 8: return 0x00030;
145+
case 16: return 0x000B0;
146+
case 32: return 0x002B0;
147+
case 64: return 0x00AB0;
148+
case 128: return 0x02AB0;
149+
case 256: return 0x0AAB0;
150+
case 512: return 0x2AAB0;
151+
case 1024: return 0xAAAB0;
152+
default: return -1;
153+
}
154+
}
155+
156+
static int mm_offset_vq(int w)
157+
{
158+
switch (w)
159+
{
160+
case 1: return 0x00000;
161+
case 2: return 0x00001;
162+
case 4: return 0x00002;
163+
case 8: return 0x00006;
164+
case 16: return 0x00016;
165+
case 32: return 0x00056;
166+
case 64: return 0x00156;
167+
case 128: return 0x00556;
168+
case 256: return 0x01556;
169+
case 512: return 0x05556;
170+
case 1024: return 0x15556;
171+
default: return -1;
172+
}
173+
}
174+
175+
static byte *decode_mm(pvr_t *pvr, pvr_image_func_t image_func, pvr_pixel_func_t pixel_func, qboolean vq, qboolean detwiddle)
176+
{
177+
int offset = vq ? mm_offset_vq(pvr->width) : mm_offset(pvr->width);
178+
return image_func(pvr, offset, detwiddle, pixel_func);
179+
}
180+
181+
static byte *decode(pvr_t *pvr, int offset, qboolean detwiddle, pvr_pixel_func_t pixel_func)
182+
{
183+
int x, y;
184+
unsigned int *rgba32;
185+
byte *ret;
186+
187+
ret = (byte *)ri.Malloc(pvr->width * pvr->height * sizeof(unsigned int));
188+
rgba32 = (unsigned int *)ret;
189+
190+
for (y = 0; y < pvr->height; y++)
191+
{
192+
for (x = 0; x < pvr->width; x++)
193+
{
194+
unsigned short color;
195+
int ofs;
196+
if (detwiddle)
197+
ofs = offset + pvr_detwiddle(x, y, pvr->width, pvr->height) * 2;
198+
else
199+
ofs = offset + (y * pvr->width + x) * 2;
200+
201+
if (ofs < 0)
202+
{
203+
ri.Free(ret);
204+
return NULL;
205+
}
206+
207+
color = *(unsigned short *)(((byte *)(pvr + 1)) + ofs);
208+
209+
rgba32[y * pvr->width + x] = pixel_func(color);
210+
}
211+
}
212+
213+
return ret;
214+
}
215+
216+
static byte *decode_vq(pvr_t *pvr, int offset, qboolean detwiddle, pvr_pixel_func_t pixel_func)
217+
{
218+
int x, y;
219+
unsigned int *rgba32;
220+
unsigned short *codebook;
221+
unsigned char *indices;
222+
byte *ret;
223+
224+
ret = (byte *)ri.Malloc(pvr->width * pvr->height * (pixel_func ? sizeof(unsigned int) : sizeof(unsigned short)));
225+
rgba32 = (unsigned int *)ret;
226+
227+
codebook = (unsigned short *)(pvr + 1);
228+
indices = ((unsigned char *)(codebook + 1024)) + offset;
229+
230+
for (y = 0; y < pvr->height / 2; y++)
231+
{
232+
for (x = 0; x < pvr->width / 2; x++)
233+
{
234+
unsigned short *colors;
235+
int a, b, c, d;
236+
int idx;
237+
if (detwiddle)
238+
idx = pvr_detwiddle(x, y, pvr->width, pvr->height);
239+
else
240+
idx = y * (pvr->width / 2) + x;
241+
242+
if (idx < 0)
243+
{
244+
ri.Free(ret);
245+
return NULL;
246+
}
247+
248+
colors = &codebook[indices[idx] * 4];
249+
250+
a = ((y * 2) + 0) * pvr->width + ((x * 2) + 0);
251+
b = ((y * 2) + 1) * pvr->width + ((x * 2) + 0);
252+
c = ((y * 2) + 0) * pvr->width + ((x * 2) + 1);
253+
d = ((y * 2) + 1) * pvr->width + ((x * 2) + 1);
254+
255+
rgba32[a] = pixel_func(colors[0]);
256+
rgba32[b] = pixel_func(colors[1]);
257+
rgba32[c] = pixel_func(colors[2]);
258+
rgba32[d] = pixel_func(colors[3]);
259+
}
260+
}
261+
262+
return ret;
263+
}
264+
96265
void R_LoadPVR(const char *name, byte **pic, int *width, int *height)
97266
{
98267
unsigned int length;
99268
void *buffer;
269+
byte *ptr;
100270
pvr_t *pvr;
101-
unsigned int *rgba;
102-
int x, y;
271+
int pixel_type, image_type;
272+
pvr_pixel_func_t pixel_func;
273+
byte *ret = NULL;
103274

104275
*pic = NULL;
105276
if (width)
@@ -112,51 +283,104 @@ void R_LoadPVR(const char *name, byte **pic, int *width, int *height)
112283
if (!buffer || length < 0)
113284
return;
114285

286+
ptr = (byte *)buffer;
287+
288+
// skip global index
289+
if (memcmp(ptr, "GBIX", 4) == 0)
290+
{
291+
gbix_t *gbix = (gbix_t *)ptr;
292+
ptr += sizeof(gbix_t) + LittleLong(gbix->len);
293+
}
294+
115295
// check magic identifier
116-
pvr = (pvr_t *)buffer;
117-
if (memcmp(pvr->magic, "PVRT", sizeof(pvr->magic)) != 0)
296+
if (memcmp(ptr, "PVRT", 4) != 0)
118297
ri.Error(ERR_DROP, "LoadPVR: magic identifier does not match expected (%s)", name);
119298

120299
// fix up header
300+
pvr = (pvr_t *)ptr;
121301
pvr->len_file = LittleLong(pvr->len_file);
122302
pvr->type = LittleLong(pvr->type);
123303
pvr->width = LittleShort(pvr->width);
124304
pvr->height = LittleShort(pvr->height);
125305

126-
// allocate rgba buffer
127-
rgba = (unsigned int *)ri.Malloc(pvr->width * pvr->height * 4);
306+
// break out type values
307+
pixel_type = pvr->type & 0xFF;
308+
image_type = (pvr->type & 0xFF00) >> 8;
128309

129-
// decompress image
130-
for (y = 0; y < pvr->height / 2; y++)
310+
// get pixel function
311+
switch (pixel_type)
131312
{
132-
for (x = 0; x < pvr->width / 2; x++)
313+
case PVR_PIXEL_TYPE_ARGB1555:
133314
{
134-
unsigned short *colors;
135-
int a, b, c, d;
136-
int idx = from_xy(x, y, pvr->width, pvr->height);
137-
138-
if (idx < 0)
139-
ri.Error(ERR_DROP, "LoadPVR: invalid data passed to decompressor (%s)", name);
140-
141-
colors = &pvr->codebook[pvr->indices[idx] * 4];
142-
143-
a = ((y * 2) + 0) * pvr->width + ((x * 2) + 0);
144-
b = ((y * 2) + 1) * pvr->width + ((x * 2) + 0);
145-
c = ((y * 2) + 0) * pvr->width + ((x * 2) + 1);
146-
d = ((y * 2) + 1) * pvr->width + ((x * 2) + 1);
315+
pixel_func = argb1555_to_rgba8888;
316+
break;
317+
}
318+
case PVR_PIXEL_TYPE_RGB565:
319+
{
320+
pixel_func = rgb565_to_rgba8888;
321+
break;
322+
}
323+
case PVR_PIXEL_TYPE_ARGB4444:
324+
{
325+
pixel_func = argb4444_to_rgba8888;
326+
break;
327+
}
328+
default:
329+
{
330+
ri.Error(ERR_DROP, "LoadPVR: unsupported pixel type 0x%02x (%s)", pixel_type, name);
331+
break;
332+
}
333+
}
147334

148-
rgba[a] = rgb565_to_rgba24(colors[0]);
149-
rgba[b] = rgb565_to_rgba24(colors[1]);
150-
rgba[c] = rgb565_to_rgba24(colors[2]);
151-
rgba[d] = rgb565_to_rgba24(colors[3]);
335+
// decompress image
336+
switch (image_type)
337+
{
338+
case PVR_IMAGE_TYPE_TWIDDLED:
339+
{
340+
ret = decode(pvr, 0, qtrue, pixel_func);
341+
break;
342+
}
343+
case PVR_IMAGE_TYPE_TWIDDLED_MM:
344+
{
345+
ret = decode_mm(pvr, decode, pixel_func, qfalse, qtrue);
346+
break;
347+
}
348+
case PVR_IMAGE_TYPE_VQ:
349+
{
350+
ret = decode_vq(pvr, 0, qtrue, pixel_func);
351+
break;
352+
}
353+
case PVR_IMAGE_TYPE_VQ_MM:
354+
{
355+
ret = decode_mm(pvr, decode_vq, pixel_func, qtrue, qtrue);
356+
break;
357+
}
358+
case PVR_IMAGE_TYPE_RECTANGULAR:
359+
{
360+
ret = decode(pvr, 0, qfalse, pixel_func);
361+
break;
362+
}
363+
case PVR_IMAGE_TYPE_RECTANGULAR_MM:
364+
{
365+
ret = decode_mm(pvr, decode, pixel_func, qfalse, qfalse);
366+
break;
367+
}
368+
default:
369+
{
370+
ri.Error(ERR_DROP, "LoadPVR: unsupported image type 0x%02x (%s)", image_type, name);
371+
break;
152372
}
153373
}
154374

155375
// clean up
156376
ri.FS_FreeFile(buffer);
157377

378+
// something failed
379+
if (!ret)
380+
return;
381+
158382
// return stuff
159-
*pic = (byte *)rgba;
383+
*pic = ret;
160384
if (width)
161385
*width = pvr->width;
162386
if (height)

0 commit comments

Comments
 (0)