#include #include #include "rwcore.h" #define PS2IDENT 0x00325350 /* '\0', '2', 'S', 'P' */ RwUInt32 platform; RwTexDictionary *RwCurrentTexDictionary; RwTexDictionary *RwTexDictionaryStreamRead(RwStream *txd) { RwUInt32 i; RwTexDictionary *td; RwUInt16 tmp; RwChunkHeaderInfo rwh; td = RwTexDictionaryCreate(); RwStreamReadChunkHeaderInfo(txd, &rwh); if (rwh.type != rwID_TEXDICTIONARY) { fprintf(stderr, "Not a Texture Dictionary\n"); exit(1); } RwStreamSkip(txd, 12); RwStreamRead(txd, &tmp, sizeof(RwUInt16)); td->numTextures = tmp; RwStreamSkip(txd, 2); td->texture = new RwTexture[td->numTextures]; for (i = 0; i < td->numTextures; i++) { RwStreamSkip(txd, 12); RwStreamReadChunkHeaderInfo(txd, &rwh); RwStreamRead(txd, &platform, sizeof(RwUInt32)); if (platform != PS2IDENT && platform != rwID_PCD3D8 && platform != rwID_PCD3D9) { fprintf(stderr, "Unsupported platform %X\n", platform); exit(2); } if (platform == PS2IDENT) RwTextureReadPs2(txd, &td->texture[i]); else RwTextureReadPc(txd, &td->texture[i], rwh.length); RwStreamReadChunkHeaderInfo(txd, &rwh); RwStreamSkip(txd, rwh.length); } return td; } void unswizzle8(RwUInt8 *indices, RwUInt8 *rawindices, RwUInt32 Width, RwUInt32 Height) { RwUInt32 x, y; 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(RwUInt8 *indices, RwUInt32 Width, RwUInt32 Height) { RwUInt32 i; RwUInt8 tmp; RwUInt8 map[4] = { 0, 16, 8, 24 }; for (i = 0; i < Width*Height; i++) { tmp = indices[i]; indices[i] = (tmp & ~24) | map[(tmp & 24) >> 3]; } } void RwTextureReadPc(RwStream *txd, RwTexture *tex, RwUInt32 size) { RwUInt32 i; RwUInt8 ind; RwUInt32 end; RwUInt32 picsize; RwUInt8 pal[256*4]; RwUInt8 tmpb[4]; RwChar fourcc[4]; end = size - 4 + RwStreamTell(txd); RwStreamRead(txd, &tex->FilterFlags, sizeof(RwUInt32)); RwStreamRead(txd, &tex->Name, 32); RwStreamRead(txd, &tex->MaskName, 32); RwStreamRead(txd, &tex->RasterFormat, sizeof(RwUInt32)); if (platform == rwID_PCD3D9) RwStreamRead(txd, &fourcc, 4*sizeof(RwChar)); else RwStreamRead(txd, &tex->HasAlpha, sizeof(RwUInt32)); RwStreamRead(txd, &tex->width, sizeof(RwUInt16)); RwStreamRead(txd, &tex->height, sizeof(RwUInt16)); tex->width &= 0x0000FFFF; tex->height &= 0x0000FFFF; RwStreamRead(txd, tmpb, 4*sizeof(RwUInt8)); tex->depth = tmpb[0]; tex->MipmapCount = tmpb[1]; tex->Compression = tmpb[3]; if (platform == rwID_PCD3D9) { if (tex->Compression == 8) tex->HasAlpha = 0; else tex->HasAlpha = 1; tex->Compression = fourcc[3] - '0'; } tex->Size = NULL; picsize = tex->width * tex->height; if ((tex->RasterFormat & 0x2000) != 0) RwStreamRead(txd, pal, 256*4); tex->Data = new RwUInt8[picsize*4]; tex->Data_a = new RwUInt8[picsize*4]; RwStreamSkip(txd, 4); // RwStreamRead(txd, &tex->size1, sizeof(RwUInt32)); if ((tex->RasterFormat & 0x2000) != 0) { for (i = 0; i < picsize; i++) { RwStreamRead(txd, &ind, 1); tex->Data[i*4] = tex->Data_a[i*4] = pal[ind*4]; tex->Data[i*4+1] = tex->Data_a[i*4+1] = pal[ind*4+1]; tex->Data[i*4+2] = tex->Data_a[i*4+2] = pal[ind*4+2]; tex->Data_a[i*4+3] = pal[ind*4+3]; tex->Data[i*4+3] = 0xFF; } tex->depth = 32; tex->reversed = 0; } else if (tex->depth == 32) { RwStreamRead(txd, tex->Data_a, picsize*4); tex->reversed = 1; tex->Data = NULL; } else if (tex->depth == 16) { RwStreamRead(txd, tex->Data_a, picsize*2); tex->Data = NULL; } else { fprintf(stderr, "%d bits not yet supported\n", tex->depth); exit(3); } RwStreamSeek(txd, end); } void RwTextureReadPs2(RwStream *txd, RwTexture *tex) { RwUInt32 i; RwUInt32 picsize; RwUInt8 ind; RwUInt8 *rawindices, *indices, *pal; RwUInt32 psize; RwUInt32 buffer[3]; RwChunkHeaderInfo rwh; RwUInt32 end; tex->reversed = 0; RwStreamRead(txd, &tex->FilterFlags, sizeof(RwUInt32)); RwStreamReadChunkHeaderInfo(txd, &rwh); RwStreamRead(txd, tex->Name, rwh.length); RwStreamReadChunkHeaderInfo(txd, &rwh); RwStreamRead(txd, tex->MaskName, rwh.length); if (tex->MaskName[0] == '\0') tex->HasAlpha = 0; else tex->HasAlpha = 1; RwStreamSkip(txd, 24); RwStreamRead(txd, buffer, 3*sizeof(RwUInt32)); tex->width = buffer[0]; tex->height = buffer[1]; tex->depth = buffer[2]; RwStreamSkip(txd, 52); RwStreamReadChunkHeaderInfo(txd, &rwh); end = rwh.length + RwStreamTell(txd); #if VERBOSE // cout << "Reading: " << ras->Name << " " << ras->width; // cout << " " << ras->height << " " << ras->depth << endl; #endif RwStreamSkip(txd, 80); /* Pixels/Indices */ picsize = tex->width * tex->height; if (tex->depth == 8) { rawindices = new RwUInt8[picsize]; indices = new RwUInt8[picsize]; RwStreamRead(txd, rawindices, picsize); unswizzle8(indices, rawindices, tex->width, tex->height); delete[] rawindices; correctindices(indices, tex->width, tex->height); // tex->Data = indices; } else if (tex->depth == 4) { rawindices = new RwUInt8[picsize]; indices = new RwUInt8[picsize]; for (i = 0; i < picsize; i += 2) { RwStreamRead(txd, &ind, 1); rawindices[i+1] = ind >> 4; rawindices[i] = ind & 0x0F; } if (rwh.version != 0x310) unswizzle8(indices, rawindices, tex->width,tex->height); else memcpy(indices, rawindices, picsize); delete[] rawindices; // tex->Data = indices; } else if (tex->depth == 16) { tex->Data = new RwUInt8[picsize*4]; tex->Data_a = new RwUInt8[picsize*4]; for (i = 0; i < picsize*4; i += 4) { RwInt16 tmp; RwStreamRead(txd, &tmp, sizeof(RwInt16)); tex->Data[i+2] = tex->Data_a[i+2] = (tmp & 0x1F) * 8; tmp >>= 5; tex->Data[i+1] = tex->Data_a[i+1] = (tmp & 0x1F) * 8; tmp >>= 5; tex->Data[i] = tex->Data_a[i] = (tmp & 0x1F) * 8; tmp >>= 5; tex->Data_a[i+3] = (tmp & 0x01) * 8; if (tex->Data_a[i+3] != 0xFF) tex->HasAlpha = 1; tex->Data[i+3] = 0xFF; } tex->depth = 32; tex->reversed = 1; tex->Palette = NULL; } else if (tex->depth == 32) { tex->Data = new RwUInt8[picsize*4]; tex->Data_a = new RwUInt8[picsize*4]; for (i = 0; i < picsize*4; i += 4) { RwUInt8 tmp[4]; RwStreamRead(txd, tmp, 4); tex->Data[i] = tex->Data_a[i] = tmp[2]; tex->Data[i+1] = tex->Data_a[i+1] = tmp[1]; tex->Data[i+2] = tex->Data_a[i+2] = tmp[0]; tex->Data_a[i+3] = tmp[3]; if (tex->Data_a[i+3] != 0) { tex->Data_a[i+3] *= 2; tex->Data_a[i+3]-- ; } if (tex->Data_a[i+3] != 0xFF) tex->HasAlpha = 1; tex->Data[i+3] = 0xFF; } tex->reversed = 1; tex->Palette = NULL; } else { fprintf(stderr, "Unknown Depth: %d\n%s\n", tex->depth, tex->Name); exit(4); } /* Read palette */ if (tex->depth == 8 || tex->depth == 4) { RwStreamSkip(txd, 80); /* Don't know what's happening there */ if (rwh.version != 0x310 && tex->depth == 4 && tex->width <= 16) RwStreamSkip(txd, picsize/2); if (rwh.version != 0x310 && tex->depth == 4 && tex->width <= 8) RwStreamSkip(txd, picsize); if (tex->depth == 8) psize = 256; else psize = 16; pal = new RwUInt8[psize*4]; RwStreamRead(txd, pal, psize*4); // tex->Palette = pal; // tex->PalLength = psize; } if (rwh.version != 0x310 && tex->depth == 4) RwStreamSkip(txd, 32); /* See above */ // if (rwh.version != 0x310 && tex->depth == 4 && tex->width == 16) // RwStreamSeek(txd, RwStreamTell(txd)-4); /* Convert to 32 bit picture */ if (tex->depth == 4 || tex->depth == 8) { // if (tex->depth == 8) { // if (0) { tex->Data = new RwUInt8[picsize*4]; tex->Data_a = new RwUInt8[picsize*4]; for (i = 0; i < picsize; i++) { tex->Data[i*4]=tex->Data_a[i*4]=pal[indices[i]*4+2]; tex->Data[i*4+1]=tex->Data_a[i*4+1]=pal[indices[i]*4+1]; tex->Data[i*4+2]=tex->Data_a[i*4+2]=pal[indices[i]*4]; tex->Data_a[i*4+3] = pal[indices[i]*4+3]; if (tex->Data_a[i*4+3] != 0) { tex->Data_a[i*4+3] *= 2; tex->Data_a[i*4+3]-- ; } if (tex->Data_a[i*4+3] != 0xFF) tex->HasAlpha = 1; tex->Data[i*4+3] = 0xFF; } tex->depth = 32; tex->reversed = 1; delete[] pal; delete[] indices; } tex->RasterFormat = 0; tex->MipmapCount = 0; tex->Compression = 0; tex->Size = NULL; RwStreamSeek(txd, end); } RwTexDictionary *RwTexDictionarySetCurrent(RwTexDictionary *TexDict) { return RwCurrentTexDictionary = TexDict; } RwTexDictionary *RwTexDictionaryGetCurrent() { return RwCurrentTexDictionary; } RwTexture *RwTexDictionaryFindNamedTexture(RwTexDictionary *TexDict, const RwChar *Name) { RwUInt32 i; for (i = 0; i < TexDict->numTextures; i++) #ifdef _WIN32 if (lstrcmpiA(TexDict->texture[i].Name, Name) == 0) #else if (strcasecmp(TexDict->texture[i].Name, Name) == 0) #endif return &TexDict->texture[i]; return NULL; } RwTexDictionary *RwTexDictionaryCreate() { RwTexDictionary *td; td = new RwTexDictionary; td->texture = NULL; td->numTextures = 0; return td; } void RwTexDictionaryDestroy(RwTexDictionary *td) { RwUInt32 i; if (td == NULL) return; for (i = 0; i < td->numTextures; i++) { delete[] td->texture[i].Data; delete[] td->texture[i].Data_a; delete[] td->texture[i].Size; } delete[] td->texture; delete td; }