#include #include #include #include "../rw.h" #include "txd.h" #define PC 8 #define SA 9 #define PS2 0x00325350 #define XBOX 5 short getword(FILE *file) { short temp; fread(&temp, 2, 1, file); return temp; } int getdword(FILE *file) { int temp; fread(&temp, 4, 1, file); return temp; } void unswizzle8(unsigned char *indices, unsigned char *rawindices, int width, int height) { int y, x; for (y = 0; y < height; y++) for (x = 0; x < width; x++) { int block_loc = (y&(~0x0F))*width + (x&(~0x0F))*2; unsigned int swap_sel = (((y+2)>>2)&0x01)*4; int ypos = (((y&(~3))>>1) + (y&1))&0x07; int column_loc = ypos*width*2 + ((x+swap_sel)&0x07)*4; int byte_sum = ((y>>1)&1) + ((x>>2)&2); int swizzled = block_loc + column_loc + byte_sum; indices[y*width+x] = rawindices[swizzled]; } } void correctindices(unsigned char *indices, int width, int height) { int i; char temp; char map[4] = {0, 16, 8, 24}; for (i = 0; i < width*height; i++) { temp = indices[i]; indices[i] = (temp & ~24) | map[(temp & 24) >> 3]; } } int ReadTxd(int start, FILE *txd, Texture **tl) { int i; int texcount; int platform; rwheader rwh; Texture *texlist; fseek(txd, start, 0); rwh = ReadHeader(txd); /* Texture Dictionary */ if (rwh.type != 0x16) { *tl = NULL; printf("Not a txd file\n"); return 0; } ReadHeader(txd); /* Struct */ texcount = getword(txd); fseek(txd, 2, SEEK_CUR); texlist = malloc(texcount*sizeof(Texture)); for (i = 0; i < texcount; i++) { ReadHeader(txd); /* Texture Native */ ReadHeader(txd); /* Struct */ fread(&platform, 4, 1, txd); if (platform != PS2 /* && platform != PC */) { fprintf(stderr, "Unsupported platform %X\n", platform); exit(1); } /* Read Texture Native */ if (platform == PS2) ReadPS2Txd(txd, &texlist[i]); else ReadPCTxd(txd, &texlist[i]); /* Skip (empty) Extension */ rwh = ReadHeader(txd); fseek(txd, rwh.size, SEEK_CUR); } /* Skip (empty) Extension */ ReadHeader(txd); *tl = texlist; return texcount; } void ReadPCTxd(FILE *txd, Texture *texlist) { int i; texlist->filterflags = getdword(txd); fread(texlist->name, 32, 1, txd); fread(texlist->alpha, 32, 1, txd); texlist->rasterformat = getdword(txd); switch (texlist->rasterformat & 0xf000) { case 0x1000: break; case 0x2000: texlist->channels = 4; break; case 0x4000: texlist->channels = 4; break; case 0x8000: break; default: break; } switch (texlist->rasterformat & 0x0f00) { /* 1 5 5 5 */ case 0x100: texlist->channels = 4; break; /* 5 6 5 */ case 0x200: texlist->channels = 3; break; /* 4 4 4 4 */ case 0x300: texlist->channels = 4; break; /* gray scale */ case 0x400: texlist->channels = 1; break; /* 8 8 8 8 */ case 0x500: texlist->channels = 4; break; /* 8 8 8 */ case 0x600: texlist->channels = 3; break; /* 5 5 5 */ case 0xA00: texlist->channels = 3; break; default: fprintf(stderr, "Unknown raster format\n"); exit(1); } texlist->hasalpha = getdword(txd); texlist->width = getword(txd); texlist->height = getword(txd); texlist->bpp = getc(txd); texlist->mipmapcount = getc(txd); fseek(txd, 1, SEEK_CUR); texlist->compression = getc(txd); texlist->size = malloc(texlist->mipmapcount * sizeof(int)); texlist->data = malloc(texlist->mipmapcount * sizeof(int *)); for (i = 0; i < texlist->mipmapcount; i++) { texlist->size[i] = getdword(txd); texlist->data[i] = malloc(texlist->size[i]); fread(texlist->data[i], texlist->size[i], 1, txd); } } void ReadPS2Txd(FILE *txd, Texture *texlist) { int j; int picsize; int psize; unsigned char doubleindex; char tex[32], alpha[32]; unsigned char *rawindices, *indices, *pal; rwheader rwh; indices = NULL; pal = NULL; texlist->data = malloc(sizeof(int *)); texlist->data_a = malloc(sizeof(int *)); texlist->filterflags = getdword(txd); rwh = ReadHeader(txd); /* Texture name */ fread(tex, rwh.size, 1, txd); strcpy(texlist->name, tex); rwh = ReadHeader(txd); /* Alpha name */ fread(alpha, rwh.size, 1, txd); strcpy(texlist->alpha, alpha); if (alpha[0] != '\0') texlist->hasalpha = 1; else texlist->hasalpha = 0; ReadHeader(txd); /* Struct */ ReadHeader(txd); /* Struct */ texlist->width = getdword(txd); texlist->height = getdword(txd); texlist->bpp = getdword(txd); /* if (alpha[0] != '\0' || (rwh.version == 0x310 && texlist->bpp == 32)) { if (texlist->bpp == 32) { strcpy(alpha, tex); strcat(alpha, "a"); } texlist->hasalpha = 1; strcpy(texlist->alpha, alpha); } */ fseek(txd, 52, SEEK_CUR); ReadHeader(txd); fseek(txd, 80, SEEK_CUR); /* Pixel/Indices */ picsize = texlist->width * texlist->height; if (texlist->bpp == 8) { rawindices = malloc(picsize); indices = malloc(picsize); fread(rawindices, picsize, 1, txd); unswizzle8(indices, rawindices, texlist->width,texlist->height); free(rawindices); correctindices(indices, texlist->width, texlist->height); } else if (texlist->bpp == 4) { rawindices = malloc(picsize); indices = malloc(picsize); for (j = 0; j < picsize; j += 2) { doubleindex = getc(txd); rawindices[j+1] = doubleindex >> 4; rawindices[j] = doubleindex & 0x0F; } if (rwh.version != 0x310) unswizzle8(indices, rawindices, texlist->width, texlist->height); else memcpy(indices, rawindices, picsize); free(rawindices); } else if (texlist->bpp == 16) { texlist->data[0] = malloc(picsize*4); texlist->data_a[0] = malloc(picsize*4); for (j = 0; j < picsize*4; j += 4) { short temppixel; temppixel = getword(txd); /* 5 R 5 G 5 B 1 A */ texlist->data[0][j] = texlist->data_a[0][j] = (temppixel &0x1F) * 8; temppixel >>= 5; texlist->data[0][j+1] = texlist->data_a[0][j+1] = (temppixel &0x1F) * 8; temppixel >>= 5; texlist->data[0][j+2] = texlist->data_a[0][j+2] = (temppixel &0x1F) * 8; temppixel >>= 5; texlist->data_a[0][j+3] = (temppixel &0x01) * 8; texlist->data[0][j+3] = 0xFF; } /* It's now a 32bit picture */ texlist->bpp = 32; texlist->channels = 4; } else if (texlist->bpp == 32) { texlist->data[0] = malloc(picsize*4); texlist->data_a[0] = malloc(picsize*4); for (j = 0; j < picsize*4; j += 4) { texlist->data[0][j] = texlist->data_a[0][j] = getc(txd); texlist->data[0][j+1] = texlist->data_a[0][j+1] = getc(txd); texlist->data[0][j+2] = texlist->data_a[0][j+2] = getc(txd); texlist->data_a[0][j+3] = getc(txd); texlist->data[0][j+3] = 0xFF; } // fread(texlist->data[0], picsize*4, 1, txd); texlist->channels = 4; } else { fprintf(stderr, "Unknown depth %d:\n", texlist->bpp); fprintf(stderr, "%s\n", texlist->name); exit(2); } if (texlist->bpp == 8 || texlist->bpp == 4) { fseek(txd, 80, SEEK_CUR); /* Weird, possibly swizzled differently */ if (texlist->bpp == 4 && texlist->width == 16) fseek(txd, 132, SEEK_CUR); /* Palette */ if (texlist->bpp == 8) psize = 256; else psize = 16; pal = malloc(psize*4); fread(pal, psize*4, 1, txd); } if (rwh.version != 0x310 && texlist->bpp == 4) fseek(txd, 32, SEEK_CUR); if (rwh.version != 0x310 && texlist->bpp == 4 && texlist->width == 16) fseek(txd, -4, SEEK_CUR); if (texlist->bpp == 4 || texlist->bpp == 8) { // if (texlist->hasalpha) // texlist->channels = 4; // else // texlist->channels = 3; // texlist->data[0] = malloc(picsize*texlist->channels); texlist->data[0] = malloc(picsize*4); texlist->data_a[0] = malloc(picsize*4); for (j = 0; j < picsize; j++) { /* texlist->data[0][j*texlist->channels] = pal[indices[j]*4]; texlist->data[0][j*texlist->channels+1] = pal[indices[j]*4+1]; texlist->data[0][j*texlist->channels+2] = pal[indices[j]*4+2]; if (texlist->channels == 4) texlist->data[0][j*texlist->channels+3] = pal[indices[j]*4+3]; */ texlist->data[0][j*4] = texlist->data_a[0][j*4] = pal[indices[j]*4]; texlist->data[0][j*4+1] = texlist->data_a[0][j*4+1] = pal[indices[j]*4+1]; texlist->data[0][j*4+2] = texlist->data_a[0][j*4+2] = pal[indices[j]*4+2]; texlist->data_a[0][j*4+3] = pal[indices[j]*4+3]; texlist->data[0][j*4+3] = 0xFF; } /* It's now a 32bit picture */ texlist->bpp = 32; free(pal); free(indices); } texlist->rasterformat = 0; texlist->mipmapcount = 0; texlist->compression = 0; texlist->size = NULL; } void DestroyTxd(Texture *texlist, int texcount) { int i, j; for (i = 0; i < texcount; i++) { for (j = 0; j < texlist[i].mipmapcount+1; j++) { free(texlist[i].data[j]); free(texlist[i].data_a[j]); } free(texlist[i].data); free(texlist[i].data_a); free(texlist[i].size); } free(texlist); }