summaryrefslogtreecommitdiff
path: root/src/d3d/d3d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/d3d/d3d.cpp')
-rw-r--r--src/d3d/d3d.cpp1087
1 files changed, 1087 insertions, 0 deletions
diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp
new file mode 100644
index 0000000..f1f5f49
--- /dev/null
+++ b/src/d3d/d3d.cpp
@@ -0,0 +1,1087 @@
+#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 "rwd3dimpl.h"
+
+#define PLUGIN_ID ID_DRIVER
+
+namespace rw {
+namespace d3d {
+
+bool32 isP8supported = 1; // set to 0 when actual d3d device is used
+
+// 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, VERT_FLOAT4, VERT_ARGB, VERT_RGBA /* blend indices */
+};
+
+void*
+createIndexBuffer(uint32 length, bool dynamic)
+{
+#ifdef RW_D3D9
+ IDirect3DIndexBuffer9 *ibuf;
+ if(dynamic)
+ d3ddevice->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &ibuf, 0);
+ else
+ d3ddevice->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0);
+ if(ibuf)
+ d3d9Globals.numIndexBuffers++;
+ return ibuf;
+#else
+ return rwNewT(uint8, length, MEMDUR_EVENT | ID_DRIVER);
+#endif
+}
+
+void
+destroyIndexBuffer(void *indexBuffer)
+{
+#ifdef RW_D3D9
+ if(indexBuffer){
+ if(((IUnknown*)indexBuffer)->Release() != 0)
+ printf("indexBuffer wasn't destroyed\n");
+ d3d9Globals.numIndexBuffers--;
+ }
+#else
+ rwFree(indexBuffer);
+#endif
+}
+
+uint16*
+lockIndices(void *indexBuffer, uint32 offset, uint32 size, uint32 flags)
+{
+ if(indexBuffer == nil)
+ return nil;
+#ifdef RW_D3D9
+ uint16 *indices;
+ IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer;
+ ibuf->Lock(offset, size, (void**)&indices, flags);
+ return indices;
+#else
+ (void)offset;
+ (void)size;
+ (void)flags;
+ return (uint16*)indexBuffer;
+#endif
+}
+
+void
+unlockIndices(void *indexBuffer)
+{
+ if(indexBuffer == nil)
+ return;
+#ifdef RW_D3D9
+ IDirect3DIndexBuffer9 *ibuf = (IDirect3DIndexBuffer9*)indexBuffer;
+ ibuf->Unlock();
+#endif
+}
+
+void*
+createVertexBuffer(uint32 length, uint32 fvf, bool dynamic)
+{
+#ifdef RW_D3D9
+ IDirect3DVertexBuffer9 *vbuf;
+ if(dynamic)
+ d3ddevice->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY|D3DUSAGE_DYNAMIC, fvf, D3DPOOL_DEFAULT, &vbuf, 0);
+ else
+ d3ddevice->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, fvf, D3DPOOL_MANAGED, &vbuf, 0);
+ if(vbuf)
+ d3d9Globals.numVertexBuffers++;
+ return vbuf;
+#else
+ (void)fvf;
+ return rwNewT(uint8, length, MEMDUR_EVENT | ID_DRIVER);
+#endif
+}
+
+void
+destroyVertexBuffer(void *vertexBuffer)
+{
+#ifdef RW_D3D9
+ if(vertexBuffer){
+ if(((IUnknown*)vertexBuffer)->Release() != 0)
+ printf("vertexBuffer wasn't destroyed\n");
+ d3d9Globals.numVertexBuffers--;
+ }
+#else
+ rwFree(vertexBuffer);
+#endif
+}
+
+uint8*
+lockVertices(void *vertexBuffer, uint32 offset, uint32 size, uint32 flags)
+{
+ if(vertexBuffer == nil)
+ return nil;
+#ifdef RW_D3D9
+ uint8 *verts;
+ IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer;
+ vertbuf->Lock(offset, size, (void**)&verts, flags);
+ return verts;
+#else
+ (void)offset;
+ (void)size;
+ (void)flags;
+ return (uint8*)vertexBuffer;
+#endif
+}
+
+void
+unlockVertices(void *vertexBuffer)
+{
+ if(vertexBuffer == nil)
+ return;
+#ifdef RW_D3D9
+ IDirect3DVertexBuffer9 *vertbuf = (IDirect3DVertexBuffer9*)vertexBuffer;
+ vertbuf->Unlock();
+#endif
+}
+
+void*
+createTexture(int32 width, int32 height, int32 numlevels, uint32 usage, uint32 format)
+{
+#ifdef RW_D3D9
+ IDirect3DTexture9 *tex;
+ d3ddevice->CreateTexture(width, height, numlevels, usage,
+ (D3DFORMAT)format, D3DPOOL_MANAGED, &tex, nil);
+ if(tex)
+ d3d9Globals.numTextures++;
+ return tex;
+#else
+ 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 = (uint8*)rwNew(sizeof(RasterLevels)+sizeof(RasterLevels::Level)*(numlevels-1)+size,
+ MEMDUR_EVENT | ID_DRIVER);
+ 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
+}
+
+void
+destroyTexture(void *texture)
+{
+#ifdef RW_D3D9
+ if(texture){
+ if(((IUnknown*)texture)->Release() != 0)
+ printf("texture wasn't destroyed\n");
+ d3d9Globals.numTextures--;
+ }
+#else
+ rwFree(texture);
+#endif
+}
+
+// Native Raster
+
+int32 nativeRasterOffset;
+
+struct RasterFormatInfo
+{
+ uint32 d3dformat;
+ int32 depth;
+ bool32 hasAlpha;
+ uint32 rwFormat;
+};
+
+// indexed directly by RW format
+static RasterFormatInfo formatInfoRW[16] = {
+ { 0, 0, 0, 0},
+ { D3DFMT_A1R5G5B5, 16, 1, Raster::C1555 },
+ { D3DFMT_R5G6B5, 16, 0, Raster::C565 },
+ { D3DFMT_A4R4G4B4, 16, 1, Raster::C4444 },
+ { D3DFMT_L8, 8, 0, Raster::LUM8 },
+ { D3DFMT_A8R8G8B8, 32, 1, Raster::C8888 },
+ { D3DFMT_X8R8G8B8, 32, 0, Raster::C888 },
+ { D3DFMT_D16, 16, 0, Raster::D16 },
+ { D3DFMT_D24X8, 32, 0, Raster::D24 },
+ { D3DFMT_D32, 32, 0, Raster::D32 },
+ { D3DFMT_X1R5G5B5, 16, 0, Raster::C555 },
+};
+
+static RasterFormatInfo formatInfoFull[] = {
+ { D3DFMT_R8G8B8, 0, 24, 0 },
+ { D3DFMT_A8R8G8B8, 1, 32, Raster::C8888 },
+ { D3DFMT_X8R8G8B8, 0, 32, Raster::C888 },
+ { D3DFMT_R5G6B5, 0, 16, Raster::C565 },
+ { D3DFMT_X1R5G5B5, 0, 16, Raster::C555 },
+ { D3DFMT_A1R5G5B5, 1, 16, Raster::C1555 },
+ { D3DFMT_A4R4G4B4, 1, 16, Raster::C4444 },
+ { D3DFMT_R3G3B2, 0, 8, 0 },
+ { D3DFMT_A8, 1, 8, 0 },
+ { D3DFMT_A8R3G3B2, 1, 16, 0 },
+ { D3DFMT_X4R4G4B4, 0, 16, 0 },
+ { D3DFMT_A2B10G10R10, 1, 32, 0 },
+ { D3DFMT_A8B8G8R8, 1, 32, 0 },
+ { D3DFMT_X8B8G8R8, 0, 32, 0 },
+ { D3DFMT_G16R16, 0, 32, 0 },
+ { D3DFMT_A2R10G10B10, 1, 32, 0 },
+ { D3DFMT_A16B16G16R16, 1, 64, 0 },
+ { D3DFMT_A8P8, 1, 16, 0 },
+// { D3DFMT_P8, 0, 8, ... },
+// { D3DFMT_L8, 0, 8, ... },
+ { D3DFMT_A8L8, 1, 16, 0 },
+ { D3DFMT_A4L4, 1, 8, 0 },
+ { D3DFMT_V8U8, 0, 16, 0 },
+ { D3DFMT_L6V5U5, 0, 16, 0 },
+ { D3DFMT_X8L8V8U8, 0, 32, 0 },
+ { D3DFMT_Q8W8V8U8, 0, 32, 0 },
+ { D3DFMT_V16U16, 0, 32, 0 },
+ { D3DFMT_A2W10V10U10, 1, 32, 0 },
+ { D3DFMT_D16_LOCKABLE, 0, 16, Raster::D16 },
+ { D3DFMT_D32, 0, 32, Raster::D32 },
+ { D3DFMT_D15S1, 0, 16, Raster::D16 },
+ { D3DFMT_D24S8, 0, 32, Raster::D32 },
+ { D3DFMT_D24X8, 0, 32, Raster::D32 },
+ { D3DFMT_D24X4S4, 0, 32, Raster::D32 },
+ { D3DFMT_D16, 0, 16, Raster::D16 },
+ { D3DFMT_D32F_LOCKABLE, 0, 32, Raster::D32 },
+ { D3DFMT_D24FS8, 0, 32, Raster::D32 },
+ { D3DFMT_L16, 0, 16, 0 },
+ { D3DFMT_Q16W16V16U16, 0, 64, 0 },
+ { D3DFMT_R16F, 0, 16, 0 },
+ { D3DFMT_G16R16F, 0, 32, 0 },
+ { D3DFMT_A16B16G16R16F, 1, 64, 0 },
+ { D3DFMT_R32F, 0, 32, 0 },
+ { D3DFMT_G32R32F, 0, 64, 0 },
+ { D3DFMT_A32B32G32R32F, 1, 128, 0 },
+ { D3DFMT_CxV8U8, 0, 16, 0 },
+};
+
+RasterFormatInfo*
+findFormatInfoD3D(uint32 d3dformat)
+{
+ static RasterFormatInfo fake = { 0, 0, 0, 0 };
+ int i;
+ for(i = 0; i < (int)nelem(formatInfoFull); i++)
+ if(formatInfoFull[i].d3dformat == d3dformat)
+ return &formatInfoFull[i];
+ return &fake;
+}
+
+
+static void
+rasterSetFormat(Raster *raster)
+{
+ if(raster->format == 0){
+ // have to find a format first
+ // this could perhaps be a bit more intelligent
+
+ switch(raster->type){
+ case Raster::NORMAL:
+ case Raster::TEXTURE:
+ raster->format = Raster::C8888;
+ break;
+
+#ifdef RW_D3D9
+ case Raster::ZBUFFER:
+ // TODO: allow other formats
+ raster->format = findFormatInfoD3D(d3d9Globals.present.AutoDepthStencilFormat)->rwFormat;
+ // can this even happen? just do something...
+ if(raster->format == 0)
+ raster->format = Raster::D32;
+ break;
+
+ case Raster::CAMERATEXTURE:
+// let's not use this because we apparently don't want alpha
+// raster->format = findFormatInfoD3D(d3d9Globals.present.BackBufferFormat)->rwFormat;
+ raster->format = findFormatInfoD3D(d3d9Globals.startMode.mode.Format)->rwFormat;
+ // can this even happen? just do something...
+ if(raster->format == 0)
+ raster->format = Raster::C888;
+ break;
+ case Raster::CAMERA:
+ raster->format = findFormatInfoD3D(d3d9Globals.present.BackBufferFormat)->rwFormat;
+ // can this even happen? just do something...
+ if(raster->format == 0)
+ raster->format = Raster::C8888;
+ break;
+#endif
+ }
+ }
+
+
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+ if(raster->format & (Raster::PAL4 | Raster::PAL8)){
+ // TODO: do we even allow PAL4?
+ natras->format = D3DFMT_P8;
+ raster->depth = 8;
+ }else{
+ natras->format = formatInfoRW[(raster->format >> 8) & 0xF].d3dformat;
+ raster->depth = formatInfoRW[(raster->format >> 8) & 0xF].depth;
+ }
+ natras->bpp = raster->depth/8;
+ natras->hasAlpha = formatInfoRW[(raster->format >> 8) & 0xF].hasAlpha;
+ raster->stride = raster->width*natras->bpp;
+
+ natras->autogenMipmap = (raster->format & (Raster::MIPMAP|Raster::AUTOMIPMAP)) == (Raster::MIPMAP|Raster::AUTOMIPMAP);
+}
+
+static Raster*
+rasterCreateTexture(Raster *raster)
+{
+ int32 levels;
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+
+ if(natras->format == D3DFMT_P8)
+ natras->palette = (uint8*)rwNew(4*256, MEMDUR_EVENT | ID_DRIVER);
+ if(natras->autogenMipmap)
+ levels = 0;
+ else if(raster->format & Raster::MIPMAP)
+ levels = Raster::calculateNumLevels(raster->width, raster->height);
+ else
+ levels = 1;
+
+ assert(natras->texture == nil);
+ natras->texture = createTexture(raster->width, raster->height,
+ levels,
+ natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0,
+ natras->format);
+ if(natras->texture == nil){
+ RWERROR((ERR_NOTEXTURE));
+ return nil;
+ }
+ return raster;
+}
+
+#ifdef RW_D3D9
+
+static Raster*
+rasterCreateCameraTexture(Raster *raster)
+{
+ if(raster->format & (Raster::PAL4 | Raster::PAL8)){
+ RWERROR((ERR_NOTEXTURE));
+ return nil;
+ }
+
+ int32 levels;
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+ if(natras->autogenMipmap)
+ levels = 0;
+ else if(raster->format & Raster::MIPMAP)
+ levels = Raster::calculateNumLevels(raster->width, raster->height);
+ else
+ levels = 1;
+
+ IDirect3DTexture9 *tex;
+ d3ddevice->CreateTexture(raster->width, raster->height,
+ levels,
+ (natras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0) | D3DUSAGE_RENDERTARGET,
+ (D3DFORMAT)natras->format, D3DPOOL_DEFAULT, &tex, nil);
+ assert(natras->texture == nil);
+ natras->texture = tex;
+ if(natras->texture == nil){
+ RWERROR((ERR_NOTEXTURE));
+ return nil;
+ }
+ d3d9Globals.numTextures++;
+ addVidmemRaster(raster);
+ return raster;
+}
+
+static Raster*
+rasterCreateCamera(Raster *raster)
+{
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+
+ natras->autogenMipmap = 0;
+
+ natras->format = d3d9Globals.present.BackBufferFormat;
+ raster->depth = findFormatDepth(natras->format);
+
+ natras->texture = nil; // global default render target
+ return raster;
+}
+
+static Raster*
+rasterCreateZbuffer(Raster *raster)
+{
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+
+ natras->autogenMipmap = 0;
+
+ // TODO: allow other formats
+ natras->format = d3d9Globals.present.AutoDepthStencilFormat;
+ raster->depth = findFormatDepth(natras->format);
+
+ RECT rect;
+ GetClientRect(d3d9Globals.window, &rect);
+ // This check is done by RW but it's rather strange...
+ if(rect.right == raster->width && rect.bottom == raster->height)
+ natras->texture = d3d9Globals.defaultDepthSurf;
+ else{
+ IDirect3DSurface9 *surf = nil;
+ d3ddevice->CreateDepthStencilSurface(raster->width, raster->height, (D3DFORMAT)natras->format,
+ d3d9Globals.present.MultiSampleType, d3d9Globals.present.MultiSampleQuality,
+ FALSE, &surf, nil);
+ assert(natras->texture == nil);
+ natras->texture = surf;
+ if(natras->texture == nil){
+ RWERROR((ERR_NOTEXTURE));
+ return nil;
+ }
+ }
+ addVidmemRaster(raster);
+
+ return raster;
+}
+#endif
+
+Raster*
+rasterCreate(Raster *raster)
+{
+ rasterSetFormat(raster);
+
+ Raster *ret = raster;
+
+ if(raster->width == 0 || raster->height == 0){
+ raster->flags |= Raster::DONTALLOCATE;
+ raster->stride = 0;
+ goto ret;
+ }
+ if(raster->flags & Raster::DONTALLOCATE)
+ goto ret;
+
+ switch(raster->type){
+ case Raster::NORMAL:
+ case Raster::TEXTURE:
+ ret = rasterCreateTexture(raster);
+ break;
+
+#ifdef RW_D3D9
+ case Raster::CAMERATEXTURE:
+ ret = rasterCreateCameraTexture(raster);
+ break;
+ case Raster::ZBUFFER:
+ ret = rasterCreateZbuffer(raster);
+ break;
+ case Raster::CAMERA:
+ ret = rasterCreateCamera(raster);
+ break;
+#endif
+
+ default:
+ RWERROR((ERR_INVRASTER));
+ return nil;
+ }
+
+ret:
+ raster->originalWidth = raster->width;
+ raster->originalHeight = raster->height;
+ raster->originalStride = raster->stride;
+ raster->originalPixels = raster->pixels;
+ return ret;
+}
+
+uint8*
+rasterLock(Raster *raster, int32 level, int32 lockMode)
+{
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+
+ // check if already locked
+ if(raster->privateFlags & (Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE))
+ return nil;
+
+#ifdef RW_D3D9
+ DWORD flags = D3DLOCK_NOSYSLOCK;
+ if(lockMode & Raster::LOCKREAD)
+ flags |= D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE;
+ IDirect3DTexture9 *tex = (IDirect3DTexture9*)natras->texture;
+ IDirect3DSurface9 *surf, *rt;
+ D3DLOCKED_RECT lr;
+
+ switch(raster->type){
+ case Raster::NORMAL:
+ case Raster::TEXTURE: {
+ tex->GetSurfaceLevel(level, &surf);
+ natras->lockedSurf = surf;
+ HRESULT res = surf->LockRect(&lr, 0, flags);
+ assert(res == D3D_OK);
+ break;
+ }
+
+ case Raster::CAMERATEXTURE:
+ case Raster::CAMERA: {
+ if(lockMode & Raster::PRIVATELOCK_WRITE)
+ assert(0 && "can't lock framebuffer for writing");
+ if(raster->type == Raster::CAMERA)
+ rt = d3d9Globals.defaultRenderTarget;
+ else
+ tex->GetSurfaceLevel(level, &rt);
+ D3DSURFACE_DESC desc;
+ rt->GetDesc(&desc);
+ HRESULT res = d3ddevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, nil);
+ if(res != D3D_OK)
+ return nil;
+ d3ddevice->GetRenderTargetData(rt, surf);
+ natras->lockedSurf = surf;
+ res = surf->LockRect(&lr, 0, flags);
+ assert(res == D3D_OK);
+ break;
+ }
+
+ default:
+ assert(0 && "can't lock this raster type (yet)");
+ }
+
+ raster->pixels = (uint8*)lr.pBits;
+ raster->width >>= level;
+ raster->height >>= level;
+ raster->stride = lr.Pitch;
+ if(raster->width == 0) raster->width = 1;
+ if(raster->height == 0) raster->height = 1;
+#else
+ RasterLevels *levels = (RasterLevels*)natras->texture;
+ raster->pixels = levels->levels[level].data;
+ raster->width = levels->levels[level].width;
+ raster->height = levels->levels[level].height;
+ raster->stride = raster->width*natras->bpp;
+#endif
+ if(lockMode & Raster::LOCKREAD) raster->privateFlags |= Raster::PRIVATELOCK_READ;
+ if(lockMode & Raster::LOCKWRITE) raster->privateFlags |= Raster::PRIVATELOCK_WRITE;
+
+ return raster->pixels;
+}
+
+void
+rasterUnlock(Raster *raster, int32 level)
+{
+#if RW_D3D9
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+ IDirect3DSurface9 *surf = (IDirect3DSurface9*)natras->lockedSurf;
+ surf->UnlockRect();
+ surf->Release();
+ natras->lockedSurf = nil;
+#endif
+ raster->width = raster->originalWidth;
+ raster->height = raster->originalHeight;
+ raster->stride = raster->originalStride;
+ raster->pixels = raster->originalPixels;
+
+ raster->privateFlags &= ~(Raster::PRIVATELOCK_READ|Raster::PRIVATELOCK_WRITE);
+}
+
+int32
+rasterNumLevels(Raster *raster)
+{
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+#ifdef RW_D3D9
+ IDirect3DTexture9 *tex = (IDirect3DTexture9*)natras->texture;
+ return tex->GetLevelCount();
+#else
+ RasterLevels *levels = (RasterLevels*)natras->texture;
+ return levels->numlevels;
+#endif
+}
+
+// Almost the same as ps2 and gl3 function
+bool32
+imageFindRasterFormat(Image *img, int32 type,
+ int32 *pWidth, int32 *pHeight, int32 *pDepth, int32 *pFormat)
+{
+ int32 width, height, depth, format;
+
+ assert((type&0xF) == Raster::TEXTURE);
+
+// for(width = 1; width < img->width; width <<= 1);
+// for(height = 1; height < img->height; height <<= 1);
+ // Perhaps non-power-of-2 textures are acceptable?
+ width = img->width;
+ height = img->height;
+
+ depth = img->depth;
+
+ if(depth <= 8 && !isP8supported)
+ depth = 32;
+
+ switch(depth){
+ case 32:
+ if(img->hasAlpha())
+ format = Raster::C8888;
+ else{
+ format = Raster::C888;
+ depth = 24;
+ }
+ break;
+ case 24:
+ format = Raster::C888;
+ break;
+ case 16:
+ format = Raster::C1555;
+ break;
+ case 8:
+ format = Raster::PAL8 | Raster::C8888;
+ break;
+ case 4:
+ format = Raster::PAL4 | Raster::C8888;
+ break;
+ default:
+ RWERROR((ERR_INVRASTER));
+ return 0;
+ }
+
+ format |= type;
+
+ *pWidth = width;
+ *pHeight = height;
+ *pDepth = depth;
+ *pFormat = format;
+
+ return 1;
+}
+
+bool32
+rasterFromImage(Raster *raster, Image *image)
+{
+ if((raster->type&0xF) != Raster::TEXTURE)
+ return 0;
+
+ void (*conv)(uint8 *out, uint8 *in) = nil;
+
+ // Unpalettize image if necessary but don't change original
+ Image *truecolimg = nil;
+ if(image->depth <= 8 && !isP8supported){
+ truecolimg = Image::create(image->width, image->height, image->depth);
+ truecolimg->pixels = image->pixels;
+ truecolimg->stride = image->stride;
+ truecolimg->palette = image->palette;
+ truecolimg->unpalettize();
+ image = truecolimg;
+ }
+
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+ int32 format = raster->format&(Raster::PAL8 | Raster::PAL4 | 0xF00);
+ switch(image->depth){
+ case 32:
+ if(format == Raster::C8888)
+ conv = conv_BGRA8888_from_RGBA8888;
+ else if(format == Raster::C888)
+ conv = conv_BGR888_from_RGB888;
+ else
+ goto err;
+ break;
+ case 24:
+ if(format == Raster::C8888)
+ conv = conv_BGRA8888_from_RGB888;
+ else if(format == Raster::C888)
+ conv = conv_BGR888_from_RGB888;
+ else
+ goto err;
+ break;
+ case 16:
+ if(format == Raster::C1555)
+ conv = conv_ARGB1555_from_ARGB1555;
+ else
+ goto err;
+ break;
+ case 8:
+ if(format == (Raster::PAL8 | Raster::C8888))
+ conv = conv_8_from_8;
+ else
+ goto err;
+ break;
+ case 4:
+ if(format == (Raster::PAL4 | Raster::C8888) ||
+ format == (Raster::PAL8 | Raster::C8888))
+ conv = conv_8_from_8;
+ else
+ goto err;
+ break;
+ default:
+ err:
+fprintf(stderr, "%d %x\n", image->depth, format); fflush(stdout);
+ RWERROR((ERR_INVRASTER));
+ return 0;
+ }
+
+ uint8 *in, *out;
+ int pallength = 0;
+ if(raster->format & Raster::PAL4)
+ pallength = 16;
+ else if(raster->format & Raster::PAL8)
+ pallength = 256;
+ if(pallength){
+ in = image->palette;
+ out = (uint8*)natras->palette;
+ for(int32 i = 0; i < pallength; i++){
+ conv_RGBA8888_from_RGBA8888(out, in);
+ in += 4;
+ out += 4;
+ }
+ }
+
+ bool unlock = false;
+ if(raster->pixels == nil){
+ raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
+ unlock = true;
+ }
+
+ uint8 *pixels = raster->pixels;
+ assert(pixels);
+ uint8 *imgpixels = image->pixels;
+
+ int x, y;
+ assert(image->width == raster->width);
+ assert(image->height == raster->height);
+ for(y = 0; y < image->height; y++){
+ uint8 *imgrow = imgpixels;
+ uint8 *rasrow = pixels;
+ for(x = 0; x < image->width; x++){
+ conv(rasrow, imgrow);
+ imgrow += image->bpp;
+ rasrow += natras->bpp;
+ }
+ imgpixels += image->stride;
+ pixels += raster->stride;
+ }
+ if(unlock)
+ raster->unlock(0);
+
+ if(truecolimg)
+ truecolimg->destroy();
+
+ return 1;
+}
+
+Image*
+rasterToImage(Raster *raster)
+{
+ int32 depth;
+ Image *image;
+
+ bool unlock = false;
+ if(raster->pixels == nil){
+ raster->lock(0, Raster::LOCKREAD);
+ unlock = true;
+ }
+
+ D3dRaster *natras = GETD3DRASTEREXT(raster);
+ if(natras->customFormat){
+ int w = raster->width;
+ int h = raster->height;
+ // pixels are in the upper right corner
+ if(w < 4) w = 4;
+ if(h < 4) h = 4;
+ image = Image::create(w, h, 32);
+ image->allocate();
+ uint8 *pix = raster->pixels;
+ switch(natras->format){
+ case D3DFMT_DXT1:
+ image->setPixelsDXT(1, pix);
+ if((raster->format & 0xF00) == Raster::C565)
+ image->removeMask();
+ break;
+ case D3DFMT_DXT3:
+ image->setPixelsDXT(3, pix);
+ break;
+ case D3DFMT_DXT5:
+ image->setPixelsDXT(5, pix);
+ break;
+ default:
+ image->destroy();
+ if(unlock)
+ raster->unlock(0);
+ return nil;
+ }
+ // fix it up again
+ image->width = raster->width;
+ image->height = raster->height;
+
+ if(unlock)
+ raster->unlock(0);
+ return image;
+ }
+
+ void (*conv)(uint8 *out, uint8 *in) = nil;
+ switch(raster->format & 0xF00){
+ case Raster::C1555:
+ depth = 16;
+ conv = conv_ARGB1555_from_ARGB1555;
+ break;
+ case Raster::C8888:
+ depth = 32;
+ conv = conv_RGBA8888_from_BGRA8888;
+ break;
+ case Raster::C888:
+ depth = 24;
+ conv = conv_RGB888_from_BGR888;
+ break;
+ case Raster::C555:
+ depth = 16;
+ conv = conv_ARGB1555_from_RGB555;
+ break;
+
+ default:
+ case Raster::C565:
+ case Raster::C4444:
+ case Raster::LUM8:
+ RWERROR((ERR_INVRASTER));
+ return nil;
+ }
+ int32 pallength = 0;
+ if((raster->format & Raster::PAL4) == Raster::PAL4){
+ depth = 4;
+ pallength = 16;
+ }else if((raster->format & Raster::PAL8) == Raster::PAL8){
+ depth = 8;
+ pallength = 256;
+ }
+
+ uint8 *in, *out;
+ image = Image::create(raster->width, raster->height, depth);
+ image->allocate();
+
+ if(pallength){
+ out = image->palette;
+ in = (uint8*)natras->palette;
+ for(int32 i = 0; i < pallength; i++){
+ conv_RGBA8888_from_RGBA8888(out, in);
+ in += 4;
+ out += 4;
+ }
+ }
+
+ uint8 *imgpixels = image->pixels;
+ uint8 *pixels = raster->pixels;
+
+ int x, y;
+ assert(image->width == raster->width);
+ assert(image->height == raster->height);
+ for(y = 0; y < image->height; y++){
+ uint8 *imgrow = imgpixels;
+ uint8 *rasrow = pixels;
+ for(x = 0; x < image->width; x++){
+ conv(imgrow, rasrow);
+ imgrow += image->bpp;
+ rasrow += natras->bpp;
+ }
+ imgpixels += image->stride;
+ pixels += raster->stride;
+ }
+ image->compressPalette();
+
+ if(unlock)
+ raster->unlock(0);
+
+ return image;
+}
+
+int32
+getLevelSize(Raster *raster, int32 level)
+{
+ D3dRaster *ras = GETD3DRASTEREXT(raster);
+#ifdef RW_D3D9
+ IDirect3DTexture9 *tex = (IDirect3DTexture9*)ras->texture;
+ D3DSURFACE_DESC desc;
+ tex->GetLevelDesc(level, &desc);
+ return calculateTextureSize(desc.Width, desc.Height, 1, desc.Format);
+#else
+ RasterLevels *levels = (RasterLevels*)ras->texture;
+ return levels->levels[level].size;
+#endif
+}
+
+void
+allocateDXT(Raster *raster, int32 dxt, int32 numLevels, bool32 hasAlpha)
+{
+ static uint32 dxtMap[] = {
+ 0x31545844, // DXT1
+ 0x32545844, // DXT2
+ 0x33545844, // DXT3
+ 0x34545844, // DXT4
+ 0x35545844, // DXT5
+ };
+ D3dRaster *ras = GETD3DRASTEREXT(raster);
+ ras->format = dxtMap[dxt-1];
+ ras->hasAlpha = hasAlpha;
+ ras->customFormat = 1;
+ if(ras->autogenMipmap)
+ numLevels = 0;
+ else if(raster->format & Raster::MIPMAP)
+ {}
+ else
+ numLevels = 1;
+ ras->texture = createTexture(raster->width, raster->height,
+ numLevels,
+ ras->autogenMipmap ? D3DUSAGE_AUTOGENMIPMAP : 0,
+ ras->format);
+ raster->flags &= ~Raster::DONTALLOCATE;
+}
+
+void
+setPalette(Raster *raster, void *palette, int32 size)
+{
+ D3dRaster *ras = GETD3DRASTEREXT(raster);
+ memcpy(ras->palette, palette, 4*size);
+}
+
+void
+setTexels(Raster *raster, void *texels, int32 level)
+{
+ uint8 *dst = raster->lock(level, Raster::LOCKWRITE|Raster::LOCKNOFETCH);
+ memcpy(dst, texels, getLevelSize(raster, level));
+ raster->unlock(level);
+}
+
+static void*
+createNativeRaster(void *object, int32 offset, int32)
+{
+ D3dRaster *raster = PLUGINOFFSET(D3dRaster, object, offset);
+ raster->texture = nil;
+ raster->palette = nil;
+ raster->lockedSurf = nil;
+ raster->format = 0;
+ raster->hasAlpha = 0;
+ raster->customFormat = 0;
+ return object;
+}
+
+static void*
+destroyNativeRaster(void *object, int32 offset, int32)
+{
+ Raster *raster = (Raster*)object;
+ D3dRaster *natras = PLUGINOFFSET(D3dRaster, raster, offset);
+#ifdef RW_D3D9
+ removeVidmemRaster(raster);
+ evictD3D9Raster(raster);
+#endif
+ switch(raster->type){
+ case Raster::NORMAL:
+ case Raster::TEXTURE:
+ case Raster::CAMERATEXTURE:
+ destroyTexture(natras->texture);
+ break;
+
+ case Raster::ZBUFFER:
+#ifdef RW_D3D9
+ if(raster->flags & Raster::DONTALLOCATE)
+ break;
+ if(natras->texture != d3d9Globals.defaultDepthSurf)
+ ((IDirect3DSurface9*)natras->texture)->Release();
+ natras->texture = nil;
+#endif
+ break;
+ case Raster::CAMERA:
+ break;
+ }
+ rwFree(natras->palette);
+ return object;
+}
+
+static void*
+copyNativeRaster(void *dst, void *, int32 offset, int32)
+{
+ D3dRaster *raster = PLUGINOFFSET(D3dRaster, dst, offset);
+ raster->texture = nil;
+ raster->palette = nil;
+ raster->lockedSurf = nil;
+ raster->format = 0;
+ raster->hasAlpha = 0;
+ raster->customFormat = 0;
+ return dst;
+}
+
+void
+registerNativeRaster(void)
+{
+ nativeRasterOffset = Raster::registerPlugin(sizeof(D3dRaster),
+ ID_RASTERD3D9,
+ createNativeRaster,
+ destroyNativeRaster,
+ copyNativeRaster);
+}
+
+}
+}