summaryrefslogtreecommitdiff
path: root/src/d3d/d3d8.cpp
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
committerclaude-bot <[email protected]>2026-07-13 12:40:03 +0000
commit847962910f0bff071f3bf07c9abb87764fb6cac3 (patch)
treeddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /src/d3d/d3d8.cpp
downloadlibrw-847962910f0bff071f3bf07c9abb87764fb6cac3.tar.gz
librw-847962910f0bff071f3bf07c9abb87764fb6cac3.zip
Import aap/librw @ masterHEADmaster
Snapshot for re3/reVC vendoring, per @lzcnt. Source: https://github.com/aap/librw (master).
Diffstat (limited to 'src/d3d/d3d8.cpp')
-rw-r--r--src/d3d/d3d8.cpp678
1 files changed, 678 insertions, 0 deletions
diff --git a/src/d3d/d3d8.cpp b/src/d3d/d3d8.cpp
new file mode 100644
index 0000000..671948f
--- /dev/null
+++ b/src/d3d/d3d8.cpp
@@ -0,0 +1,678 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define WITH_D3D
+#include "../rwbase.h"
+#include "../rwerror.h"
+#include "../rwplg.h"
+#include "../rwpipeline.h"
+#include "../rwobjects.h"
+#include "../rwengine.h"
+#include "rwd3d.h"
+#include "rwd3d8.h"
+
+#include "rwd3dimpl.h"
+
+#define PLUGIN_ID 2
+
+namespace rw {
+namespace d3d8 {
+using namespace d3d;
+
+static void*
+driverOpen(void *o, int32, int32)
+{
+ engine->driver[PLATFORM_D3D8]->defaultPipeline = makeDefaultPipeline();
+
+ engine->driver[PLATFORM_D3D8]->rasterNativeOffset = nativeRasterOffset;
+ engine->driver[PLATFORM_D3D8]->rasterCreate = rasterCreate;
+ engine->driver[PLATFORM_D3D8]->rasterLock = rasterLock;
+ engine->driver[PLATFORM_D3D8]->rasterUnlock = rasterUnlock;
+ engine->driver[PLATFORM_D3D8]->rasterNumLevels = rasterNumLevels;
+ engine->driver[PLATFORM_D3D8]->imageFindRasterFormat = imageFindRasterFormat;
+ engine->driver[PLATFORM_D3D8]->rasterFromImage = rasterFromImage;
+ engine->driver[PLATFORM_D3D8]->rasterToImage = rasterToImage;
+ return o;
+}
+
+static void*
+driverClose(void *o, int32, int32)
+{
+ return o;
+}
+
+void
+registerPlatformPlugins(void)
+{
+ Driver::registerPlugin(PLATFORM_D3D8, 0, PLATFORM_D3D8,
+ driverOpen, driverClose);
+ // shared between D3D8 and 9
+ if(nativeRasterOffset == 0)
+ registerNativeRaster();
+}
+
+uint32
+makeFVFDeclaration(uint32 flags, int32 numTex)
+{
+ uint32 fvf = 0x2;
+ if(flags & Geometry::NORMALS)
+ fvf |= 0x10;
+ if(flags & Geometry::PRELIT)
+ fvf |= 0x40;
+ fvf |= numTex << 8;
+ return fvf;
+}
+
+int32
+getStride(uint32 flags, int32 numTex)
+{
+ int32 stride = 12;
+ if(flags & Geometry::NORMALS)
+ stride += 12;;
+ if(flags & Geometry::PRELIT)
+ stride += 4;
+ stride += numTex*8;
+ return stride;
+}
+
+void*
+destroyNativeData(void *object, int32, int32)
+{
+ Geometry *geometry = (Geometry*)object;
+ if(geometry->instData == nil ||
+ geometry->instData->platform != PLATFORM_D3D8)
+ return object;
+ InstanceDataHeader *header =
+ (InstanceDataHeader*)geometry->instData;
+ geometry->instData = nil;
+ InstanceData *inst = header->inst;
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ destroyIndexBuffer(inst->indexBuffer);
+ destroyVertexBuffer(inst->vertexBuffer);
+ inst++;
+ }
+ rwFree(header->inst);
+ rwFree(header);
+ return object;
+}
+
+Stream*
+readNativeData(Stream *stream, int32, void *object, int32, int32)
+{
+ ASSERTLITTLE;
+ Geometry *geometry = (Geometry*)object;
+ uint32 platform;
+ if(!findChunk(stream, ID_STRUCT, nil, nil)){
+ RWERROR((ERR_CHUNK, "STRUCT"));
+ return nil;
+ }
+ platform = stream->readU32();
+ if(platform != PLATFORM_D3D8){
+ RWERROR((ERR_PLATFORM, platform));
+ return nil;
+ }
+ InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY);
+ geometry->instData = header;
+ header->platform = PLATFORM_D3D8;
+
+ int32 size = stream->readI32();
+ uint8 *data = rwNewT(uint8, size, MEMDUR_FUNCTION | ID_GEOMETRY);
+ stream->read8(data, size);
+ uint8 *p = data;
+ header->serialNumber = *(uint16*)p; p += 2;
+ header->numMeshes = *(uint16*)p; p += 2;
+ header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);
+
+ InstanceData *inst = header->inst;
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ inst->minVert = *(uint32*)p; p += 4;
+ inst->stride = *(uint32*)p; p += 4;
+ inst->numVertices = *(uint32*)p; p += 4;
+ inst->numIndices = *(uint32*)p; p += 4;
+ uint32 matid = *(uint32*)p; p += 4;
+ inst->material = geometry->matList.materials[matid];
+ inst->vertexShader = *(uint32*)p; p += 4;
+ inst->primType = *(uint32*)p; p += 4;
+ inst->indexBuffer = nil; p += 4;
+ inst->vertexBuffer = nil; p += 4;
+ inst->baseIndex = 0; p += 4;
+ inst->vertexAlpha = *p++;
+ inst->managed = 0; p++;
+ inst->remapped = 0; p++; // TODO: really unused? and what's that anyway?
+ inst++;
+ }
+ rwFree(data);
+
+ inst = header->inst;
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ assert(inst->indexBuffer == nil);
+ inst->indexBuffer = createIndexBuffer(inst->numIndices*2, false);
+ uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
+ stream->read8(indices, 2*inst->numIndices);
+ unlockIndices(inst->indexBuffer);
+
+ inst->managed = 1;
+ assert(inst->vertexBuffer == nil);
+ inst->vertexBuffer = createVertexBuffer(inst->stride*inst->numVertices, 0, false);
+ uint8 *verts = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
+ stream->read8(verts, inst->stride*inst->numVertices);
+ unlockVertices(inst->vertexBuffer);
+
+ inst++;
+ }
+ return stream;
+}
+
+Stream*
+writeNativeData(Stream *stream, int32 len, void *object, int32, int32)
+{
+ ASSERTLITTLE;
+ Geometry *geometry = (Geometry*)object;
+ writeChunkHeader(stream, ID_STRUCT, len-12);
+ if(geometry->instData == nil ||
+ geometry->instData->platform != PLATFORM_D3D8)
+ return stream;
+ stream->writeU32(PLATFORM_D3D8);
+ InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
+
+ int32 size = 4 + geometry->meshHeader->numMeshes*0x2C;
+ uint8 *data = rwNewT(uint8, size, MEMDUR_FUNCTION | ID_GEOMETRY);
+ stream->writeI32(size);
+ uint8 *p = data;
+ *(uint16*)p = header->serialNumber; p += 2;
+ *(uint16*)p = header->numMeshes; p += 2;
+
+ InstanceData *inst = header->inst;
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ *(uint32*)p = inst->minVert; p += 4;
+ *(uint32*)p = inst->stride; p += 4;
+ *(uint32*)p = inst->numVertices; p += 4;
+ *(uint32*)p = inst->numIndices; p += 4;
+ int32 matid = geometry->matList.findIndex(inst->material);
+ *(int32*)p = matid; p += 4;
+ *(uint32*)p = inst->vertexShader; p += 4;
+ *(uint32*)p = inst->primType; p += 4;
+ *(uint32*)p = 0; p += 4; // index buffer
+ *(uint32*)p = 0; p += 4; // vertex buffer
+ *(uint32*)p = inst->baseIndex; p += 4;
+ *p++ = inst->vertexAlpha;
+ *p++ = inst->managed;
+ *p++ = inst->remapped;
+ inst++;
+ }
+ stream->write8(data, size);
+ rwFree(data);
+
+ inst = header->inst;
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
+ stream->write8(indices, 2*inst->numIndices);
+ unlockIndices(inst->indexBuffer);
+
+ uint8 *verts = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
+ stream->write8(verts, inst->stride*inst->numVertices);
+ unlockVertices(inst->vertexBuffer);
+ inst++;
+ }
+ return stream;
+}
+
+int32
+getSizeNativeData(void *object, int32, int32)
+{
+ Geometry *geometry = (Geometry*)object;
+ if(geometry->instData == nil ||
+ geometry->instData->platform != PLATFORM_D3D8)
+ return 0;
+
+ InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData;
+ InstanceData *inst = header->inst;
+ int32 size = 12 + 4 + 4 + 4 + header->numMeshes*0x2C;
+ for(int32 i = 0; i < header->numMeshes; i++){
+ size += inst->numIndices*2 + inst->numVertices*inst->stride;
+ inst++;
+ }
+ return size;
+}
+
+void
+registerNativeDataPlugin(void)
+{
+ Geometry::registerPlugin(0, ID_NATIVEDATA,
+ nil, destroyNativeData, nil);
+ Geometry::registerPluginStream(ID_NATIVEDATA,
+ readNativeData,
+ writeNativeData,
+ getSizeNativeData);
+}
+
+
+static void
+instance(rw::ObjPipeline *rwpipe, Atomic *atomic)
+{
+ ObjPipeline *pipe = (ObjPipeline*)rwpipe;
+ Geometry *geo = atomic->geometry;
+ // TODO: allow for REINSTANCE
+ if(geo->instData)
+ return;
+ InstanceDataHeader *header = rwNewT(InstanceDataHeader, 1, MEMDUR_EVENT | ID_GEOMETRY);
+ MeshHeader *meshh = geo->meshHeader;
+ geo->instData = header;
+ header->platform = PLATFORM_D3D8;
+
+ header->serialNumber = meshh->serialNum;
+ header->numMeshes = meshh->numMeshes;
+ header->inst = rwNewT(InstanceData, header->numMeshes, MEMDUR_EVENT | ID_GEOMETRY);
+
+ InstanceData *inst = header->inst;
+ Mesh *mesh = meshh->getMeshes();
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ findMinVertAndNumVertices(mesh->indices, mesh->numIndices,
+ &inst->minVert, &inst->numVertices);
+ inst->numIndices = mesh->numIndices;
+ inst->material = mesh->material;
+ inst->vertexShader = 0;
+ inst->primType = meshh->flags == 1 ? D3DPT_TRIANGLESTRIP : D3DPT_TRIANGLELIST;
+ inst->vertexBuffer = nil;
+ inst->baseIndex = 0; // (maybe) not used by us
+ inst->vertexAlpha = 0;
+ inst->managed = 0;
+ inst->remapped = 0;
+
+ inst->indexBuffer = createIndexBuffer(inst->numIndices*2, false);
+ uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
+ if(inst->minVert == 0)
+ memcpy(indices, mesh->indices, inst->numIndices*2);
+ else
+ for(int32 j = 0; j < inst->numIndices; j++)
+ indices[j] = mesh->indices[j] - inst->minVert;
+ unlockIndices(inst->indexBuffer);
+
+ pipe->instanceCB(geo, inst);
+ mesh++;
+ inst++;
+ }
+}
+
+static void
+uninstance(rw::ObjPipeline *rwpipe, Atomic *atomic)
+{
+ ObjPipeline *pipe = (ObjPipeline*)rwpipe;
+ Geometry *geo = atomic->geometry;
+ if((geo->flags & Geometry::NATIVE) == 0)
+ return;
+ assert(geo->instData != nil);
+ assert(geo->instData->platform == PLATFORM_D3D8);
+ geo->numTriangles = geo->meshHeader->guessNumTriangles();
+ geo->allocateData();
+ geo->allocateMeshes(geo->meshHeader->numMeshes, geo->meshHeader->totalIndices, 0);
+
+ InstanceDataHeader *header = (InstanceDataHeader*)geo->instData;
+ InstanceData *inst = header->inst;
+ Mesh *mesh = geo->meshHeader->getMeshes();
+ for(uint32 i = 0; i < header->numMeshes; i++){
+ uint16 *indices = lockIndices(inst->indexBuffer, 0, 0, 0);
+ if(inst->minVert == 0)
+ memcpy(mesh->indices, indices, inst->numIndices*2);
+ else
+ for(int32 j = 0; j < inst->numIndices; j++)
+ mesh->indices[j] = indices[j] + inst->minVert;
+ unlockIndices(inst->indexBuffer);
+
+ pipe->uninstanceCB(geo, inst);
+ mesh++;
+ inst++;
+ }
+ geo->generateTriangles();
+ geo->flags &= ~Geometry::NATIVE;
+ destroyNativeData(geo, 0, 0);
+}
+
+static void
+render(rw::ObjPipeline *rwpipe, Atomic *atomic)
+{
+ ObjPipeline *pipe = (ObjPipeline*)rwpipe;
+ Geometry *geo = atomic->geometry;
+ // TODO: allow for REINSTANCE
+ if(geo->instData == nil)
+ pipe->instance(atomic);
+ assert(geo->instData != nil);
+ assert(geo->instData->platform == PLATFORM_D3D8);
+ if(pipe->renderCB)
+ pipe->renderCB(atomic, (InstanceDataHeader*)geo->instData);
+}
+
+void
+ObjPipeline::init(void)
+{
+ this->rw::ObjPipeline::init(PLATFORM_D3D8);
+ this->impl.instance = d3d8::instance;
+ this->impl.uninstance = d3d8::uninstance;
+ this->impl.render = d3d8::render;
+ this->instanceCB = nil;
+ this->uninstanceCB = nil;
+ this->renderCB = nil;
+}
+
+ObjPipeline*
+ObjPipeline::create(void)
+{
+ ObjPipeline *pipe = rwNewT(ObjPipeline, 1, MEMDUR_GLOBAL);
+ pipe->init();
+ return pipe;
+}
+
+void
+defaultInstanceCB(Geometry *geo, InstanceData *inst)
+{
+ inst->vertexShader = makeFVFDeclaration(geo->flags, geo->numTexCoordSets);
+ inst->stride = getStride(geo->flags, geo->numTexCoordSets);
+
+ assert(inst->vertexBuffer == nil);
+ inst->vertexBuffer = createVertexBuffer(inst->numVertices*inst->stride,
+ inst->vertexShader, false);
+ inst->managed = 1;
+
+ uint8 *dst = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
+ instV3d(VERT_FLOAT3, dst,
+ &geo->morphTargets[0].vertices[inst->minVert],
+ inst->numVertices, inst->stride);
+ dst += 12;
+
+ if(geo->flags & Geometry::NORMALS){
+ instV3d(VERT_FLOAT3, dst,
+ &geo->morphTargets[0].normals[inst->minVert],
+ inst->numVertices, inst->stride);
+ dst += 12;
+ }
+
+ inst->vertexAlpha = 0;
+ if(geo->flags & Geometry::PRELIT){
+ inst->vertexAlpha = instColor(VERT_ARGB, dst, &geo->colors[inst->minVert],
+ inst->numVertices, inst->stride);
+ dst += 4;
+ }
+
+ for(int32 i = 0; i < geo->numTexCoordSets; i++){
+ instTexCoords(VERT_FLOAT2, dst, &geo->texCoords[i][inst->minVert],
+ inst->numVertices, inst->stride);
+ dst += 8;
+ }
+ unlockVertices(inst->vertexBuffer);
+}
+
+void
+defaultUninstanceCB(Geometry *geo, InstanceData *inst)
+{
+ uint8 *src = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK);
+ uninstV3d(VERT_FLOAT3,
+ &geo->morphTargets[0].vertices[inst->minVert],
+ src, inst->numVertices, inst->stride);
+ src += 12;
+
+ if(geo->flags & Geometry::NORMALS){
+ uninstV3d(VERT_FLOAT3,
+ &geo->morphTargets[0].normals[inst->minVert],
+ src, inst->numVertices, inst->stride);
+ src += 12;
+ }
+
+ inst->vertexAlpha = 0;
+ if(geo->flags & Geometry::PRELIT){
+ uninstColor(VERT_ARGB, &geo->colors[inst->minVert], src,
+ inst->numVertices, inst->stride);
+ src += 4;
+ }
+
+ for(int32 i = 0; i < geo->numTexCoordSets; i++){
+ uninstTexCoords(VERT_FLOAT2, &geo->texCoords[i][inst->minVert], src,
+ inst->numVertices, inst->stride);
+ src += 8;
+ }
+ unlockVertices(inst->vertexBuffer);
+}
+
+ObjPipeline*
+makeDefaultPipeline(void)
+{
+ ObjPipeline *pipe = ObjPipeline::create();
+ pipe->instanceCB = defaultInstanceCB;
+ pipe->uninstanceCB = defaultUninstanceCB;
+ pipe->renderCB = defaultRenderCB;
+ return pipe;
+}
+
+// Native Texture and Raster
+
+// only handles 4 and 8 bit textures right now
+Raster*
+readAsImage(Stream *stream, int32 width, int32 height, int32 depth, int32 format, int32 numLevels)
+{
+ uint8 palette[256*4];
+ int32 pallen = 0;
+ uint8 *data = nil;
+
+ Image *img = Image::create(width, height, 32);
+ img->allocate();
+
+ if(format & Raster::PAL4){
+ pallen = 16;
+ stream->read8(palette, 4*32);
+ }else if(format & Raster::PAL8){
+ pallen = 256;
+ stream->read8(palette, 4*256);
+ }
+ if(!Raster::formatHasAlpha(format))
+ for(int32 i = 0; i < pallen; i++)
+ palette[i*4+3] = 0xFF;
+
+ Raster *ras = nil;
+
+ for(int i = 0; i < numLevels; i++){
+ uint32 size = stream->readU32();
+
+ // don't read levels that don't exist
+ if(ras && i >= ras->getNumLevels()){
+ stream->seek(size);
+ continue;
+ }
+
+ // one allocation is enough, first level is largest
+ if(data == nil)
+ data = rwNewT(uint8, size, MEMDUR_FUNCTION | ID_IMAGE);
+ stream->read8(data, size);
+
+ if(ras){
+ ras->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
+ img->width = ras->width;
+ img->height = ras->height;
+ img->stride = img->width*img->bpp;
+ }
+
+ if(format & (Raster::PAL4 | Raster::PAL8)){
+ uint8 *idx = data;
+ uint8 *pixels = img->pixels;
+ for(int y = 0; y < img->height; y++){
+ uint8 *line = pixels;
+ for(int x = 0; x < img->width; x++){
+ line[0] = palette[*idx*4+0];
+ line[1] = palette[*idx*4+1];
+ line[2] = palette[*idx*4+2];
+ if(img->bpp > 3)
+ line[3] = palette[*idx*4+3];
+ line += img->bpp;
+ idx++;
+ }
+ pixels += img->stride;
+ }
+ }
+
+ if(ras == nil){
+ // Important to have filled the image with data
+ int32 newformat;
+ Raster::imageFindRasterFormat(img, format&7, &width, &height, &depth, &newformat);
+ newformat |= format & (Raster::MIPMAP | Raster::AUTOMIPMAP);
+ ras = Raster::create(width, height, depth, newformat);
+ ras->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
+ }
+
+ ras->setFromImage(img);
+ ras->unlock(i);
+ }
+
+ rwFree(data);
+ img->destroy();
+ return ras;
+}
+
+Texture*
+readNativeTexture(Stream *stream)
+{
+ uint32 platform;
+ if(!findChunk(stream, ID_STRUCT, nil, nil)){
+ RWERROR((ERR_CHUNK, "STRUCT"));
+ return nil;
+ }
+ platform = stream->readU32();
+ if(platform != PLATFORM_D3D8){
+ RWERROR((ERR_PLATFORM, platform));
+ return nil;
+ }
+ Texture *tex = Texture::create(nil);
+ if(tex == nil)
+ return nil;
+
+ // Texture
+ tex->filterAddressing = stream->readU32();
+ stream->read8(tex->name, 32);
+ stream->read8(tex->mask, 32);
+
+ // Raster
+ uint32 format = stream->readU32();
+ bool32 hasAlpha = stream->readI32();
+ 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 pallength = 0;
+ if(format & Raster::PAL4 || format & Raster::PAL8){
+ pallength = format & Raster::PAL4 ? 32 : 256;
+ if(!d3d::isP8supported){
+ tex->raster = readAsImage(stream, width, height, depth, format|type, numLevels);
+ return tex;
+ }
+ }
+
+ Raster *raster;
+ D3dRaster *ras;
+ if(compression){
+ raster = Raster::create(width, height, depth, format | type | Raster::DONTALLOCATE, PLATFORM_D3D8);
+ ras = GETD3DRASTEREXT(raster);
+ allocateDXT(raster, compression, numLevels, hasAlpha);
+ ras->customFormat = 1;
+ }else{
+ raster = Raster::create(width, height, depth, format | type, PLATFORM_D3D8);
+ ras = GETD3DRASTEREXT(raster);
+ }
+ tex->raster = raster;
+
+ // TODO: check if format supported and convert if necessary
+
+ if(pallength != 0)
+ stream->read8(ras->palette, 4*pallength);
+
+ uint32 size;
+ uint8 *data;
+ for(int32 i = 0; i < numLevels; i++){
+ size = stream->readU32();
+ if(i < raster->getNumLevels()){
+ data = raster->lock(i, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
+ stream->read8(data, size);
+ raster->unlock(i);
+ }else
+ stream->seek(size);
+ }
+ return tex;
+}
+
+void
+writeNativeTexture(Texture *tex, Stream *stream)
+{
+ int32 chunksize = getSizeNativeTexture(tex);
+ writeChunkHeader(stream, ID_STRUCT, chunksize-12);
+ stream->writeU32(PLATFORM_D3D8);
+
+ // Texture
+ stream->writeU32(tex->filterAddressing);
+ stream->write8(tex->name, 32);
+ stream->write8(tex->mask, 32);
+
+ // Raster
+ Raster *raster = tex->raster;
+ D3dRaster *ras = GETD3DRASTEREXT(raster);
+ int32 numLevels = raster->getNumLevels();
+ stream->writeI32(raster->format);
+ stream->writeI32(ras->hasAlpha);
+ stream->writeU16(raster->width);
+ stream->writeU16(raster->height);
+ stream->writeU8(raster->depth);
+ stream->writeU8(numLevels);
+ stream->writeU8(raster->type);
+ int32 compression = 0;
+ if(ras->format)
+ switch(ras->format){
+ case 0x31545844: // DXT1
+ compression = 1;
+ break;
+ case 0x32545844: // DXT2
+ compression = 2;
+ break;
+ case 0x33545844: // DXT3
+ compression = 3;
+ break;
+ case 0x34545844: // DXT4
+ compression = 4;
+ break;
+ case 0x35545844: // DXT5
+ compression = 5;
+ break;
+ }
+ stream->writeU8(compression);
+
+ if(raster->format & Raster::PAL4)
+ stream->write8(ras->palette, 4*32);
+ else if(raster->format & Raster::PAL8)
+ stream->write8(ras->palette, 4*256);
+
+ uint32 size;
+ uint8 *data;
+ for(int32 i = 0; i < numLevels; i++){
+ size = getLevelSize(raster, i);
+ stream->writeU32(size);
+ data = raster->lock(i, Raster::LOCKREAD);
+ stream->write8(data, size);
+ raster->unlock(i);
+ }
+}
+
+uint32
+getSizeNativeTexture(Texture *tex)
+{
+ uint32 size = 12 + 72 + 16;
+ int32 levels = tex->raster->getNumLevels();
+ if(tex->raster->format & Raster::PAL4)
+ size += 4*32;
+ else if(tex->raster->format & Raster::PAL8)
+ size += 4*256;
+ for(int32 i = 0; i < levels; i++)
+ size += 4 + getLevelSize(tex->raster, i);
+ return size;
+}
+
+}
+}