From 926b0a639ae3e059a41f0dad02dfbc32a7fcfdbc Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 15 Sep 2015 08:29:57 +0200 Subject: [PATCH] implemented basic read/write of xbox textures --- librw.sln | 13 ++ src/d3d.cpp | 266 +++++++++++++++------ src/d3d8.cpp | 6 +- src/image.cpp | 33 ++- src/rwd3d.h | 17 +- src/rwobjects.h | 12 + src/rwxbox.h | 25 ++ src/xbox.cpp | 444 +++++++++++++++++++++++++++++++++++- tools/txdwrite/txdwrite.cpp | 50 ++++ 9 files changed, 781 insertions(+), 85 deletions(-) create mode 100644 tools/txdwrite/txdwrite.cpp diff --git a/librw.sln b/librw.sln index 4af86ec..bf1fb90 100644 --- a/librw.sln +++ b/librw.sln @@ -21,6 +21,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "insttest", "tools\insttest\ EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d9", "tools\d3d9\d3d9.vcxproj", "{E5D477C8-4CAF-43BF-B7E3-6689503D469F}" + ProjectSection(ProjectDependencies) = postProject + {30552BB0-3B19-49A4-ABF4-87CF68AF9E38} = {30552BB0-3B19-49A4-ABF4-87CF68AF9E38} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txdwrite", "tools\txdwrite\txdwrite.vcxproj", "{403C35A9-6D06-4261-B305-9ED000F00136}" + ProjectSection(ProjectDependencies) = postProject + {30552BB0-3B19-49A4-ABF4-87CF68AF9E38} = {30552BB0-3B19-49A4-ABF4-87CF68AF9E38} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -53,6 +61,11 @@ Global {E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Debug|Win32.Build.0 = Debug|Win32 {E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|Win32.ActiveCfg = Release|Win32 {E5D477C8-4CAF-43BF-B7E3-6689503D469F}.Release|Win32.Build.0 = Release|Win32 + {403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|Win32.ActiveCfg = Debug - null|Win32 + {403C35A9-6D06-4261-B305-9ED000F00136}.Debug - null|Win32.Build.0 = Debug - null|Win32 + {403C35A9-6D06-4261-B305-9ED000F00136}.Debug|Win32.ActiveCfg = Debug|Win32 + {403C35A9-6D06-4261-B305-9ED000F00136}.Release|Win32.ActiveCfg = Release|Win32 + {403C35A9-6D06-4261-B305-9ED000F00136}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/d3d.cpp b/src/d3d.cpp index 0c1dbc4..3b26093 100644 --- a/src/d3d.cpp +++ b/src/d3d.cpp @@ -18,8 +18,166 @@ namespace d3d { #ifdef RW_D3D9 IDirect3DDevice9 *device = NULL; +#else +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ + ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 )) +enum { + D3DFMT_UNKNOWN = 0, + + D3DFMT_R8G8B8 = 20, + D3DFMT_A8R8G8B8 = 21, + D3DFMT_X8R8G8B8 = 22, + D3DFMT_R5G6B5 = 23, + D3DFMT_X1R5G5B5 = 24, + D3DFMT_A1R5G5B5 = 25, + D3DFMT_A4R4G4B4 = 26, + D3DFMT_R3G3B2 = 27, + D3DFMT_A8 = 28, + D3DFMT_A8R3G3B2 = 29, + D3DFMT_X4R4G4B4 = 30, + D3DFMT_A2B10G10R10 = 31, + D3DFMT_A8B8G8R8 = 32, + D3DFMT_X8B8G8R8 = 33, + D3DFMT_G16R16 = 34, + D3DFMT_A2R10G10B10 = 35, + D3DFMT_A16B16G16R16 = 36, + + D3DFMT_A8P8 = 40, + D3DFMT_P8 = 41, + + D3DFMT_L8 = 50, + D3DFMT_A8L8 = 51, + D3DFMT_A4L4 = 52, + + D3DFMT_V8U8 = 60, + D3DFMT_L6V5U5 = 61, + D3DFMT_X8L8V8U8 = 62, + D3DFMT_Q8W8V8U8 = 63, + D3DFMT_V16U16 = 64, + D3DFMT_A2W10V10U10 = 67, + + D3DFMT_UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'), + D3DFMT_R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'), + D3DFMT_YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'), + D3DFMT_G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'), + D3DFMT_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'), + D3DFMT_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'), + D3DFMT_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'), + D3DFMT_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'), + D3DFMT_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'), + + D3DFMT_D16_LOCKABLE = 70, + D3DFMT_D32 = 71, + D3DFMT_D15S1 = 73, + D3DFMT_D24S8 = 75, + D3DFMT_D24X8 = 77, + D3DFMT_D24X4S4 = 79, + D3DFMT_D16 = 80, + + D3DFMT_D32F_LOCKABLE = 82, + D3DFMT_D24FS8 = 83, + + // d3d9ex only + /* Z-Stencil formats valid for CPU access */ + D3DFMT_D32_LOCKABLE = 84, + D3DFMT_S8_LOCKABLE = 85, + + D3DFMT_L16 = 81, + + D3DFMT_VERTEXDATA =100, + D3DFMT_INDEX16 =101, + D3DFMT_INDEX32 =102, + + D3DFMT_Q16W16V16U16 =110, + + D3DFMT_MULTI2_ARGB8 = MAKEFOURCC('M','E','T','1'), + + // Floating point surface formats + + // s10e5 formats (16-bits per channel) + D3DFMT_R16F = 111, + D3DFMT_G16R16F = 112, + D3DFMT_A16B16G16R16F = 113, + + // IEEE s23e8 formats (32-bits per channel) + D3DFMT_R32F = 114, + D3DFMT_G32R32F = 115, + D3DFMT_A32B32G32R32F = 116, + + D3DFMT_CxV8U8 = 117, + + // d3d9ex only + // Monochrome 1 bit per pixel format + D3DFMT_A1 = 118, + // 2.8 biased fixed point + D3DFMT_A2B10G10R10_XR_BIAS = 119, + // Binary format indicating that the data has no inherent type + D3DFMT_BINARYBUFFER = 199, +}; #endif +// stolen from d3d8to9 +static uint32 +calculateTextureSize(uint32 width, uint32 height, uint32 depth, uint32 format) +{ +#define D3DFMT_W11V11U10 65 + switch(format){ + default: + case D3DFMT_UNKNOWN: + return 0; + case D3DFMT_R3G3B2: + case D3DFMT_A8: + case D3DFMT_P8: + case D3DFMT_L8: + case D3DFMT_A4L4: + return width * height * depth; + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_A8R3G3B2: + case D3DFMT_X4R4G4B4: + case D3DFMT_A8P8: + case D3DFMT_A8L8: + case D3DFMT_V8U8: + case D3DFMT_L6V5U5: + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D15S1: + case D3DFMT_D16: + case D3DFMT_UYVY: + case D3DFMT_YUY2: + return width * 2 * height * depth; + case D3DFMT_R8G8B8: + return width * 3 * height * depth; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A2B10G10R10: + case D3DFMT_A8B8G8R8: + case D3DFMT_X8B8G8R8: + case D3DFMT_G16R16: + case D3DFMT_X8L8V8U8: + case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + case D3DFMT_W11V11U10: + case D3DFMT_A2W10V10U10: + case D3DFMT_D32: + case D3DFMT_D24S8: + case D3DFMT_D24X8: + case D3DFMT_D24X4S4: + return width * 4 * height * depth; + case D3DFMT_DXT1: + assert(depth <= 1); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 8; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + case D3DFMT_DXT4: + case D3DFMT_DXT5: + assert(depth <= 1); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 16; + } +} + int vertFormatMap[] = { -1, VERT_FLOAT2, VERT_FLOAT3, -1, VERT_ARGB }; @@ -101,15 +259,43 @@ unlockVertices(void *vertexBuffer) } void* -createTexture(int32 width, int32 height, int32 levels, uint32 format) +createTexture(int32 width, int32 height, int32 numlevels, uint32 format) { #ifdef RW_D3D9 IDirect3DTexture9 *tex; - device->CreateTexture(width, height, levels, 0, + device->CreateTexture(width, height, numlevels, 0, (D3DFORMAT)format, D3DPOOL_MANAGED, &tex, NULL); return tex; #else - assert(0 && "only supported with RW_D3D9"); + int32 w = width; + int32 h = height; + int32 size = 0; + for(int32 i = 0; i < numlevels; i++){ + size += calculateTextureSize(w, h, 1, format); + w /= 2; + if(w == 0) w = 1; + h /= 2; + if(h == 0) h = 1; + } + uint8 *data = new uint8[sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1)+size]; + RasterLevels *levels = (RasterLevels*)data; + data += sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1); + levels->numlevels = numlevels; + levels->format = format; + w = width; + h = height; + for(int32 i = 0; i < numlevels; i++){ + levels->levels[i].width = w; + levels->levels[i].height = h; + levels->levels[i].data = data; + levels->levels[i].size = calculateTextureSize(w, h, 1, format); + data += levels->levels[i].size; + w /= 2; + if(w == 0) w = 1; + h /= 2; + if(h == 0) h = 1; + } + return levels; #endif } @@ -122,7 +308,8 @@ lockTexture(void *texture, int32 level) tex->LockRect(level, &lr, 0, 0); return (uint8*)lr.pBits; #else - assert(0 && "only supported with RW_D3D9"); + RasterLevels *levels = (RasterLevels*)texture; + return levels->levels[level].data; #endif } @@ -185,8 +372,9 @@ makeNativeRaster(Raster *raster) uint32 format = formatMap[(raster->format >> 8) & 0xF]; ras->format = 0; ras->hasAlpha = alphaMap[(raster->format >> 8) & 0xF]; + int32 levels = Raster::calculateNumLevels(raster->width, raster->height); ras->texture = createTexture(raster->width, raster->width, - raster->format & Raster::MIPMAP ? 0 : 1, + raster->format & Raster::MIPMAP ? levels : 1, format); assert((raster->flags & (Raster::PAL4 | Raster::PAL8)) == 0); } @@ -213,71 +401,11 @@ getNumLevels(Raster *raster) IDirect3DTexture9 *tex = (IDirect3DTexture9*)ras->texture; return tex->GetLevelCount(); #else - assert(0 && "only supported with RW_D3D9"); + RasterLevels *levels = (RasterLevels*)ras->texture; + return levels->numlevels; #endif } -// stolen from d3d8to9 -uint32 -calculateTextureSize(uint32 width, uint32 height, uint32 depth, uint32 format) -{ -#define D3DFMT_W11V11U10 65 - switch(format){ - default: - case D3DFMT_UNKNOWN: - return 0; - case D3DFMT_R3G3B2: - case D3DFMT_A8: - case D3DFMT_P8: - case D3DFMT_L8: - case D3DFMT_A4L4: - return width * height * depth; - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: - case D3DFMT_A1R5G5B5: - case D3DFMT_A4R4G4B4: - case D3DFMT_A8R3G3B2: - case D3DFMT_X4R4G4B4: - case D3DFMT_A8P8: - case D3DFMT_A8L8: - case D3DFMT_V8U8: - case D3DFMT_L6V5U5: - case D3DFMT_D16_LOCKABLE: - case D3DFMT_D15S1: - case D3DFMT_D16: - case D3DFMT_UYVY: - case D3DFMT_YUY2: - return width * 2 * height * depth; - case D3DFMT_R8G8B8: - return width * 3 * height * depth; - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: - case D3DFMT_A2B10G10R10: - case D3DFMT_A8B8G8R8: - case D3DFMT_X8B8G8R8: - case D3DFMT_G16R16: - case D3DFMT_X8L8V8U8: - case D3DFMT_Q8W8V8U8: - case D3DFMT_V16U16: - case D3DFMT_W11V11U10: - case D3DFMT_A2W10V10U10: - case D3DFMT_D32: - case D3DFMT_D24S8: - case D3DFMT_D24X8: - case D3DFMT_D24X4S4: - return width * 4 * height * depth; - case D3DFMT_DXT1: - assert(depth <= 1); - return ((width + 3) >> 2) * ((height + 3) >> 2) * 8; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - case D3DFMT_DXT4: - case D3DFMT_DXT5: - assert(depth <= 1); - return ((width + 3) >> 2) * ((height + 3) >> 2) * 16; - } -} - int32 getLevelSize(Raster *raster, int32 level) { @@ -288,10 +416,12 @@ getLevelSize(Raster *raster, int32 level) tex->GetLevelDesc(level, &desc); return calculateTextureSize(desc.Width, desc.Height, 1, desc.Format); #else - assert(0 && "only supported with RW_D3D9"); + RasterLevels *levels = (RasterLevels*)ras->texture; + return levels->levels[level].size; #endif } + static void* createNativeRaster(void *object, int32 offset, int32) { diff --git a/src/d3d8.cpp b/src/d3d8.cpp index 50de84b..92d9cc9 100644 --- a/src/d3d8.cpp +++ b/src/d3d8.cpp @@ -419,7 +419,7 @@ readNativeTexture(Stream *stream) ras->format = dxtMap[compression-1]; ras->hasAlpha = hasAlpha; ras->texture = createTexture(raster->width, raster->width, - raster->format & Raster::MIPMAP ? 0 : 1, + raster->format & Raster::MIPMAP ? numLevels : 1, ras->format); raster->flags &= ~0x80; }else @@ -432,7 +432,7 @@ readNativeTexture(Stream *stream) uint32 size; uint8 *data; - for(uint32 i = 0; i < numLevels; i++){ + for(int32 i = 0; i < numLevels; i++){ size = stream->readU32(); if(i < raster->getNumLevels()){ data = raster->lock(i); @@ -493,7 +493,7 @@ writeNativeTexture(Texture *tex, Stream *stream) uint32 size; uint8 *data; - for(uint32 i = 0; i < numLevels; i++){ + for(int32 i = 0; i < numLevels; i++){ size = getLevelSize(raster, i); stream->writeU32(size); data = raster->lock(i); diff --git a/src/image.cpp b/src/image.cpp index 714b007..44a5888 100755 --- a/src/image.cpp +++ b/src/image.cpp @@ -10,6 +10,7 @@ #include "rwpipeline.h" #include "rwobjects.h" #include "rwd3d.h" +#include "rwxbox.h" #include "rwd3d8.h" using namespace std; @@ -81,7 +82,6 @@ uint32 TexDictionary::streamGetSize(void) { uint32 size = 12 + 4; - Texture *tex; for(Texture *tex = this->first; tex; tex = tex->next) size += 12 + tex->streamGetSizeNative(); size += 12 + this->streamGetPluginSize(); @@ -210,6 +210,8 @@ Texture::streamReadNative(Stream *stream) { if(rw::platform == PLATFORM_D3D8) return d3d8::readNativeTexture(stream); + if(rw::platform == PLATFORM_XBOX) + return xbox::readNativeTexture(stream); assert(0 && "unsupported platform"); return NULL; } @@ -219,6 +221,8 @@ Texture::streamWriteNative(Stream *stream) { if(this->raster->platform == PLATFORM_D3D8) d3d8::writeNativeTexture(this, stream); + else if(this->raster->platform == PLATFORM_XBOX) + xbox::writeNativeTexture(this, stream); else assert(0 && "unsupported platform"); } @@ -228,6 +232,8 @@ Texture::streamGetSizeNative(void) { if(this->raster->platform == PLATFORM_D3D8) return d3d8::getSizeNativeTexture(this); + if(this->raster->platform == PLATFORM_XBOX) + return xbox::getSizeNativeTexture(this); assert(0 && "unsupported platform"); return 0; } @@ -530,6 +536,8 @@ Raster::Raster(int32 width, int32 height, int32 depth, int32 format, int32 platf if(this->platform == PLATFORM_D3D8 || this->platform == PLATFORM_D3D9) d3d::makeNativeRaster(this); + if(this->platform == PLATFORM_XBOX) + xbox::makeNativeRaster(this); this->constructPlugins(); } @@ -543,18 +551,23 @@ Raster::~Raster(void) uint8* Raster::lock(int32 level) { - if(this->platform == PLATFORM_D3D8 || + if(this->platform == PLATFORM_D3D8 || this->platform == PLATFORM_D3D9) return d3d::lockRaster(this, level); + if(this->platform == PLATFORM_XBOX) + return xbox::lockRaster(this, level); assert(0 && "unsupported raster platform"); + return NULL; } void Raster::unlock(int32 level) { - if(this->platform == PLATFORM_D3D8 || + if(this->platform == PLATFORM_D3D8 || this->platform == PLATFORM_D3D9) d3d::unlockRaster(this, level); + else if(this->platform == PLATFORM_XBOX) + xbox::unlockRaster(this, level); else assert(0 && "unsupported raster platform"); } @@ -562,13 +575,25 @@ Raster::unlock(int32 level) int32 Raster::getNumLevels(void) { - if(this->platform == PLATFORM_D3D8 || + if(this->platform == PLATFORM_D3D8 || this->platform == PLATFORM_D3D9) return d3d::getNumLevels(this); + if(this->platform == PLATFORM_XBOX) + return xbox::getNumLevels(this); assert(0 && "unsupported raster platform"); return 1; } +int32 +Raster::calculateNumLevels(int32 width, int32 height) +{ + int32 size = width >= height ? width : height; + int32 n; + for(n = 0; size != 0; n++) + size /= 2; + return n; +} + // BAD BAD BAD BAD Raster* Raster::createFromImage(Image *image) diff --git a/src/rwd3d.h b/src/rwd3d.h index 910c0e6..95b8035 100644 --- a/src/rwd3d.h +++ b/src/rwd3d.h @@ -72,20 +72,21 @@ void deleteObject(void *object); // Native Raster -struct D3dRaster { - void *texture; // IDirect3DTexture9 +void makeNativeRaster(Raster *raster); +uint8 *lockRaster(Raster *raster, int32 level); +void unlockRaster(Raster *raster, int32 level); +int32 getNumLevels(Raster *raster); +int32 getLevelSize(Raster *raster, int32 level); + +struct D3dRaster +{ + void *texture; void *palette; uint32 format; bool32 hasAlpha; }; extern int32 nativeRasterOffset; - -void makeNativeRaster(Raster *raster); -uint8 *lockRaster(Raster *raster, int32 level); -void unlockRaster(Raster *raster, int32 level); -int32 getNumLevels(Raster *raster); -int32 getLevelSize(Raster *raster, int32 level); void registerNativeRaster(void); } diff --git a/src/rwobjects.h b/src/rwobjects.h index 8165774..41f3e59 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -95,6 +95,17 @@ struct Image Image *readTGA(const char *filename); void writeTGA(Image *image, const char *filename); +// used to emulate d3d and xbox textures +struct RasterLevels +{ + int32 numlevels; + uint32 format; + struct Level { + int32 width, height, size; + uint8 *data; + } levels[1]; // 0 is illegal :/ +}; + struct Raster : PluginBase { int32 platform; @@ -114,6 +125,7 @@ struct Raster : PluginBase uint8 *lock(int32 level); void unlock(int32 level); int32 getNumLevels(void); + static int32 calculateNumLevels(int32 width, int32 height); enum Format { DEFAULT = 0, diff --git a/src/rwxbox.h b/src/rwxbox.h index ebea38a..f6b2d43 100644 --- a/src/rwxbox.h +++ b/src/rwxbox.h @@ -66,5 +66,30 @@ uint32 getVertexFmtStride(uint32 fmt); void registerVertexFormatPlugin(void); +// Native Texture and Raster + +void makeNativeRaster(Raster *raster); +uint8 *lockRaster(Raster *raster, int32 level); +void unlockRaster(Raster *raster, int32 level); +int32 getNumLevels(Raster *raster); +int32 getLevelSize(Raster *raster, int32 level); + +Texture *readNativeTexture(Stream *stream); +void writeNativeTexture(Texture *tex, Stream *stream); +uint32 getSizeNativeTexture(Texture *tex); + +struct XboxRaster +{ + void *texture; + void *palette; + uint32 format; + bool32 hasAlpha; + bool32 unknownFlag; +// int32 compression; +}; + +extern int32 nativeRasterOffset; +void registerNativeRaster(void); + } } diff --git a/src/xbox.cpp b/src/xbox.cpp index d6cb4b5..2aba5a9 100644 --- a/src/xbox.cpp +++ b/src/xbox.cpp @@ -16,6 +16,97 @@ using namespace std; namespace rw { namespace xbox { +enum { + D3DFMT_UNKNOWN = 0xFFFFFFFF, + + /* Swizzled formats */ + + D3DFMT_A8R8G8B8 = 0x00000006, + D3DFMT_X8R8G8B8 = 0x00000007, + D3DFMT_R5G6B5 = 0x00000005, + D3DFMT_R6G5B5 = 0x00000027, + D3DFMT_X1R5G5B5 = 0x00000003, + D3DFMT_A1R5G5B5 = 0x00000002, + D3DFMT_A4R4G4B4 = 0x00000004, + D3DFMT_A8 = 0x00000019, + D3DFMT_A8B8G8R8 = 0x0000003A, + D3DFMT_B8G8R8A8 = 0x0000003B, + D3DFMT_R4G4B4A4 = 0x00000039, + D3DFMT_R5G5B5A1 = 0x00000038, + D3DFMT_R8G8B8A8 = 0x0000003C, + D3DFMT_R8B8 = 0x00000029, + D3DFMT_G8B8 = 0x00000028, + + D3DFMT_P8 = 0x0000000B, + + D3DFMT_L8 = 0x00000000, + D3DFMT_A8L8 = 0x0000001A, + D3DFMT_AL8 = 0x00000001, + D3DFMT_L16 = 0x00000032, + + D3DFMT_V8U8 = 0x00000028, + D3DFMT_L6V5U5 = 0x00000027, + D3DFMT_X8L8V8U8 = 0x00000007, + D3DFMT_Q8W8V8U8 = 0x0000003A, + D3DFMT_V16U16 = 0x00000033, + + D3DFMT_D16_LOCKABLE = 0x0000002C, + D3DFMT_D16 = 0x0000002C, + D3DFMT_D24S8 = 0x0000002A, + D3DFMT_F16 = 0x0000002D, + D3DFMT_F24S8 = 0x0000002B, + + /* YUV formats */ + + D3DFMT_YUY2 = 0x00000024, + D3DFMT_UYVY = 0x00000025, + + /* Compressed formats */ + + D3DFMT_DXT1 = 0x0000000C, + D3DFMT_DXT2 = 0x0000000E, + D3DFMT_DXT3 = 0x0000000E, + D3DFMT_DXT4 = 0x0000000F, + D3DFMT_DXT5 = 0x0000000F, + + /* Linear formats */ + + D3DFMT_LIN_A1R5G5B5 = 0x00000010, + D3DFMT_LIN_A4R4G4B4 = 0x0000001D, + D3DFMT_LIN_A8 = 0x0000001F, + D3DFMT_LIN_A8B8G8R8 = 0x0000003F, + D3DFMT_LIN_A8R8G8B8 = 0x00000012, + D3DFMT_LIN_B8G8R8A8 = 0x00000040, + D3DFMT_LIN_G8B8 = 0x00000017, + D3DFMT_LIN_R4G4B4A4 = 0x0000003E, + D3DFMT_LIN_R5G5B5A1 = 0x0000003D, + D3DFMT_LIN_R5G6B5 = 0x00000011, + D3DFMT_LIN_R6G5B5 = 0x00000037, + D3DFMT_LIN_R8B8 = 0x00000016, + D3DFMT_LIN_R8G8B8A8 = 0x00000041, + D3DFMT_LIN_X1R5G5B5 = 0x0000001C, + D3DFMT_LIN_X8R8G8B8 = 0x0000001E, + + D3DFMT_LIN_A8L8 = 0x00000020, + D3DFMT_LIN_AL8 = 0x0000001B, + D3DFMT_LIN_L16 = 0x00000035, + D3DFMT_LIN_L8 = 0x00000013, + + D3DFMT_LIN_V16U16 = 0x00000036, + D3DFMT_LIN_V8U8 = 0x00000017, + D3DFMT_LIN_L6V5U5 = 0x00000037, + D3DFMT_LIN_X8L8V8U8 = 0x0000001E, + D3DFMT_LIN_Q8W8V8U8 = 0x00000012, + + D3DFMT_LIN_D24S8 = 0x0000002E, + D3DFMT_LIN_F24S8 = 0x0000002F, + D3DFMT_LIN_D16 = 0x00000030, + D3DFMT_LIN_F16 = 0x00000031, + + D3DFMT_VERTEXDATA = 100, + D3DFMT_INDEX16 = 101, +}; + void* destroyNativeData(void *object, int32, int32) { @@ -472,8 +563,8 @@ skinUninstanceCB(Geometry *geo, InstanceDataHeader *header) memcpy(skin->inverseMatrices, invMats, skin->numBones*64); delete[] data; - for(int32 i = 0; i < skin->numUsedBones; i++) - skin->usedBones[i] = natskin->table1[i]; + for(int32 j = 0; j < skin->numUsedBones; j++) + skin->usedBones[j] = natskin->table1[j]; float *weights = skin->weights; uint8 *indices = skin->indices; @@ -623,5 +714,354 @@ registerVertexFormatPlugin(void) getSizeVertexFmt); } +// Native Texture and Raster + +static uint32 +calculateTextureSize(uint32 width, uint32 height, uint32 depth, uint32 format) +{ +#define D3DFMT_W11V11U10 65 + switch(format){ + default: + case D3DFMT_UNKNOWN: + return 0; + case D3DFMT_A8: + case D3DFMT_P8: + case D3DFMT_L8: + case D3DFMT_AL8: + case D3DFMT_LIN_A8: + case D3DFMT_LIN_AL8: + case D3DFMT_LIN_L8: + return width * height * depth; + case D3DFMT_R5G6B5: + case D3DFMT_R6G5B5: + case D3DFMT_X1R5G5B5: + case D3DFMT_A1R5G5B5: + case D3DFMT_A4R4G4B4: + case D3DFMT_R4G4B4A4: + case D3DFMT_R5G5B5A1: + case D3DFMT_R8B8: + case D3DFMT_G8B8: + case D3DFMT_A8L8: + case D3DFMT_L16: + //case D3DFMT_V8U8: + //case D3DFMT_L6V5U5: + case D3DFMT_D16_LOCKABLE: + //case D3DFMT_D16: + case D3DFMT_F16: + case D3DFMT_YUY2: + case D3DFMT_UYVY: + case D3DFMT_LIN_A1R5G5B5: + case D3DFMT_LIN_A4R4G4B4: + case D3DFMT_LIN_G8B8: + case D3DFMT_LIN_R4G4B4A4: + case D3DFMT_LIN_R5G5B5A1: + case D3DFMT_LIN_R5G6B5: + case D3DFMT_LIN_R6G5B5: + case D3DFMT_LIN_R8B8: + case D3DFMT_LIN_X1R5G5B5: + case D3DFMT_LIN_A8L8: + case D3DFMT_LIN_L16: + //case D3DFMT_LIN_V8U8: + //case D3DFMT_LIN_L6V5U5: + case D3DFMT_LIN_D16: + case D3DFMT_LIN_F16: + return width * 2 * height * depth; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + case D3DFMT_A8B8G8R8: + case D3DFMT_B8G8R8A8: + case D3DFMT_R8G8B8A8: + //case D3DFMT_X8L8V8U8: + //case D3DFMT_Q8W8V8U8: + case D3DFMT_V16U16: + case D3DFMT_D24S8: + case D3DFMT_F24S8: + case D3DFMT_LIN_A8B8G8R8: + case D3DFMT_LIN_A8R8G8B8: + case D3DFMT_LIN_B8G8R8A8: + case D3DFMT_LIN_R8G8B8A8: + case D3DFMT_LIN_X8R8G8B8: + case D3DFMT_LIN_V16U16: + //case D3DFMT_LIN_X8L8V8U8: + //case D3DFMT_LIN_Q8W8V8U8: + case D3DFMT_LIN_D24S8: + case D3DFMT_LIN_F24S8: + return width * 4 * height * depth; + case D3DFMT_DXT1: + assert(depth <= 1); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 8; + //case D3DFMT_DXT2: + case D3DFMT_DXT3: + //case D3DFMT_DXT4: + case D3DFMT_DXT5: + assert(depth <= 1); + return ((width + 3) >> 2) * ((height + 3) >> 2) * 16; + } +} + + +int32 nativeRasterOffset; + +void* +createTexture(int32 width, int32 height, int32 numlevels, uint32 format) +{ + int32 w = width; + int32 h = height; + int32 size = 0; + for(int32 i = 0; i < numlevels; i++){ + size += calculateTextureSize(w, h, 1, format); + w /= 2; + if(w == 0) w = 1; + h /= 2; + if(h == 0) h = 1; + } + size = (size+3)&~3; + uint8 *data = new uint8[sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1)+size]; + RasterLevels *levels = (RasterLevels*)data; + data += sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1); + levels->numlevels = numlevels; + levels->format = format; + w = width; + h = height; + for(int32 i = 0; i < numlevels; i++){ + levels->levels[i].width = w; + levels->levels[i].height = h; + levels->levels[i].data = data; + levels->levels[i].size = calculateTextureSize(w, h, 1, format); + data += levels->levels[i].size; + w /= 2; + if(w == 0) w = 1; + h /= 2; + if(h == 0) h = 1; + } + return levels; +} + +void +makeNativeRaster(Raster *raster) +{ + static uint32 formatMap[] = { + D3DFMT_UNKNOWN, + D3DFMT_A1R5G5B5, + D3DFMT_R5G6B5, + D3DFMT_A4R4G4B4, + D3DFMT_L8, + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN, + D3DFMT_X1R5G5B5, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN, + D3DFMT_UNKNOWN + }; + static bool32 alphaMap[] = { + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, 0, 0, + 0, + 0, 0, 0, 0, 0 + }; + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + if(raster->flags & 0x80) + return; + uint32 format = formatMap[(raster->format >> 8) & 0xF]; + ras->format = 0; + ras->hasAlpha = alphaMap[(raster->format >> 8) & 0xF]; + int32 levels = Raster::calculateNumLevels(raster->width, raster->height); + ras->texture = createTexture(raster->width, raster->width, + raster->format & Raster::MIPMAP ? levels : 1, + format); + assert((raster->flags & (Raster::PAL4 | Raster::PAL8)) == 0); +} + +uint8* +lockRaster(Raster *raster, int32 level) +{ + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + RasterLevels *levels = (RasterLevels*)ras->texture; + return levels->levels[level].data; +} + +void +unlockRaster(Raster *raster, int32 level) +{ +} + +int32 +getNumLevels(Raster *raster) +{ + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + RasterLevels *levels = (RasterLevels*)ras->texture; + return levels->numlevels; +} + +int32 +getLevelSize(Raster *raster, int32 level) +{ + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + RasterLevels *levels = (RasterLevels*)ras->texture; + return levels->levels[level].size; +} + +Texture* +readNativeTexture(Stream *stream) +{ + uint32 version; + assert(findChunk(stream, ID_STRUCT, NULL, &version)); + assert(version >= 0x34001); + assert(stream->readU32() == PLATFORM_XBOX); + Texture *tex = new Texture; + + // Texture + tex->filterAddressing = stream->readU32(); + stream->read(tex->name, 32); + stream->read(tex->mask, 32); + + // Raster + int32 format = stream->readI32(); + bool32 hasAlpha = stream->readI16(); + bool32 unknownFlag = stream->readI16(); + int32 width = stream->readU16(); + int32 height = stream->readU16(); + int32 depth = stream->readU8(); + int32 numLevels = stream->readU8(); + int32 type = stream->readU8(); + int32 compression = stream->readU8(); + int32 totalSize = stream->readI32(); + + assert(unknownFlag == 0); + Raster *raster; + if(compression){ + raster = new Raster(width, height, depth, format | type | 0x80, PLATFORM_XBOX); + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + ras->format = compression; + ras->hasAlpha = hasAlpha; + ras->texture = createTexture(raster->width, raster->width, + raster->format & Raster::MIPMAP ? numLevels : 1, + ras->format); + raster->flags &= ~0x80; + }else + raster = new Raster(width, height, depth, format | type, PLATFORM_XBOX); + tex->raster = raster; + + if(raster->format & (Raster::PAL4 | Raster::PAL8)) + assert(0 && "don't support palettes"); + + // exploit the fact that mipmaps are allocated consecutively + uint8 *data = raster->lock(0); + stream->read(data, totalSize); + raster->unlock(0); + + tex->streamReadPlugins(stream); + return tex; +} + +void +writeNativeTexture(Texture *tex, Stream *stream) +{ + int32 chunksize = getSizeNativeTexture(tex); + int32 plgsize = tex->streamGetPluginSize(); + writeChunkHeader(stream, ID_TEXTURENATIVE, chunksize); + writeChunkHeader(stream, ID_STRUCT, chunksize-24-plgsize); + stream->writeU32(PLATFORM_XBOX); + + // Texture + stream->writeU32(tex->filterAddressing); + stream->write(tex->name, 32); + stream->write(tex->mask, 32); + + // Raster + Raster *raster = tex->raster; + XboxRaster *ras = PLUGINOFFSET(XboxRaster, raster, nativeRasterOffset); + int32 numLevels = raster->getNumLevels(); + stream->writeI32(raster->format); + stream->writeI16(ras->hasAlpha); + stream->writeI16(ras->unknownFlag); + stream->writeU16(raster->width); + stream->writeU16(raster->height); + stream->writeU8(raster->depth); + stream->writeU8(numLevels); + stream->writeU8(raster->type); + stream->writeU8(ras->format); + + int32 totalSize = 0; + for(int32 i = 0; i < numLevels; i++) + totalSize += getLevelSize(tex->raster, i); + totalSize = (totalSize+3)&~3; + stream->writeI32(totalSize); + + // exploit the fact that mipmaps are allocated consecutively + uint8 *data = raster->lock(0); + stream->write(data, totalSize); + raster->unlock(0); + + tex->streamWritePlugins(stream); +} + +uint32 +getSizeNativeTexture(Texture *tex) +{ + uint32 size = 12 + 72 + 16 + 4; + int32 levels = tex->raster->getNumLevels(); + for(int32 i = 0; i < levels; i++) + size += getLevelSize(tex->raster, i); + size = (size+3)&~3; + size += 12 + tex->streamGetPluginSize(); + return size; +} + +static void* +createNativeRaster(void *object, int32 offset, int32) +{ + XboxRaster *raster = PLUGINOFFSET(XboxRaster, object, offset); + raster->texture = NULL; + raster->palette = NULL; + raster->format = 0; + raster->hasAlpha = 0; + raster->unknownFlag = 0; +// raster->compression = 0; + return object; +} + +static void* +destroyNativeRaster(void *object, int32 offset, int32) +{ + // TODO: + return object; +} + +static void* +copyNativeRaster(void *dst, void *, int32 offset, int32) +{ + XboxRaster *raster = PLUGINOFFSET(XboxRaster, dst, offset); + raster->texture = NULL; + raster->palette = NULL; + raster->format = 0; + raster->hasAlpha = 0; + raster->unknownFlag = 0; +// raster->compression = 0; + return dst; +} + +void +registerNativeRaster(void) +{ + nativeRasterOffset = Raster::registerPlugin(sizeof(XboxRaster), + 0x12340000 | PLATFORM_XBOX, + createNativeRaster, + destroyNativeRaster, + copyNativeRaster); +} + + } } diff --git a/tools/txdwrite/txdwrite.cpp b/tools/txdwrite/txdwrite.cpp new file mode 100644 index 0000000..626caab --- /dev/null +++ b/tools/txdwrite/txdwrite.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace rw; + +int +main(int argc, char *argv[]) +{ + gta::attachPlugins(); + rw::xbox::registerNativeRaster(); + rw::d3d::registerNativeRaster(); + +// rw::version = 0x33002; +// rw::platform = rw::PLATFORM_PS2; +// rw::platform = rw::PLATFORM_OGL; + rw::platform = rw::PLATFORM_XBOX; +// rw::platform = rw::PLATFORM_D3D8; +// rw::platform = rw::PLATFORM_D3D9; + + if(argc < 2){ + printf("usage: %s in.txd\n", argv[0]); + return 0; + } + + rw::StreamFile in; + if(in.open(argv[1], "rb") == NULL){ + printf("couldn't open file\n"); + return 1; + } + rw::findChunk(&in, rw::ID_TEXDICTIONARY, NULL, NULL); + rw::TexDictionary *txd; + txd = rw::TexDictionary::streamRead(&in); + assert(txd); + in.close(); + rw::currentTexDictionary = txd; + + rw::StreamFile out; + out.open("out.txd", "wb"); + txd->streamWrite(&out); + out.close(); + + return 0; +}