implemented basic read/write of xbox textures

This commit is contained in:
aap 2015-09-15 08:29:57 +02:00
parent b39d9d2b89
commit 926b0a639a
9 changed files with 781 additions and 85 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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);
}

View File

@ -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<Raster>
{
int32 platform;
@ -114,6 +125,7 @@ struct Raster : PluginBase<Raster>
uint8 *lock(int32 level);
void unlock(int32 level);
int32 getNumLevels(void);
static int32 calculateNumLevels(int32 width, int32 height);
enum Format {
DEFAULT = 0,

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,50 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <new>
#include <rw.h>
#include <src/gtaplg.h>
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;
}