mirror of
https://github.com/aap/librw.git
synced 2025-01-23 17:22:23 +00:00
1067 lines
25 KiB
C++
1067 lines
25 KiB
C++
#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;
|
|
|
|
// 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},
|
|
{ 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 < 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;
|
|
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;
|
|
}
|
|
|
|
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&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:
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|