librw/src/d3d/d3ddevice.cpp
2020-04-20 19:18:28 +02:00

1469 lines
37 KiB
C++

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#define WITH_D3D
#include "../rwbase.h"
#include "../rwplg.h"
#include "../rwerror.h"
#include "../rwrender.h"
#include "../rwengine.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "rwd3d.h"
#include "rwd3dimpl.h"
#define PLUGIN_ID 0
namespace rw {
namespace d3d {
#ifdef RW_D3D9
D3d9Globals d3d9Globals;
// Keep track of rasters exclusively in video memory
// as they need special treatment sometimes
struct VidmemRaster
{
Raster *raster;
VidmemRaster *next;
};
static VidmemRaster *vidmemRasters;
void addVidmemRaster(Raster *raster);
void removeVidmemRaster(Raster *raster);
// Same thing for dynamic vertex buffers
struct DynamicVB
{
uint32 length;
uint32 fvf;
IDirect3DVertexBuffer9 **buf;
DynamicVB *next;
};
static DynamicVB *dynamicVBs;
void addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9 **buf);
void removeDynamicVB(IDirect3DVertexBuffer9 **buf);
struct RwRasterStateCache {
Raster *raster;
Texture::Addressing addressingU;
Texture::Addressing addressingV;
Texture::FilterMode filter;
};
#define MAXNUMSTAGES 8
// cached RW render states
struct RwStateCache {
bool32 vertexAlpha;
bool32 textureAlpha;
uint32 srcblend, destblend;
uint32 zwrite;
uint32 ztest;
uint32 fogenable;
RGBA fogcolor;
uint32 cullmode;
uint32 alphafunc;
uint32 alpharef;
RwRasterStateCache texstage[MAXNUMSTAGES];
};
static RwStateCache rwStateCache;
D3dShaderState d3dShaderState;
#define MAXNUMSTATES (D3DRS_BLENDOPALPHA+1)
#define MAXNUMTEXSTATES (D3DTSS_CONSTANT+1)
#define MAXNUMSAMPLERSTATES (D3DSAMP_DMAPOFFSET+1)
static int32 numDirtyStates;
static uint32 dirtyStates[MAXNUMSTATES];
static struct {
uint32 value;
bool32 dirty;
} stateCache[MAXNUMSTATES];
static uint32 d3dStates[MAXNUMSTATES];
static int32 numDirtyTextureStageStates;
static struct {
uint32 stage;
uint32 type;
} dirtyTextureStageStates[MAXNUMTEXSTATES*MAXNUMSTAGES];
static struct {
uint32 value;
bool32 dirty;
} textureStageStateCache[MAXNUMTEXSTATES][MAXNUMSTAGES];
static uint32 d3dTextureStageStates[MAXNUMTEXSTATES][MAXNUMSTAGES];
static uint32 d3dSamplerStates[MAXNUMSAMPLERSTATES][MAXNUMSTAGES];
static bool validStates[MAXNUMSTATES];
static bool validTexStates[MAXNUMTEXSTATES];
static D3DMATERIAL9 d3dmaterial;
static uint32 blendMap[] = {
D3DBLEND_ZERO, // actually invalid
D3DBLEND_ZERO,
D3DBLEND_ONE,
D3DBLEND_SRCCOLOR,
D3DBLEND_INVSRCCOLOR,
D3DBLEND_SRCALPHA,
D3DBLEND_INVSRCALPHA,
D3DBLEND_DESTALPHA,
D3DBLEND_INVDESTALPHA,
D3DBLEND_DESTCOLOR,
D3DBLEND_INVDESTCOLOR,
D3DBLEND_SRCALPHASAT
};
static uint32 alphafuncMap[] = {
D3DCMP_ALWAYS,
D3DCMP_GREATEREQUAL,
D3DCMP_LESS
};
static uint32 cullmodeMap[] = {
D3DCULL_NONE, // actually invalid
D3DCULL_NONE,
D3DCULL_CW,
D3DCULL_CCW
};
// TODO: support mipmaps
static uint32 filterConvMap_NoMIP[] = {
0, D3DTEXF_POINT, D3DTEXF_LINEAR,
D3DTEXF_POINT, D3DTEXF_LINEAR,
D3DTEXF_POINT, D3DTEXF_LINEAR
};
static uint32 addressConvMap[] = {
0, D3DTADDRESS_WRAP, D3DTADDRESS_MIRROR,
D3DTADDRESS_CLAMP, D3DTADDRESS_BORDER
};
// D3D render state
void
setRenderState(uint32 state, uint32 value)
{
if(stateCache[state].value != value){
stateCache[state].value = value;
if(!stateCache[state].dirty){
stateCache[state].dirty = 1;
dirtyStates[numDirtyStates++] = state;
}
}
}
void
getRenderState(uint32 state, uint32 *value)
{
*value = stateCache[state].value;
}
void
setTextureStageState(uint32 stage, uint32 type, uint32 value)
{
if(textureStageStateCache[type][stage].value != value){
textureStageStateCache[type][stage].value = value;
if(!textureStageStateCache[type][stage].dirty){
textureStageStateCache[type][stage].dirty = 1;
dirtyTextureStageStates[numDirtyTextureStageStates].stage = stage;
dirtyTextureStageStates[numDirtyTextureStageStates].type = type;
numDirtyTextureStageStates++;
}
}
}
void
getTextureStageState(uint32 stage, uint32 type, uint32 *value)
{
*value = textureStageStateCache[type][stage].value;
}
void
flushCache(void)
{
uint32 s, t;
uint32 v;
for(int32 i = 0; i < numDirtyStates; i++){
s = dirtyStates[i];
v = stateCache[s].value;
stateCache[s].dirty = 0;
if(d3dStates[s] != v){
d3ddevice->SetRenderState((D3DRENDERSTATETYPE)s, v);
d3dStates[s] = v;
}
}
numDirtyStates = 0;
for(int32 i = 0; i < numDirtyTextureStageStates; i++){
s = dirtyTextureStageStates[i].stage;
t = dirtyTextureStageStates[i].type;
v = textureStageStateCache[t][s].value;
textureStageStateCache[t][s].dirty = 0;
if(d3dTextureStageStates[t][s] != v){
d3ddevice->SetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, v);
d3dTextureStageStates[t][s] = v;
}
}
numDirtyTextureStageStates = 0;
}
void
setSamplerState(uint32 stage, uint32 type, uint32 value)
{
if(d3dSamplerStates[type][stage] != value){
d3ddevice->SetSamplerState(stage, (D3DSAMPLERSTATETYPE)type, value);
d3dSamplerStates[type][stage] = value;
}
}
void
getSamplerState(uint32 stage, uint32 type, uint32 *value)
{
*value = d3dSamplerStates[type][stage];
}
// Bring D3D device in accordance with saved render states (after a reset)
static void
restoreD3d9Device(void)
{
int32 i;
uint32 s, t;
for(i = 0; i < MAXNUMSTAGES; i++){
Raster *raster = rwStateCache.texstage[i].raster;
if(raster){
D3dRaster *d3draster = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
d3ddevice->SetTexture(i, (IDirect3DTexture9*)d3draster->texture);
}else
d3ddevice->SetTexture(i, nil);
setSamplerState(i, D3DSAMP_ADDRESSU, addressConvMap[rwStateCache.texstage[i].addressingU]);
setSamplerState(i, D3DSAMP_ADDRESSV, addressConvMap[rwStateCache.texstage[i].addressingV]);
setSamplerState(i, D3DSAMP_MAGFILTER, filterConvMap_NoMIP[rwStateCache.texstage[i].filter]);
setSamplerState(i, D3DSAMP_MINFILTER, filterConvMap_NoMIP[rwStateCache.texstage[i].filter]);
}
for(s = 0; s < MAXNUMSTATES; s++)
if(validStates[s])
d3ddevice->SetRenderState((D3DRENDERSTATETYPE)s, d3dStates[s]);
for(t = 0; t < MAXNUMTEXSTATES; t++)
if(validTexStates[t])
for(s = 0; s < MAXNUMSTAGES; s++)
d3ddevice->SetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, d3dTextureStageStates[t][s]);
for(t = 1; t < MAXNUMSAMPLERSTATES; t++)
for(s = 0; s < MAXNUMSTAGES; s++)
d3ddevice->SetSamplerState(s, (D3DSAMPLERSTATETYPE)t, d3dSamplerStates[t][s]);
d3ddevice->SetMaterial(&d3dmaterial);
}
void
destroyD3D9Raster(Raster *raster)
{
int i;
if(raster->type == Raster::CAMERATEXTURE)
removeVidmemRaster(raster);
// Make sure we're not still referencing this raster
for(i = 0; i < MAXNUMSTAGES; i++)
if(rwStateCache.texstage[i].raster == raster)
rwStateCache.texstage[i].raster = nil;
}
// RW render state
static void
setDepthTest(bool32 enable)
{
if(rwStateCache.ztest != enable){
rwStateCache.ztest = enable;
if(rwStateCache.zwrite && !enable){
// If we still want to write, enable but set mode to always
setRenderState(D3DRS_ZENABLE, TRUE);
setRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
}else{
setRenderState(D3DRS_ZENABLE, rwStateCache.ztest);
setRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}
}
}
static void
setDepthWrite(bool32 enable)
{
if(rwStateCache.zwrite != enable){
rwStateCache.zwrite = enable;
if(enable && !rwStateCache.ztest){
// Have to switch on ztest so writing can work
setRenderState(D3DRS_ZENABLE, TRUE);
setRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
}
setRenderState(D3DRS_ZWRITEENABLE, rwStateCache.zwrite);
}
}
static void
setVertexAlpha(bool32 enable)
{
if(rwStateCache.vertexAlpha != enable){
if(!rwStateCache.textureAlpha){
setRenderState(D3DRS_ALPHABLENDENABLE, enable);
setRenderState(D3DRS_ALPHATESTENABLE, enable);
}
rwStateCache.vertexAlpha = enable;
}
}
void
setRasterStage(uint32 stage, Raster *raster)
{
bool32 alpha;
D3dRaster *d3draster = nil;
if(raster != rwStateCache.texstage[stage].raster){
rwStateCache.texstage[stage].raster = raster;
if(raster){
assert(raster->platform == PLATFORM_D3D8 ||
raster->platform == PLATFORM_D3D9);
d3draster = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
d3ddevice->SetTexture(stage, (IDirect3DTexture9*)d3draster->texture);
alpha = d3draster->hasAlpha;
}else{
d3ddevice->SetTexture(stage, nil);
alpha = 0;
}
if(stage == 0){
if(rwStateCache.textureAlpha != alpha){
rwStateCache.textureAlpha = alpha;
if(!rwStateCache.vertexAlpha){
setRenderState(D3DRS_ALPHABLENDENABLE, alpha);
setRenderState(D3DRS_ALPHATESTENABLE, alpha);
}
}
}
}
}
static void
setFilterMode(uint32 stage, int32 filter)
{
// TODO: mip mapping
if(rwStateCache.texstage[stage].filter != (Texture::FilterMode)filter){
rwStateCache.texstage[stage].filter = (Texture::FilterMode)filter;
setSamplerState(stage, D3DSAMP_MAGFILTER, filterConvMap_NoMIP[filter]);
setSamplerState(stage, D3DSAMP_MINFILTER, filterConvMap_NoMIP[filter]);
}
}
static void
setAddressU(uint32 stage, int32 addressing)
{
if(rwStateCache.texstage[stage].addressingU != (Texture::Addressing)addressing){
rwStateCache.texstage[stage].addressingU = (Texture::Addressing)addressing;
setSamplerState(stage, D3DSAMP_ADDRESSU, addressConvMap[addressing]);
}
}
static void
setAddressV(uint32 stage, int32 addressing)
{
if(rwStateCache.texstage[stage].addressingV != (Texture::Addressing)addressing){
rwStateCache.texstage[stage].addressingV = (Texture::Addressing)addressing;
setSamplerState(stage, D3DSAMP_ADDRESSV, addressConvMap[addressing]);
}
}
void
setTexture(uint32 stage, Texture *tex)
{
if(tex == nil){
setRasterStage(stage, nil);
return;
}
if(tex->raster){
setFilterMode(stage, tex->getFilter());
setAddressU(stage, tex->getAddressU());
setAddressV(stage, tex->getAddressV());
}
setRasterStage(stage, tex->raster);
}
void
setD3dMaterial(D3DMATERIAL9 *mat9)
{
if(d3dmaterial.Diffuse.r != mat9->Diffuse.r ||
d3dmaterial.Diffuse.g != mat9->Diffuse.g ||
d3dmaterial.Diffuse.b != mat9->Diffuse.b ||
d3dmaterial.Diffuse.a != mat9->Diffuse.a ||
d3dmaterial.Ambient.r != mat9->Ambient.r ||
d3dmaterial.Ambient.g != mat9->Ambient.g ||
d3dmaterial.Ambient.b != mat9->Ambient.b ||
d3dmaterial.Ambient.a != mat9->Ambient.a ||
d3dmaterial.Specular.r != mat9->Specular.r ||
d3dmaterial.Specular.g != mat9->Specular.g ||
d3dmaterial.Specular.b != mat9->Specular.b ||
d3dmaterial.Specular.a != mat9->Specular.a ||
d3dmaterial.Emissive.r != mat9->Emissive.r ||
d3dmaterial.Emissive.g != mat9->Emissive.g ||
d3dmaterial.Emissive.b != mat9->Emissive.b ||
d3dmaterial.Emissive.a != mat9->Emissive.a ||
d3dmaterial.Power != mat9->Power){
d3ddevice->SetMaterial(mat9);
d3dmaterial = *mat9;
}
}
void
setMaterial(SurfaceProperties surfProps, rw::RGBA color)
{
D3DMATERIAL9 mat9;
D3DCOLORVALUE black = { 0, 0, 0, 0 };
float ambmult = surfProps.ambient/255.0f;
float diffmult = surfProps.diffuse/255.0f;
mat9.Ambient.r = color.red*ambmult;
mat9.Ambient.g = color.green*ambmult;
mat9.Ambient.b = color.blue*ambmult;
mat9.Ambient.a = color.alpha;
mat9.Diffuse.r = color.red*diffmult;
mat9.Diffuse.g = color.green*diffmult;
mat9.Diffuse.b = color.blue*diffmult;
mat9.Diffuse.a = color.alpha;
mat9.Power = 0.0f;
mat9.Emissive = black;
mat9.Specular = black;
setD3dMaterial(&mat9);
}
static void
setRwRenderState(int32 state, void *pvalue)
{
uint32 value = (uint32)(uintptr)pvalue;
uint32 bval = value ? TRUE : FALSE;
switch(state){
case TEXTURERASTER:
setRasterStage(0, (Raster*)pvalue);
break;
case TEXTUREADDRESS:
setAddressU(0, value);
setAddressV(0, value);
break;
case TEXTUREADDRESSU:
setAddressU(0, value);
break;
case TEXTUREADDRESSV:
setAddressV(0, value);
break;
case TEXTUREFILTER:
setFilterMode(0, value);
break;
case VERTEXALPHA:
setVertexAlpha(bval);
break;
case SRCBLEND:
if(rwStateCache.srcblend != value){
rwStateCache.srcblend = value;
setRenderState(D3DRS_SRCBLEND, blendMap[value]);
}
break;
case DESTBLEND:
if(rwStateCache.destblend != value){
rwStateCache.destblend = value;
setRenderState(D3DRS_DESTBLEND, blendMap[value]);
}
break;
case ZTESTENABLE:
setDepthTest(bval);
break;
case ZWRITEENABLE:
setDepthWrite(bval);
break;
case FOGENABLE:
if(rwStateCache.fogenable != bval){
rwStateCache.fogenable = bval;
// setRenderState(D3DRS_FOGENABLE, rwStateCache.fogenable);
d3dShaderState.fogData.disable = bval ? 0.0f : 1.0f;
};
break;
case FOGCOLOR:{
RGBA c;
c.red = value;
c.green = value>>8;
c.blue = value>>16;
c.alpha = value>>24;
if(!equal(rwStateCache.fogcolor, c)){
rwStateCache.fogcolor = c;
setRenderState(D3DRS_FOGCOLOR, D3DCOLOR_RGBA(c.red, c.green, c.blue, c.alpha));
convColor(&d3dShaderState.fogColor, &c);
}} break;
case CULLMODE:
if(rwStateCache.cullmode != value){
rwStateCache.cullmode = value;
setRenderState(D3DRS_CULLMODE, cullmodeMap[value]);
}
break;
case ALPHATESTFUNC:
if(rwStateCache.alphafunc != value){
rwStateCache.alphafunc = value;
setRenderState(D3DRS_ALPHAFUNC, alphafuncMap[rwStateCache.alphafunc]);
}
break;
case ALPHATESTREF:
if(rwStateCache.alpharef != value){
rwStateCache.alpharef = value;
setRenderState(D3DRS_ALPHAREF, rwStateCache.alpharef);
}
break;
}
}
static void*
getRwRenderState(int32 state)
{
uint32 val;
switch(state){
case TEXTURERASTER:
return rwStateCache.texstage[0].raster;
case TEXTUREADDRESS:
if(rwStateCache.texstage[0].addressingU == rwStateCache.texstage[0].addressingV)
val = rwStateCache.texstage[0].addressingU;
else
val = 0; // invalid
break;
case TEXTUREADDRESSU:
val = rwStateCache.texstage[0].addressingU;
break;
case TEXTUREADDRESSV:
val = rwStateCache.texstage[0].addressingV;
break;
case TEXTUREFILTER:
val = rwStateCache.texstage[0].filter;
break;
case VERTEXALPHA:
val = rwStateCache.vertexAlpha;
break;
case SRCBLEND:
val = rwStateCache.srcblend;
break;
case DESTBLEND:
val = rwStateCache.destblend;
break;
case ZTESTENABLE:
val = rwStateCache.ztest;
break;
case ZWRITEENABLE:
val = rwStateCache.zwrite;
break;
case FOGENABLE:
val = rwStateCache.fogenable;
break;
case FOGCOLOR:
val = RWRGBAINT(rwStateCache.fogcolor.red, rwStateCache.fogcolor.green,
rwStateCache.fogcolor.blue, rwStateCache.fogcolor.alpha);
break;
case CULLMODE:
val = rwStateCache.cullmode;
break;
case ALPHATESTFUNC:
val = rwStateCache.alphafunc;
break;
case ALPHATESTREF:
val = rwStateCache.alpharef;
break;
default:
val = 0;
}
return (void*)(uintptr)val;
}
// Shaders
void
setVertexShader(void *vs)
{
d3ddevice->SetVertexShader((IDirect3DVertexShader9*)vs);
}
void
setPixelShader(void *ps)
{
d3ddevice->SetPixelShader((IDirect3DPixelShader9*)ps);
}
void*
createVertexShader(void *csosrc)
{
void *shdr;
if(d3ddevice->CreateVertexShader((DWORD*)csosrc, (IDirect3DVertexShader9**)&shdr) == D3D_OK)
return shdr;
d3d9Globals.numVertexShaders++;
return nil;
}
void*
createPixelShader(void *csosrc)
{
void *shdr;
if(d3ddevice->CreatePixelShader((DWORD*)csosrc, (IDirect3DPixelShader9**)&shdr) == D3D_OK)
return shdr;
d3d9Globals.numPixelShaders++;
return nil;
}
void
destroyVertexShader(void *shader)
{
((IDirect3DVertexShader9*)shader)->Release();
d3d9Globals.numVertexShaders--;
}
void
destroyPixelShader(void *shader)
{
((IDirect3DPixelShader9*)shader)->Release();
d3d9Globals.numPixelShaders--;
}
// Camera
static void
beginUpdate(Camera *cam)
{
float view[16], proj[16];
// View Matrix
Matrix inv;
Matrix::invert(&inv, cam->getFrame()->getLTM());
// Since we're looking into positive Z,
// flip X to ge a left handed view space.
view[0] = -inv.right.x;
view[1] = inv.right.y;
view[2] = inv.right.z;
view[3] = 0.0f;
view[4] = -inv.up.x;
view[5] = inv.up.y;
view[6] = inv.up.z;
view[7] = 0.0f;
view[8] = -inv.at.x;
view[9] = inv.at.y;
view[10] = inv.at.z;
view[11] = 0.0f;
view[12] = -inv.pos.x;
view[13] = inv.pos.y;
view[14] = inv.pos.z;
view[15] = 1.0f;
memcpy(&cam->devView, view, sizeof(RawMatrix));
d3ddevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)view);
// Projection Matrix
float32 invwx = 1.0f/cam->viewWindow.x;
float32 invwy = 1.0f/cam->viewWindow.y;
float32 invz = 1.0f/(cam->farPlane-cam->nearPlane);
proj[0] = invwx;
proj[1] = 0.0f;
proj[2] = 0.0f;
proj[3] = 0.0f;
proj[4] = 0.0f;
proj[5] = invwy;
proj[6] = 0.0f;
proj[7] = 0.0f;
proj[8] = cam->viewOffset.x*invwx;
proj[9] = cam->viewOffset.y*invwy;
proj[12] = -proj[8];
proj[13] = -proj[9];
if(cam->projection == Camera::PERSPECTIVE){
proj[10] = cam->farPlane*invz;
proj[11] = 1.0f;
proj[15] = 0.0f;
}else{
proj[10] = invz;
proj[11] = 0.0f;
proj[15] = 1.0f;
}
proj[14] = -cam->nearPlane*proj[10];
memcpy(&cam->devProj, proj, sizeof(RawMatrix));
d3ddevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)proj);
// TODO: figure out where this is really done
// setRenderState(D3DRS_FOGSTART, *(uint32*)&cam->fogPlane);
// setRenderState(D3DRS_FOGEND, *(uint32*)&cam->farPlane);
d3dShaderState.fogData.start = cam->fogPlane;
d3dShaderState.fogData.end = cam->farPlane;
d3dShaderState.fogData.range = 1.0f/(cam->fogPlane - cam->farPlane);
d3dShaderState.fogDisable.start = 0.0f;
d3dShaderState.fogDisable.end = 0.0f;
d3dShaderState.fogDisable.range = 0.0f;
d3dShaderState.fogDisable.disable = 1.0f;
D3DVIEWPORT9 vp;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
vp.X = cam->frameBuffer->offsetX;
vp.Y = cam->frameBuffer->offsetY;
vp.Width = cam->frameBuffer->width;
vp.Height = cam->frameBuffer->height;
d3ddevice->SetViewport(&vp);
// TODO: figure out when to call this
d3ddevice->BeginScene();
}
static void
endUpdate(Camera *cam)
{
// TODO: figure out when to call this
d3ddevice->EndScene();
}
// Manage video memory
void
addVidmemRaster(Raster *raster)
{
VidmemRaster *vmr = rwNewT(VidmemRaster, 1, ID_DRIVER | MEMDUR_EVENT);
vmr->raster = raster;
vmr->next = vidmemRasters;
vidmemRasters = vmr;
}
void
removeVidmemRaster(Raster *raster)
{
VidmemRaster **p, *vmr;
for(p = &vidmemRasters; *p; p = &(*p)->next)
if((*p)->raster == raster)
goto found;
return;
found:
vmr = *p;
*p = vmr->next;
rwFree(vmr);
}
static void
releaseVidmemRasters(void)
{
VidmemRaster *vmr;
Raster *raster;
D3dRaster *natras;
for(vmr = vidmemRasters; vmr; vmr = vmr->next){
raster = vmr->raster;
natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
if(raster->type == Raster::CAMERATEXTURE){
if(natras->texture){
deleteObject(natras->texture);
d3d9Globals.numTextures--;
natras->texture = nil;
}
}
}
}
static void
recreateVidmemRasters(void)
{
VidmemRaster *vmr;
Raster *raster;
D3dRaster *natras;
for(vmr = vidmemRasters; vmr; vmr = vmr->next){
raster = vmr->raster;
natras = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset);
if(raster->type == Raster::CAMERATEXTURE){
int32 levels = Raster::calculateNumLevels(raster->width, raster->height);
IDirect3DTexture9 *tex;
d3ddevice->CreateTexture(raster->width, raster->height,
raster->format & Raster::MIPMAP ? levels : 1,
D3DUSAGE_RENDERTARGET,
(D3DFORMAT)natras->format, D3DPOOL_DEFAULT, &tex, nil);
natras->texture = tex;
if(natras->texture)
d3d9Globals.numTextures++;
}
}
}
void
addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9 **buf)
{
DynamicVB *dvb = rwNewT(DynamicVB, 1, ID_DRIVER | MEMDUR_EVENT);
dvb->length = length;
dvb->fvf = fvf;
dvb->buf = buf;
dvb->next = dynamicVBs;
dynamicVBs = dvb;
}
void
removeDynamicVB(IDirect3DVertexBuffer9 **buf)
{
DynamicVB **p, *dvb;
for(p = &dynamicVBs; *p; p = &(*p)->next)
if((*p)->buf == buf)
goto found;
return;
found:
dvb = *p;
*p = dvb->next;
rwFree(dvb);
}
static void
releaseDynamicVBs(void)
{
DynamicVB *dvb;
for(dvb = dynamicVBs; dvb; dvb = dvb->next){
if(*dvb->buf){
deleteObject(*dvb->buf);
d3d9Globals.numVertexBuffers--;
*dvb->buf = nil;
}
}
}
static void
recreateDynamicVBs(void)
{
DynamicVB *dvb;
for(dvb = dynamicVBs; dvb; dvb = dvb->next){
*dvb->buf = (IDirect3DVertexBuffer9*)createVertexBuffer(dvb->length, dvb->fvf, true);
if(*dvb->buf)
d3d9Globals.numVertexBuffers++;
}
}
static void
releaseVideoMemory(void)
{
int32 i;
for(i = 0; i < MAXNUMSTAGES; i++)
d3ddevice->SetTexture(i, nil);
d3ddevice->SetVertexDeclaration(nil);
d3ddevice->SetVertexShader(nil);
d3ddevice->SetPixelShader(nil);
d3ddevice->SetIndices(nil);
for(i = 0; i < 2; i++)
d3ddevice->SetStreamSource(0, nil, 0, 0);
releaseVidmemRasters();
releaseDynamicVBs();
}
static void
restoreVideoMemory(void)
{
recreateDynamicVBs();
// important that we get all raster back before restoring state
recreateVidmemRasters();
restoreD3d9Device();
}
static void
clearCamera(Camera *cam, RGBA *col, uint32 mode)
{
int flags = 0;
if(mode & Camera::CLEARIMAGE)
mode |= D3DCLEAR_TARGET;
if(mode & Camera::CLEARZ)
mode |= D3DCLEAR_ZBUFFER;
D3DCOLOR c = D3DCOLOR_RGBA(col->red, col->green, col->blue, col->alpha);
RECT r;
GetClientRect(d3d9Globals.window, &r);
BOOL icon = IsIconic(d3d9Globals.window);
Raster *ras = cam->frameBuffer;
if(!icon &&
(r.right != d3d9Globals.present.BackBufferWidth || r.bottom != d3d9Globals.present.BackBufferHeight)){
d3d9Globals.present.BackBufferWidth = r.right;
d3d9Globals.present.BackBufferHeight = r.bottom;
releaseVideoMemory();
d3d::d3ddevice->Reset(&d3d9Globals.present);
restoreVideoMemory();
}
d3ddevice->Clear(0, 0, mode, c, 1.0f, 0);
}
static void
showRaster(Raster *raster)
{
// TODO: do this properly!
// not used but we want cameras to have rasters
assert(raster);
HRESULT res = d3ddevice->Present(nil, nil, 0, nil);
if(res == D3DERR_DEVICELOST){
res = d3ddevice->TestCooperativeLevel();
// lost while being minimized, not reset once we're back
if(res == D3DERR_DEVICENOTRESET){
releaseVideoMemory();
d3d::d3ddevice->Reset(&d3d9Globals.present);
restoreVideoMemory();
}
}
}
static bool32
rasterRenderFast(Raster *raster, int32 x, int32 y)
{
IDirect3DTexture9 *dsttex;
IDirect3DSurface9 *srcsurf, *dstsurf;
D3DSURFACE_DESC srcdesc, dstdesc;
RECT rect = { x, y, x, y };
Raster *src = raster;
Raster *dst = Raster::getCurrentContext();
D3dRaster *natdst = PLUGINOFFSET(D3dRaster, dst, nativeRasterOffset);
D3dRaster *natsrc = PLUGINOFFSET(D3dRaster, src, nativeRasterOffset);
switch(dst->type){
case Raster::CAMERATEXTURE:
switch(src->type){
case Raster::CAMERA:
dsttex = (IDirect3DTexture9*)natdst->texture;
dsttex->GetSurfaceLevel(0, &dstsurf);
assert(dstsurf);
dstsurf->GetDesc(&dstdesc);
d3ddevice->GetRenderTarget(0, &srcsurf);
assert(srcsurf);
srcsurf->GetDesc(&srcdesc);
rect.right += srcdesc.Width;
rect.bottom += srcdesc.Height;
d3ddevice->StretchRect(srcsurf, &rect, dstsurf, &rect, D3DTEXF_NONE);
dstsurf->Release();
srcsurf->Release();
return 1;
}
break;
}
return 0;
}
//
// Device
//
int
findFormatDepth(uint32 format)
{
// not all formats actually
switch(format){
case D3DFMT_R8G8B8: return 24;
case D3DFMT_A8R8G8B8: return 32;
case D3DFMT_X8R8G8B8: return 32;
case D3DFMT_R5G6B5: return 16;
case D3DFMT_X1R5G5B5: return 16;
case D3DFMT_A1R5G5B5: return 16;
case D3DFMT_A4R4G4B4: return 16;
case D3DFMT_R3G3B2: return 8;
case D3DFMT_A8: return 8;
case D3DFMT_A8R3G3B2: return 16;
case D3DFMT_X4R4G4B4: return 16;
case D3DFMT_A2B10G10R10: return 32;
case D3DFMT_A8B8G8R8: return 32;
case D3DFMT_X8B8G8R8: return 32;
case D3DFMT_G16R16: return 32;
case D3DFMT_A2R10G10B10: return 32;
case D3DFMT_A16B16G16R16: return 64;
case D3DFMT_L8: return 8;
case D3DFMT_D16: return 16;
case D3DFMT_D24X8: return 32;
case D3DFMT_D32: return 32;
default: return 0;
}
}
// the commented ones don't "work"
static D3DFORMAT fbFormats[] = {
// D3DFMT_A1R5G5B5,
/// D3DFMT_A2R10G10B10, // works but let's not use it...
// D3DFMT_A8R8G8B8,
D3DFMT_X8R8G8B8,
// D3DFMT_X1R5G5B5,
D3DFMT_R5G6B5
};
static void
addVideoMode(D3DDISPLAYMODE *mode)
{
int i;
for(i = 1; i < d3d9Globals.numModes; i++){
if(d3d9Globals.modes[i].mode.Width == mode->Width &&
d3d9Globals.modes[i].mode.Height == mode->Height &&
d3d9Globals.modes[i].mode.Format == mode->Format){
// had this format already, remember highest refresh rate
if(mode->RefreshRate > d3d9Globals.modes[i].mode.RefreshRate)
d3d9Globals.modes[i].mode.RefreshRate = mode->RefreshRate;
return;
}
}
// none found, add
d3d9Globals.modes[d3d9Globals.numModes].mode = *mode;
d3d9Globals.modes[d3d9Globals.numModes].flags = VIDEOMODEEXCLUSIVE;
d3d9Globals.numModes++;
}
static void
makeVideoModeList(void)
{
int i, j;
D3DDISPLAYMODE mode;
d3d9Globals.numModes = 1;
for(i = 0; i < nelem(fbFormats); i++)
d3d9Globals.numModes += d3d9Globals.d3d9->GetAdapterModeCount(d3d9Globals.adapter, fbFormats[i]);
rwFree(d3d9Globals.modes);
d3d9Globals.modes = rwNewT(DisplayMode, d3d9Globals.numModes, ID_DRIVER | MEMDUR_EVENT);
// first mode is current mode as windowed
d3d9Globals.d3d9->GetAdapterDisplayMode(d3d9Globals.adapter, &d3d9Globals.modes[0].mode);
d3d9Globals.modes[0].flags = 0;
d3d9Globals.numModes = 1;
for(i = 0; i < nelem(fbFormats); i++){
int n = d3d9Globals.d3d9->GetAdapterModeCount(d3d9Globals.adapter, fbFormats[i]);
for(j = 0; j < n; j++){
d3d9Globals.d3d9->EnumAdapterModes(d3d9Globals.adapter, fbFormats[i], j, &mode);
addVideoMode(&mode);
}
}
}
static int
openD3D(EngineOpenParams *params)
{
HWND win = params->window;
d3d9Globals.window = win;
d3d9Globals.numAdapters = 0;
d3d9Globals.modes = nil;
d3d9Globals.numModes = 0;
d3d9Globals.currentMode = 0;
d3d9Globals.d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(d3d9Globals.d3d9 == nil){
RWERROR((ERR_GENERAL, "Direct3DCreate9() failed"));
return 0;
}
d3d9Globals.numAdapters = d3d9Globals.d3d9->GetAdapterCount();
d3d9Globals.adapter = 0;
for(d3d9Globals.adapter = 0; d3d9Globals.adapter < d3d9Globals.numAdapters; d3d9Globals.adapter++)
if(d3d9Globals.d3d9->GetDeviceCaps(d3d9Globals.adapter, D3DDEVTYPE_HAL, &d3d9Globals.caps) == D3D_OK)
goto found;
// no adapter
d3d9Globals.d3d9->Release();
d3d9Globals.d3d9 = nil;
RWERROR((ERR_GENERAL, "Direct3DCreate9() failed"));
return 0;
found:
makeVideoModeList();
return 1;
}
static int
closeD3D(void)
{
ULONG ref = d3d9Globals.d3d9->Release();
if(ref != 0)
printf("IDirect3D9_Release did not destroy\n");
d3d9Globals.d3d9 = nil;
return 1;
}
static int
startD3D(void)
{
HRESULT hr;
int vp;
if(d3d9Globals.caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
uint32 width, height, depth;
D3DFORMAT format, zformat;
d3d9Globals.startMode = d3d9Globals.modes[d3d9Globals.currentMode];
format = d3d9Globals.startMode.mode.Format;
bool windowed = !(d3d9Globals.startMode.flags & VIDEOMODEEXCLUSIVE);
// Use window size in windowed mode, otherwise get size from video mode
if(windowed){
RECT rect;
GetClientRect(d3d9Globals.window, &rect);
width = rect.right - rect.left;
height = rect.bottom - rect.top;
}else{
// this will be much better for restoring after iconification
SetWindowLong(d3d9Globals.window, GWL_STYLE, WS_POPUP);
width = d3d9Globals.startMode.mode.Width;
height = d3d9Globals.startMode.mode.Height;
}
// See if we can get an alpha channel
if(format == D3DFMT_X8R8G8B8){
if(d3d9Globals.d3d9->CheckDeviceType(d3d9Globals.adapter, D3DDEVTYPE_HAL, format, D3DFMT_A8R8G8B8, windowed) == D3D_OK)
format = D3DFMT_A8R8G8B8;
}
depth = findFormatDepth(format);
// TOOD: use something more sophisticated maybe?
if(depth == 32)
zformat = D3DFMT_D24S8;
else
zformat = D3DFMT_D16;
d3d9Globals.present.BackBufferWidth = width;
d3d9Globals.present.BackBufferHeight = height;
d3d9Globals.present.BackBufferFormat = format;
d3d9Globals.present.BackBufferCount = 1;
d3d9Globals.present.MultiSampleType = D3DMULTISAMPLE_NONE;
d3d9Globals.present.MultiSampleQuality = 0;
d3d9Globals.present.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3d9Globals.present.hDeviceWindow = d3d9Globals.window;
d3d9Globals.present.Windowed = windowed;
d3d9Globals.present.EnableAutoDepthStencil = true;
d3d9Globals.present.AutoDepthStencilFormat = zformat;
d3d9Globals.present.Flags = 0;
d3d9Globals.present.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3d9Globals.present.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
// d3d9Globals.present.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
assert(d3d::d3ddevice == nil);
BOOL icon = IsIconic(d3d9Globals.window);
IDirect3DDevice9 *dev;
hr = d3d9Globals.d3d9->CreateDevice(d3d9Globals.adapter, D3DDEVTYPE_HAL,
d3d9Globals.window, vp, &d3d9Globals.present, &dev);
if(FAILED(hr)){
RWERROR((ERR_GENERAL, "CreateDevice() failed"));
return 0;
}
d3d::d3ddevice = dev;
return 1;
}
static int
initD3D(void)
{
int32 s, t;
// TODO: do some real stuff here
d3d9Globals.numTextures = 0;
d3d9Globals.numVertexShaders = 0;
d3d9Globals.numPixelShaders = 0;
d3d9Globals.numVertexBuffers = 0;
d3d9Globals.numIndexBuffers = 0;
d3d9Globals.numVertexDeclarations = 0;
d3ddevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
rwStateCache.alphafunc = ALPHAGREATEREQUAL;
d3ddevice->SetRenderState(D3DRS_ALPHAREF, 10);
rwStateCache.alpharef = 10;
d3ddevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
rwStateCache.fogenable = 0;
d3ddevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);
// TODO: more fog stuff
d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
rwStateCache.cullmode = CULLNONE;
d3ddevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
rwStateCache.srcblend = BLENDSRCALPHA;
d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
rwStateCache.destblend = BLENDINVSRCALPHA;
d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 0);
rwStateCache.vertexAlpha = 0;
rwStateCache.textureAlpha = 0;
setTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
// setTextureStageState(0, D3DTSS_CONSTANT, 0xFFFFFFFF);
// setTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
// setTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_CONSTANT);
// setTextureStageState(0, D3DTSS_COLOROP, D3DTA_CONSTANT);
// These states exist, not all do
validStates[D3DRS_ZENABLE] = 1;
validStates[D3DRS_FILLMODE] = 1;
validStates[D3DRS_SHADEMODE] = 1;
validStates[D3DRS_ZWRITEENABLE] = 1;
validStates[D3DRS_ALPHATESTENABLE] = 1;
validStates[D3DRS_LASTPIXEL] = 1;
validStates[D3DRS_SRCBLEND] = 1;
validStates[D3DRS_DESTBLEND] = 1;
validStates[D3DRS_CULLMODE] = 1;
validStates[D3DRS_ZFUNC] = 1;
validStates[D3DRS_ALPHAREF] = 1;
validStates[D3DRS_ALPHAFUNC] = 1;
validStates[D3DRS_DITHERENABLE] = 1;
validStates[D3DRS_ALPHABLENDENABLE] = 1;
validStates[D3DRS_FOGENABLE] = 1;
validStates[D3DRS_SPECULARENABLE] = 1;
validStates[D3DRS_FOGCOLOR] = 1;
validStates[D3DRS_FOGTABLEMODE] = 1;
validStates[D3DRS_FOGSTART] = 1;
validStates[D3DRS_FOGEND] = 1;
validStates[D3DRS_FOGDENSITY] = 1;
validStates[D3DRS_RANGEFOGENABLE] = 1;
validStates[D3DRS_STENCILENABLE] = 1;
validStates[D3DRS_STENCILFAIL] = 1;
validStates[D3DRS_STENCILZFAIL] = 1;
validStates[D3DRS_STENCILPASS] = 1;
validStates[D3DRS_STENCILFUNC] = 1;
validStates[D3DRS_STENCILREF] = 1;
validStates[D3DRS_STENCILMASK] = 1;
validStates[D3DRS_STENCILWRITEMASK] = 1;
validStates[D3DRS_TEXTUREFACTOR] = 1;
validStates[D3DRS_WRAP0] = 1;
validStates[D3DRS_WRAP1] = 1;
validStates[D3DRS_WRAP2] = 1;
validStates[D3DRS_WRAP3] = 1;
validStates[D3DRS_WRAP4] = 1;
validStates[D3DRS_WRAP5] = 1;
validStates[D3DRS_WRAP6] = 1;
validStates[D3DRS_WRAP7] = 1;
validStates[D3DRS_CLIPPING] = 1;
validStates[D3DRS_LIGHTING] = 1;
validStates[D3DRS_AMBIENT] = 1;
validStates[D3DRS_FOGVERTEXMODE] = 1;
validStates[D3DRS_COLORVERTEX] = 1;
validStates[D3DRS_LOCALVIEWER] = 1;
validStates[D3DRS_NORMALIZENORMALS] = 1;
validStates[D3DRS_DIFFUSEMATERIALSOURCE] = 1;
validStates[D3DRS_SPECULARMATERIALSOURCE] = 1;
validStates[D3DRS_AMBIENTMATERIALSOURCE] = 1;
validStates[D3DRS_EMISSIVEMATERIALSOURCE] = 1;
validStates[D3DRS_VERTEXBLEND] = 1;
validStates[D3DRS_CLIPPLANEENABLE] = 1;
validStates[D3DRS_POINTSIZE] = 1;
validStates[D3DRS_POINTSIZE_MIN] = 1;
validStates[D3DRS_POINTSPRITEENABLE] = 1;
validStates[D3DRS_POINTSCALEENABLE] = 1;
validStates[D3DRS_POINTSCALE_A] = 1;
validStates[D3DRS_POINTSCALE_B] = 1;
validStates[D3DRS_POINTSCALE_C] = 1;
validStates[D3DRS_MULTISAMPLEANTIALIAS] = 1;
validStates[D3DRS_MULTISAMPLEMASK] = 1;
validStates[D3DRS_PATCHEDGESTYLE] = 1;
validStates[D3DRS_DEBUGMONITORTOKEN] = 1;
validStates[D3DRS_POINTSIZE_MAX] = 1;
validStates[D3DRS_INDEXEDVERTEXBLENDENABLE] = 1;
validStates[D3DRS_COLORWRITEENABLE] = 1;
validStates[D3DRS_TWEENFACTOR] = 1;
validStates[D3DRS_BLENDOP] = 1;
validStates[D3DRS_POSITIONDEGREE] = 1;
validStates[D3DRS_NORMALDEGREE] = 1;
validStates[D3DRS_SCISSORTESTENABLE] = 1;
validStates[D3DRS_SLOPESCALEDEPTHBIAS] = 1;
validStates[D3DRS_ANTIALIASEDLINEENABLE] = 1;
validStates[D3DRS_MINTESSELLATIONLEVEL] = 1;
validStates[D3DRS_MAXTESSELLATIONLEVEL] = 1;
validStates[D3DRS_ADAPTIVETESS_X] = 1;
validStates[D3DRS_ADAPTIVETESS_Y] = 1;
validStates[D3DRS_ADAPTIVETESS_Z] = 1;
validStates[D3DRS_ADAPTIVETESS_W] = 1;
validStates[D3DRS_ENABLEADAPTIVETESSELLATION] = 1;
validStates[D3DRS_TWOSIDEDSTENCILMODE] = 1;
validStates[D3DRS_CCW_STENCILFAIL] = 1;
validStates[D3DRS_CCW_STENCILZFAIL] = 1;
validStates[D3DRS_CCW_STENCILPASS] = 1;
validStates[D3DRS_CCW_STENCILFUNC] = 1;
validStates[D3DRS_COLORWRITEENABLE1] = 1;
validStates[D3DRS_COLORWRITEENABLE2] = 1;
validStates[D3DRS_COLORWRITEENABLE3] = 1;
validStates[D3DRS_BLENDFACTOR] = 1;
validStates[D3DRS_SRGBWRITEENABLE] = 1;
validStates[D3DRS_DEPTHBIAS] = 1;
validStates[D3DRS_WRAP8] = 1;
validStates[D3DRS_WRAP9] = 1;
validStates[D3DRS_WRAP10] = 1;
validStates[D3DRS_WRAP11] = 1;
validStates[D3DRS_WRAP12] = 1;
validStates[D3DRS_WRAP13] = 1;
validStates[D3DRS_WRAP14] = 1;
validStates[D3DRS_WRAP15] = 1;
validStates[D3DRS_SEPARATEALPHABLENDENABLE] = 1;
validStates[D3DRS_SRCBLENDALPHA] = 1;
validStates[D3DRS_DESTBLENDALPHA] = 1;
validStates[D3DRS_BLENDOPALPHA] = 1;
validTexStates[D3DTSS_COLOROP] = 1;
validTexStates[D3DTSS_COLORARG1] = 1;
validTexStates[D3DTSS_COLORARG2] = 1;
validTexStates[D3DTSS_ALPHAOP] = 1;
validTexStates[D3DTSS_ALPHAARG1] = 1;
validTexStates[D3DTSS_ALPHAARG2] = 1;
validTexStates[D3DTSS_BUMPENVMAT00] = 1;
validTexStates[D3DTSS_BUMPENVMAT01] = 1;
validTexStates[D3DTSS_BUMPENVMAT10] = 1;
validTexStates[D3DTSS_BUMPENVMAT11] = 1;
validTexStates[D3DTSS_TEXCOORDINDEX] = 1;
validTexStates[D3DTSS_BUMPENVLSCALE] = 1;
validTexStates[D3DTSS_BUMPENVLOFFSET] = 1;
validTexStates[D3DTSS_TEXTURETRANSFORMFLAGS] = 1;
validTexStates[D3DTSS_COLORARG0] = 1;
validTexStates[D3DTSS_ALPHAARG0] = 1;
validTexStates[D3DTSS_RESULTARG] = 1;
validTexStates[D3DTSS_CONSTANT] = 1;
// Save the current states
for(s = 0; s < MAXNUMSTATES; s++)
if(validStates[s]){
d3ddevice->GetRenderState((D3DRENDERSTATETYPE)s, (DWORD*)&d3dStates[s]);
stateCache[s].value = d3dStates[s];
}
for(t = 0; t < MAXNUMTEXSTATES; t++)
if(validTexStates[t])
for(s = 0; s < MAXNUMSTAGES; s++){
d3ddevice->GetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, (DWORD*)&d3dTextureStageStates[t][s]);
textureStageStateCache[t][s].value = d3dTextureStageStates[t][s];
}
for(t = 1; t < MAXNUMSAMPLERSTATES; t++)
for(s = 0; s < MAXNUMSTAGES; s++){
d3ddevice->GetSamplerState(s, (D3DSAMPLERSTATETYPE)t, (DWORD*)&d3dSamplerStates[t][s]);
d3dSamplerStates[t][s] = d3dSamplerStates[t][s];
}
openIm2D();
openIm3D();
return 1;
}
static int
termD3D(void)
{
closeIm3D();
closeIm2D();
releaseVideoMemory();
ULONG ref = d3d::d3ddevice->Release();
if(ref != 0)
printf("IDirect3D9Device_Release did not destroy\n");
d3d::d3ddevice = nil;
return 1;
}
static int
finalizeD3D(void)
{
return 1;
}
static int
deviceSystem(DeviceReq req, void *arg, int32 n)
{
D3DADAPTER_IDENTIFIER9 adapter;
VideoMode *rwmode;
switch(req){
case DEVICEOPEN:
return openD3D((EngineOpenParams*)arg);
case DEVICECLOSE:
return closeD3D();
case DEVICEINIT:
return startD3D() && initD3D();
case DEVICETERM:
return termD3D();
case DEVICEFINALIZE:
return finalizeD3D();
case DEVICEGETNUMSUBSYSTEMS:
return d3d9Globals.numAdapters;
case DEVICEGETCURRENTSUBSYSTEM:
return d3d9Globals.adapter;
case DEVICESETSUBSYSTEM:
if(n >= d3d9Globals.numAdapters)
return 0;
d3d9Globals.adapter = n;
if(d3d9Globals.d3d9->GetDeviceCaps(d3d9Globals.adapter, D3DDEVTYPE_HAL, &d3d9Globals.caps) != D3D_OK)
return 0;
makeVideoModeList();
return 1;
case DEVICEGETSUBSSYSTEMINFO:
if(n >= d3d9Globals.numAdapters)
return 0;
if(d3d9Globals.d3d9->GetAdapterIdentifier(d3d9Globals.adapter, 0, &adapter) != D3D_OK)
return 0;
strncpy(((SubSystemInfo*)arg)->name, adapter.Description, sizeof(SubSystemInfo::name));
return 1;
case DEVICEGETNUMVIDEOMODES:
return d3d9Globals.numModes;
case DEVICEGETCURRENTVIDEOMODE:
return d3d9Globals.currentMode;
case DEVICESETVIDEOMODE:
if(n >= d3d9Globals.numModes)
return 0;
d3d9Globals.currentMode = n;
return 1;
case DEVICEGETVIDEOMODEINFO:
rwmode = (VideoMode*)arg;
rwmode->width = d3d9Globals.modes[n].mode.Width;
rwmode->height = d3d9Globals.modes[n].mode.Height;
rwmode->depth = findFormatDepth(d3d9Globals.modes[n].mode.Format);
rwmode->flags = d3d9Globals.modes[n].flags;
return 1;
}
return 1;
}
Device renderdevice = {
0.0f, 1.0f,
d3d::beginUpdate,
d3d::endUpdate,
d3d::clearCamera,
d3d::showRaster,
d3d::rasterRenderFast,
d3d::setRwRenderState,
d3d::getRwRenderState,
d3d::im2DRenderLine,
d3d::im2DRenderTriangle,
d3d::im2DRenderPrimitive,
d3d::im2DRenderIndexedPrimitive,
d3d::im3DTransform,
d3d::im3DRenderIndexed,
d3d::im3DEnd,
d3d::deviceSystem,
};
#endif
}
}