librw/src/d3d/d3ddevice.cpp

1077 lines
28 KiB
C++
Raw Normal View History

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include "../rwbase.h"
#include "../rwplg.h"
2017-08-09 10:57:32 +02:00
#include "../rwerror.h"
2017-08-29 10:12:56 +02:00
#include "../rwrender.h"
#include "../rwengine.h"
#include "../rwpipeline.h"
#include "../rwobjects.h"
#include "rwd3d.h"
#include "rwd3dimpl.h"
2017-08-09 10:57:32 +02:00
#define PLUGIN_ID 0
namespace rw {
namespace d3d {
#ifdef RW_D3D9
2017-10-20 22:38:28 +02:00
struct D3d9Globals
{
HWND window;
bool windowed;
int presentWidth, presentHeight;
} d3d9Globals;
2018-01-08 12:55:15 +01:00
// 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);
struct RwRasterStateCache {
Raster *raster;
Texture::Addressing addressingU;
Texture::Addressing addressingV;
Texture::FilterMode filter;
};
2017-08-09 10:57:32 +02:00
#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;
2017-08-09 10:57:32 +02:00
2018-06-14 15:20:45 +02:00
#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;
2018-06-14 15:20:45 +02:00
} textureStageStateCache[MAXNUMTEXSTATES][MAXNUMSTAGES];
static uint32 d3dTextureStageStates[MAXNUMTEXSTATES][MAXNUMSTAGES];
static uint32 d3dSamplerStates[MAXNUMSAMPLERSTATES][MAXNUMSTAGES];
2018-06-14 15:20:45 +02:00
static bool validStates[MAXNUMSTATES];
static bool validTexStates[MAXNUMTEXSTATES];
static D3DMATERIAL9 d3dmaterial;
static uint32 blendMap[] = {
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,
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
};
2017-08-09 10:57:32 +02:00
// 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;
}
}
}
2017-12-30 11:43:17 +01:00
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++;
}
}
}
2017-12-30 11:43:17 +01:00
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){
2017-08-09 10:57:32 +02:00
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){
2017-08-09 10:57:32 +02:00
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){
2017-08-09 10:57:32 +02:00
d3ddevice->SetSamplerState(stage, (D3DSAMPLERSTATETYPE)type, value);
d3dSamplerStates[type][stage] = value;
}
}
2017-12-30 11:43:17 +01:00
void
getSamplerState(uint32 stage, uint32 type, uint32 *value)
{
*value = d3dSamplerStates[type][stage];
}
2017-10-20 22:38:28 +02:00
// Bring D3D device in accordance with saved render states (after a reset)
static void
resetD3d9Device(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]);
2017-10-20 22:38:28 +02:00
}
for(s = 0; s < MAXNUMSTATES; s++)
2018-06-14 15:20:45 +02:00
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++)
2017-10-20 22:38:28 +02:00
for(s = 0; s < MAXNUMSTAGES; s++)
d3ddevice->SetSamplerState(s, (D3DSAMPLERSTATETYPE)t, d3dSamplerStates[t][s]);
d3ddevice->SetMaterial(&d3dmaterial);
}
2017-08-09 10:57:32 +02:00
// RW render state
static void
setVertexAlpha(bool32 enable)
{
if(rwStateCache.vertexAlpha != enable){
if(!rwStateCache.textureAlpha){
2017-08-09 10:57:32 +02:00
setRenderState(D3DRS_ALPHABLENDENABLE, enable);
setRenderState(D3DRS_ALPHATESTENABLE, enable);
}
rwStateCache.vertexAlpha = enable;
2017-08-09 10:57:32 +02:00
}
}
void
setRasterStage(uint32 stage, Raster *raster)
{
2017-08-09 10:57:32 +02:00
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);
2017-08-09 10:57:32 +02:00
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){
2017-08-09 10:57:32 +02:00
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(0, D3DSAMP_MAGFILTER, filterConvMap_NoMIP[filter]);
setSamplerState(0, 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(0, 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(0, 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);
}
2017-11-15 19:23:50 +01:00
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
2018-01-03 18:02:02 +01:00
setMaterial(SurfaceProperties surfProps, rw::RGBA color)
{
D3DMATERIAL9 mat9;
D3DCOLORVALUE black = { 0, 0, 0, 0 };
2018-01-03 18:02:02 +01:00
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*ambmult;
mat9.Diffuse.r = color.red*diffmult;
mat9.Diffuse.g = color.green*diffmult;
mat9.Diffuse.b = color.blue*diffmult;
mat9.Diffuse.a = color.alpha*diffmult;
mat9.Power = 0.0f;
mat9.Emissive = black;
mat9.Specular = black;
2017-11-15 19:23:50 +01:00
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:
if(rwStateCache.ztest != bval){
rwStateCache.ztest = bval;
setRenderState(D3DRS_ZENABLE, rwStateCache.ztest);
}
break;
case ZWRITEENABLE:
if(rwStateCache.zwrite != bval){
rwStateCache.zwrite = bval;
setRenderState(D3DRS_ZWRITEENABLE, rwStateCache.zwrite);
}
break;
case FOGENABLE:
if(rwStateCache.fogenable != bval){
rwStateCache.fogenable = bval;
setRenderState(D3DRS_FOGENABLE, rwStateCache.fogenable);
};
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));
}} 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;
}
2018-01-09 23:09:26 +01:00
// 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;
return nil;
}
void*
createPixelShader(void *csosrc)
{
void *shdr;
if(d3ddevice->CreatePixelShader((DWORD*)csosrc, (IDirect3DPixelShader9**)&shdr) == D3D_OK)
return shdr;
return nil;
}
// Camera
2017-08-09 10:57:32 +02:00
static void
2016-07-05 11:36:43 +02:00
beginUpdate(Camera *cam)
{
float view[16], proj[16];
// View Matrix
Matrix inv;
2017-08-09 10:57:32 +02:00
Matrix::invert(&inv, cam->getFrame()->getLTM());
2016-07-05 11:36:43 +02:00
// 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;
2017-12-31 10:50:49 +01:00
memcpy(&cam->devView, view, sizeof(RawMatrix));
2017-08-09 10:57:32 +02:00
d3ddevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)view);
2016-07-05 11:36:43 +02:00
// Projection Matrix
2016-07-06 11:44:59 +02:00
float32 invwx = 1.0f/cam->viewWindow.x;
float32 invwy = 1.0f/cam->viewWindow.y;
float32 invz = 1.0f/(cam->farPlane-cam->nearPlane);
2016-07-05 11:36:43 +02:00
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;
2016-07-06 11:44:59 +02:00
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){
2016-07-06 11:44:59 +02:00
proj[10] = cam->farPlane*invz;
2016-07-05 11:36:43 +02:00
proj[11] = 1.0f;
proj[15] = 0.0f;
}else{
proj[10] = invz;
proj[11] = 0.0f;
proj[15] = 1.0f;
}
2016-07-06 11:44:59 +02:00
proj[14] = -cam->nearPlane*proj[10];
2017-12-31 10:50:49 +01:00
memcpy(&cam->devProj, proj, sizeof(RawMatrix));
2017-08-09 10:57:32 +02:00
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);
2017-12-31 10:50:49 +01:00
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);
2017-08-09 10:57:32 +02:00
// TODO: figure out when to call this
d3ddevice->BeginScene();
2016-07-05 11:36:43 +02:00
}
2017-08-09 10:57:32 +02:00
static void
endUpdate(Camera *cam)
{
// TODO: figure out when to call this
d3ddevice->EndScene();
}
2018-01-08 12:55:15 +01:00
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){
deleteObject(natras->texture);
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;
}
}
}
2017-08-09 10:57:32 +02:00
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);
2017-10-20 22:38:28 +02:00
RECT r;
GetClientRect(d3d9Globals.window, &r);
BOOL icon = IsIconic(d3d9Globals.window);
Raster *ras = cam->frameBuffer;
if(!icon &&
(r.right != d3d9Globals.presentWidth || r.bottom != d3d9Globals.presentHeight)){
2018-01-08 12:55:15 +01:00
releaseVidmemRasters();
2017-10-20 22:38:28 +02:00
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = r.right;
d3dpp.BackBufferHeight = r.bottom;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = d3d9Globals.window;
d3dpp.Windowed = d3d9Globals.windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
2017-12-30 11:43:17 +01:00
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
// d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2017-10-20 22:38:28 +02:00
// TODO: check result
d3d::d3ddevice->Reset(&d3dpp);
d3d9Globals.presentWidth = r.right;
d3d9Globals.presentHeight = r.bottom;
resetD3d9Device();
}
2017-08-09 10:57:32 +02:00
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);
2017-08-09 10:57:32 +02:00
d3ddevice->Present(nil, nil, 0, nil);
}
// taken from Frank Luna's d3d9 book
static int
2017-08-29 10:12:56 +02:00
openD3D(EngineStartParams *params)
2017-08-09 10:57:32 +02:00
{
HWND win = params->window;
bool windowed = true;
2017-10-20 22:38:28 +02:00
d3d9Globals.window = win;
d3d9Globals.windowed = windowed;
2017-08-09 10:57:32 +02:00
HRESULT hr = 0;
IDirect3D9 *d3d9 = 0;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if(!d3d9){
RWERROR((ERR_GENERAL, "Direct3DCreate9() failed"));
return 0;
}
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int vp = 0;
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
RECT rect;
GetClientRect(win, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
2017-10-20 22:38:28 +02:00
d3d9Globals.presentWidth = width;
d3d9Globals.presentHeight = height;
2017-08-09 10:57:32 +02:00
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = win;
d3dpp.Windowed = windowed;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
2017-12-30 11:43:17 +01:00
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
// d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
2017-08-09 10:57:32 +02:00
IDirect3DDevice9 *dev;
hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, win,
vp, &d3dpp, &dev);
if(FAILED(hr)){
// try again using a 16-bit depth buffer
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
win, vp, &d3dpp, &dev);
if(FAILED(hr)){
RWERROR((ERR_GENERAL, "CreateDevice() failed"));
d3d9->Release();
return 0;
}
}
d3d9->Release();
d3d::d3ddevice = dev;
return 1;
}
static int
2017-08-29 10:12:56 +02:00
closeD3D(void)
2016-07-05 11:36:43 +02:00
{
2017-08-09 10:57:32 +02:00
d3d::d3ddevice->Release();
d3d::d3ddevice = nil;
return 1;
2016-07-05 11:36:43 +02:00
}
2017-08-09 10:57:32 +02:00
static int
initD3D(void)
{
2017-10-20 22:38:28 +02:00
int32 s, t;
2017-08-09 10:57:32 +02:00
// TODO: do some real stuff here
d3ddevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
rwStateCache.alphafunc = ALPHAGREATEREQUAL;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_ALPHAREF, 10);
rwStateCache.alpharef = 10;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
rwStateCache.fogenable = 0;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR);
// TODO: more fog stuff
d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
rwStateCache.cullmode = CULLNONE;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
rwStateCache.srcblend = BLENDSRCALPHA;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
rwStateCache.destblend = BLENDINVSRCALPHA;
2017-08-09 10:57:32 +02:00
d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 0);
rwStateCache.vertexAlpha = 0;
rwStateCache.textureAlpha = 0;
2017-08-09 10:57:32 +02:00
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);
2018-06-14 15:20:45 +02:00
// 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;
2017-10-20 22:38:28 +02:00
// Save the current states
2018-06-14 15:20:45 +02:00
for(s = 0; s < MAXNUMSTATES; s++)
if(validStates[s]){
d3ddevice->GetRenderState((D3DRENDERSTATETYPE)s, (DWORD*)&d3dStates[s]);
stateCache[s].value = d3dStates[s];
2017-11-15 19:23:50 +01:00
}
2018-06-14 15:20:45 +02:00
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++)
2017-11-15 19:23:50 +01:00
for(s = 0; s < MAXNUMSTAGES; s++){
2017-10-20 22:38:28 +02:00
d3ddevice->GetSamplerState(s, (D3DSAMPLERSTATETYPE)t, (DWORD*)&d3dSamplerStates[t][s]);
2017-11-15 19:23:50 +01:00
d3dSamplerStates[t][s] = d3dSamplerStates[t][s];
}
2017-10-20 22:38:28 +02:00
openIm2D();
2017-08-29 10:12:56 +02:00
openIm3D();
return 1;
}
2017-08-29 10:12:56 +02:00
static int
termD3D(void)
{
closeIm3D();
closeIm2D();
return 1;
}
static int
finalizeD3D(void)
{
2017-08-09 10:57:32 +02:00
return 1;
}
static int
deviceSystem(DeviceReq req, void *arg0)
{
switch(req){
2017-08-29 10:12:56 +02:00
case DEVICEOPEN:
return openD3D((EngineStartParams*)arg0);
case DEVICECLOSE:
return closeD3D();
2017-08-09 10:57:32 +02:00
case DEVICEINIT:
return initD3D();
2017-08-29 10:12:56 +02:00
case DEVICETERM:
return termD3D();
case DEVICEFINALIZE:
return finalizeD3D();
2017-08-09 10:57:32 +02:00
}
return 1;
}
Device renderdevice = {
0.0f, 1.0f,
d3d::beginUpdate,
d3d::endUpdate,
d3d::clearCamera,
d3d::showRaster,
d3d::setRwRenderState,
d3d::getRwRenderState,
d3d::im2DRenderIndexedPrimitive,
2017-08-29 10:12:56 +02:00
d3d::im3DTransform,
d3d::im3DRenderIndexed,
d3d::im3DEnd,
2017-08-09 10:57:32 +02:00
d3d::deviceSystem,
};
#endif
}
}