/* Texture twiddler/detwiddler for PowerVR (c)2000 Dan Potter Greets to PlanetWeb ;-) */ #include #include /* NOTES - Twiddled textures must be sizes that are powers of 2 (64, 128, 256, etc) and the x and y sizes must be identical. - Algorithm: Recursively subdivide the picture in two (in each direction) and call the blocks in the reverse-N order. When the size of the block is one, start reading/writing pixels. - To DECODE twiddled format, read pixels linearly and write them back in the twiddled format. To ENCODE twiddled format, read pixels in twiddled form and write linearly. - I LOVE recursive algorithms! ;-) */ /* Size of the texture */ int imgsize; /* Linear I/O pointer */ int ptr = 0; /* Twiddled texture */ unsigned short *twiddled = NULL; /* Normal texture */ unsigned short *detwiddled = NULL; /* Linear read: used for decoding */ unsigned short read_pixel() { return twiddled[ptr++]; } /* Linear write: used for encoding */ void write_pixel(unsigned short pixel) { twiddled[ptr++] = pixel; } void subdivide_and_move(int x1, int y1, int size, int op) { if (size == 1) { if (op == 0) { /* Decode */ detwiddled[y1*imgsize+x1] = read_pixel(); } else { /* Encode */ write_pixel(detwiddled[y1*imgsize+x1]); } } else { int ns = size/2; subdivide_and_move(x1, y1, ns, op); subdivide_and_move(x1, y1+ns, ns, op); subdivide_and_move(x1+ns, y1, ns, op); subdivide_and_move(x1+ns, y1+ns, ns, op); } } /* Sorry, we don't have general PVRT/GBIX parsing right now, so if you want to use this, you'll need to make your own parsing/dumping.. This main() is setup to do a decode. */ int main() { FILE *f; int x, y; /* Set to the size of your texture */ imgsize = 256; twiddled = malloc(imgsize*imgsize*2); detwiddled = malloc(imgsize*imgsize*2); /* Input texture filename */ f = fopen("input.pvr", "r"); fseek(f, 32, SEEK_SET); fread(twiddled, imgsize*imgsize*2, 1, f); fclose(f); /* Decode mode */ subdivide_and_move(0, 0, imgsize, 0); /* Output texture filename */ f = fopen("output.rgb", "w"); /* This loop converts from ARGB4444 into RGBA8888. This is mostly useful for usage with the "convert" program from ImageMagick. */ for (y=0; y> (11-3)) & (0x1f<<3); int g = (v >> (5-2)) & (0x3f<<2); int b = (v << 3) & (0x1f<<3); */ // ARGB4444 /*int a = (v >> (12-4)) & 0xf0; int r = (v >> (8-4)) & 0xf0; int g = (v >> (4-4)) & 0xf0; int b = (v << 4) & 0xf0;*/ // ARGB1555 int a = (v & (1<<15)) ? 0xff : 0; int r = (v >> (10-3)) & 0xf8; int g = (v >> (5-3)) & 0xf8; int b = (v << 3) & 0xf8; v = (a << 24) | (b << 16) | (g << 8) | (r << 0); fwrite(&v, 4, 1, f); } } fclose(f); return 0; }