Files
BlitzNext/Runtime/gfx/gxscene.cpp
T
Michael Fabian 'Xaymar' Dirks a16218e1d5 runtime: CMake-ify gx
2019-01-18 17:03:37 +01:00

738 lines
19 KiB
C++

#include "gxscene.hpp"
#include "gxgraphics.hpp"
#include "gxruntime.hpp"
#include "std.hpp"
static bool can_wb;
static int hw_tex_stages, tex_stages;
static float BLACK[] = {0, 0, 0};
static float WHITE[] = {1, 1, 1};
static float GRAY[] = {.5f, .5f, .5f};
static D3DMATRIX sphere_mat, nullmatrix;
void gxScene::setRS(int n, int t)
{
if (d3d_rs[n] == t)
return;
dir3dDev->SetRenderState((D3DRENDERSTATETYPE)n, t);
d3d_rs[n] = t;
}
void gxScene::setTSS(int n, int s, int t)
{
if (d3d_tss[n][s] == t)
return;
dir3dDev->SetTextureStageState(n, (D3DTEXTURESTAGESTATETYPE)s, t);
d3d_tss[n][s] = t;
}
gxScene::gxScene(gxGraphics* g, gxCanvas* t) : graphics(g), target(t), dir3dDev(g->dir3dDev), n_texs(0), tris_drawn(0)
{
memset(d3d_rs, 0x55, sizeof(d3d_rs));
memset(d3d_tss, 0x55, sizeof(d3d_tss));
//nomalize normals
setRS(D3DRENDERSTATE_NORMALIZENORMALS, TRUE);
//vertex coloring
setRS(D3DRENDERSTATE_COLORVERTEX, FALSE);
setRS(D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
setRS(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1);
setRS(D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);
setRS(D3DRENDERSTATE_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
//Alpha test
setRS(D3DRENDERSTATE_ALPHATESTENABLE, false);
setRS(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER);
setRS(D3DRENDERSTATE_ALPHAREF, 128);
//source/dest blending modes
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
//suss out caps
can_wb = false;
hw_tex_stages = 1;
D3DDEVICEDESC7 devDesc = {0};
if (dir3dDev->GetCaps(&devDesc) >= 0) {
DWORD caps = devDesc.dpcTriCaps.dwRasterCaps;
//texture stages
hw_tex_stages = devDesc.wMaxSimultaneousTextures;
//depth buffer mode
if ((caps & D3DPRASTERCAPS_WBUFFER) && graphics->zbuffFmt.dwRGBBitCount == 16)
can_wb = true;
//fog mode
if ((caps & D3DPRASTERCAPS_FOGTABLE) && (caps & D3DPRASTERCAPS_WFOG)) {
setRS(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_NONE);
setRS(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_LINEAR);
} else {
setRS(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE);
setRS(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
}
}
tex_stages = hw_tex_stages;
caps_level = 100;
if (devDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_CUBEMAP) {
caps_level = 110;
}
//default texture states
for (int n = 0; n < hw_tex_stages; ++n) {
setTSS(n, D3DTSS_COLORARG1, D3DTA_TEXTURE);
setTSS(n, D3DTSS_COLORARG2, D3DTA_CURRENT);
setTSS(n, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
setTSS(n, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
setTSS(n, D3DTSS_MINFILTER, D3DTFN_LINEAR);
setTSS(n, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
setTSS(n, D3DTSS_MIPFILTER, D3DTFP_LINEAR);
}
setHWMultiTex(true);
//ATI lighting hack
dir3dDev->LightEnable(0, true);
dir3dDev->LightEnable(0, false);
//globals
sphere_mat._11 = .5f;
sphere_mat._22 = -.5f;
sphere_mat._33 = .5f;
sphere_mat._41 = .5f;
sphere_mat._42 = .5f;
sphere_mat._43 = .5f;
nullmatrix._11 = nullmatrix._22 = nullmatrix._33 = nullmatrix._44 = 1;
//set null renderstate
memset(&material, 0, sizeof(material));
shininess = 0;
blend = BLEND_REPLACE;
fx = 0;
for (int k = 0; k < MAX_TEXTURES; ++k)
memset(&texstate[k], 0, sizeof(texstate[k]));
wbuffer = can_wb;
dither = false;
setDither(true);
antialias = true;
setAntialias(false);
wireframe = true;
setWireframe(false);
flipped = true;
setFlippedTris(false);
ambient = ~0;
setAmbient(GRAY);
ambient2 = ~0;
setAmbient2(BLACK);
fogcolor = ~0;
setFogColor(BLACK);
fogrange_nr = fogrange_fr = 0;
setFogRange(1, 1000);
fogmode = FOG_LINEAR;
setFogMode(FOG_NONE);
zmode = -1;
setZMode(ZMODE_NORMAL);
memset(&projmatrix, 0, sizeof(projmatrix));
ortho_proj = true;
frustum_nr = frustum_fr = frustum_w = frustum_h = 0;
setPerspProj(1, 1000, 1, 1);
memset(&viewport, 0, sizeof(viewport));
viewport.dvMaxZ = 1;
setViewport(0, 0, target->getWidth(), target->getHeight());
viewmatrix = nullmatrix;
setViewMatrix(0);
worldmatrix = nullmatrix;
setWorldMatrix(0);
//set default renderstate
blend = fx = ~0;
shininess = 1;
RenderState state;
memset(&state, 0, sizeof(state));
state.color[0] = state.color[1] = state.color[2] = state.alpha = 1;
state.blend = BLEND_REPLACE;
setRenderState(state);
}
gxScene::~gxScene()
{
while (_allLights.size())
freeLight(*_allLights.begin());
}
void gxScene::setTexState(int n, const TexState& state, bool tex_blend)
{
int flags = state.canvas->getFlags();
int tc_index = state.flags & TEX_COORDS2 ? 1 : 0;
//set canvas
dir3dDev->SetTexture(n, state.canvas->getTexSurface());
//set addressing modes
setTSS(n, D3DTSS_ADDRESSU, (flags & gxCanvas::CANVAS_TEX_CLAMPU) ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP);
setTSS(n, D3DTSS_ADDRESSV, (flags & gxCanvas::CANVAS_TEX_CLAMPV) ? D3DTADDRESS_CLAMP : D3DTADDRESS_WRAP);
//texgen
switch (flags & (gxCanvas::CANVAS_TEX_SPHERE | gxCanvas::CANVAS_TEX_CUBE)) {
case gxCanvas::CANVAS_TEX_SPHERE:
setTSS(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL); //|tc_index );
setTSS(n, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
dir3dDev->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0 + n), &sphere_mat);
break;
case gxCanvas::CANVAS_TEX_CUBE:
switch (state.canvas->cubeMode() & 3) {
case gxCanvas::CUBEMODE_NORMAL:
setTSS(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL); //|tc_index );
break;
case gxCanvas::CUBEMODE_POSITION:
setTSS(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); //|tc_index );
break;
default:
setTSS(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR); //|tc_index );
break;
}
if (state.canvas->cubeMode() & 4) {
setTSS(n, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
} else {
setTSS(n, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3); //COUNT4|D3DTTFF_PROJECTED );
dir3dDev->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0 + n), &inv_viewmatrix);
}
break;
default:
setTSS(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU | tc_index);
if (state.mat_valid) {
setTSS(n, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
dir3dDev->SetTransform((D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0 + n), (D3DMATRIX*)&state.matrix);
} else {
setTSS(n, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
}
}
if (!tex_blend)
return;
//blending
switch (state.blend) {
case BLEND_ALPHA:
setTSS(n, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
break;
case BLEND_MULTIPLY:
setTSS(n, D3DTSS_COLOROP, D3DTOP_MODULATE);
break;
case BLEND_ADD:
setTSS(n, D3DTSS_COLOROP, D3DTOP_ADD);
break;
case BLEND_DOT3:
setTSS(n, D3DTSS_COLOROP, D3DTOP_DOTPRODUCT3);
break;
case BLEND_MULTIPLY2:
setTSS(n, D3DTSS_COLOROP, D3DTOP_MODULATE2X);
break;
}
setTSS(n, D3DTSS_ALPHAOP, (flags & gxCanvas::CANVAS_TEX_ALPHA) ? D3DTOP_MODULATE : D3DTOP_SELECTARG2);
}
int gxScene::hwTexUnits()
{
return tex_stages;
}
int gxScene::gfxDriverCaps3D()
{
return caps_level;
}
void gxScene::setZMode()
{
switch (zmode) {
case ZMODE_NORMAL:
setRS(D3DRENDERSTATE_ZENABLE, wbuffer ? D3DZB_USEW : D3DZB_TRUE);
setRS(D3DRENDERSTATE_ZWRITEENABLE, true);
break;
case ZMODE_DISABLE:
setRS(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
setRS(D3DRENDERSTATE_ZWRITEENABLE, false);
break;
case ZMODE_CMPONLY:
setRS(D3DRENDERSTATE_ZENABLE, wbuffer ? D3DZB_USEW : D3DZB_TRUE);
setRS(D3DRENDERSTATE_ZWRITEENABLE, false);
break;
}
}
void gxScene::setLights()
{
if (fx & FX_FULLBRIGHT) {
//no lights on
for (int n = 0; n < _curLights.size(); ++n)
dir3dDev->LightEnable(n, false);
} else if (fx & FX_CONDLIGHT) {
//some lights on
for (int n = 0; n < _curLights.size(); ++n) {
gxLight* light = _curLights[n];
bool enable = light->d3d_light.dltType != D3DLIGHT_DIRECTIONAL;
dir3dDev->LightEnable(n, enable);
}
} else {
//all lights on
for (int n = 0; n < _curLights.size(); ++n)
dir3dDev->LightEnable(n, true);
}
}
void gxScene::setAmbient()
{
int n = (fx & FX_FULLBRIGHT) ? 0xffffff : ((fx & FX_CONDLIGHT) ? ambient2 : ambient);
setRS(D3DRENDERSTATE_AMBIENT, n);
}
void gxScene::setFogMode()
{
bool fog = fogmode == FOG_LINEAR && !(fx & FX_NOFOG);
setRS(D3DRENDERSTATE_FOGENABLE, fog);
}
void gxScene::setTriCull()
{
if (fx & FX_DOUBLESIDED) {
setRS(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
} else if (flipped) {
setRS(D3DRENDERSTATE_CULLMODE, D3DCULL_CW);
} else {
setRS(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
}
}
void gxScene::setHWMultiTex(bool e)
{
for (int n = 0; n < 8; ++n) {
setTSS(n, D3DTSS_COLOROP, D3DTOP_DISABLE);
setTSS(n, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
dir3dDev->SetTexture(n, 0);
}
for (int k = 0; k < MAX_TEXTURES; ++k) {
memset(&texstate[k], 0, sizeof(texstate[k]));
}
tex_stages = e ? hw_tex_stages : 1;
n_texs = 0;
}
void gxScene::setWBuffer(bool n)
{
if (n == wbuffer || !can_wb)
return;
wbuffer = n;
setZMode();
}
void gxScene::setDither(bool n)
{
if (n == dither)
return;
dither = n;
setRS(D3DRENDERSTATE_DITHERENABLE, dither ? true : false);
}
void gxScene::setAntialias(bool n)
{
if (n == antialias)
return;
antialias = n;
setRS(D3DRENDERSTATE_ANTIALIAS, antialias ? D3DANTIALIAS_SORTINDEPENDENT : D3DANTIALIAS_NONE);
}
void gxScene::setWireframe(bool n)
{
if (n == wireframe)
return;
wireframe = n;
setRS(D3DRENDERSTATE_FILLMODE, wireframe ? D3DFILL_WIREFRAME : D3DFILL_SOLID);
}
void gxScene::setFlippedTris(bool n)
{
if (n == flipped)
return;
flipped = n;
setTriCull();
}
void gxScene::setAmbient(const float rgb[])
{
int n = (int(rgb[0] * 255.0f) << 16) | (int(rgb[1] * 255.0f) << 8) | int(rgb[2] * 255.0f);
ambient = n;
setAmbient();
}
void gxScene::setAmbient2(const float rgb[])
{
int n = (int(rgb[0] * 255.0f) << 16) | (int(rgb[1] * 255.0f) << 8) | int(rgb[2] * 255.0f);
ambient2 = n;
setAmbient();
}
void gxScene::setViewport(int x, int y, int w, int h)
{
if (x == viewport.dwX && y == viewport.dwY && w == viewport.dwWidth && h == viewport.dwHeight)
return;
viewport.dwX = x;
viewport.dwY = y;
viewport.dwWidth = w;
viewport.dwHeight = h;
dir3dDev->SetViewport(&viewport);
}
void gxScene::setOrthoProj(float nr, float fr, float w, float h)
{
if (ortho_proj && nr == frustum_nr && fr == frustum_fr && w == frustum_w && h == frustum_h)
return;
frustum_nr = nr;
frustum_fr = fr;
frustum_w = w;
frustum_h = h;
ortho_proj = true;
float W = 2 / w;
float H = 2 / h;
float Q = 1 / (fr - nr);
projmatrix._11 = W;
projmatrix._22 = H;
projmatrix._33 = Q;
projmatrix._34 = 0;
projmatrix._43 = -Q * nr;
projmatrix._44 = 1;
dir3dDev->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &projmatrix);
}
void gxScene::setPerspProj(float nr, float fr, float w, float h)
{
if (!ortho_proj && nr == frustum_nr && fr == frustum_fr && w == frustum_w && h == frustum_h)
return;
frustum_nr = nr;
frustum_fr = fr;
frustum_w = w;
frustum_h = h;
ortho_proj = false;
float W = 2 * nr / w;
float H = 2 * nr / h;
float Q = fr / (fr - nr);
projmatrix._11 = W;
projmatrix._22 = H;
projmatrix._33 = Q;
projmatrix._34 = 1;
projmatrix._43 = -Q * nr;
projmatrix._44 = 0;
dir3dDev->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &projmatrix);
}
void gxScene::setFogColor(const float rgb[3])
{
int n = (int(rgb[0] * 255.0f) << 16) | (int(rgb[1] * 255.0f) << 8) | int(rgb[2] * 255.0f);
if (n == fogcolor)
return;
fogcolor = n;
setRS(D3DRENDERSTATE_FOGCOLOR, fogcolor);
}
void gxScene::setFogRange(float nr, float fr)
{
if (nr == fogrange_nr && fr == fogrange_fr)
return;
fogrange_nr = nr;
fogrange_fr = fr;
setRS(D3DRENDERSTATE_FOGSTART, *(DWORD*)&fogrange_nr);
setRS(D3DRENDERSTATE_FOGEND, *(DWORD*)&fogrange_fr);
}
void gxScene::setFogMode(int n)
{
if (n == fogmode)
return;
fogmode = n;
setFogMode();
}
void gxScene::setZMode(int n)
{
if (n == zmode)
return;
zmode = n;
setZMode();
}
void gxScene::setViewMatrix(const Matrix* m)
{
if (m) {
memcpy(&viewmatrix._11, m->elements[0], 12);
memcpy(&viewmatrix._21, m->elements[1], 12);
memcpy(&viewmatrix._31, m->elements[2], 12);
memcpy(&viewmatrix._41, m->elements[3], 12);
inv_viewmatrix._11 = viewmatrix._11;
inv_viewmatrix._21 = viewmatrix._12;
inv_viewmatrix._31 = viewmatrix._13;
inv_viewmatrix._12 = viewmatrix._21;
inv_viewmatrix._22 = viewmatrix._22;
inv_viewmatrix._32 = viewmatrix._23;
inv_viewmatrix._13 = viewmatrix._31;
inv_viewmatrix._23 = viewmatrix._32;
inv_viewmatrix._33 = viewmatrix._33;
inv_viewmatrix._44 = viewmatrix._44;
} else {
viewmatrix = inv_viewmatrix = nullmatrix;
}
dir3dDev->SetTransform(D3DTRANSFORMSTATE_VIEW, &viewmatrix);
}
void gxScene::setWorldMatrix(const Matrix* m)
{
if (m) {
memcpy(&worldmatrix._11, m->elements[0], 12);
memcpy(&worldmatrix._21, m->elements[1], 12);
memcpy(&worldmatrix._31, m->elements[2], 12);
memcpy(&worldmatrix._41, m->elements[3], 12);
} else
worldmatrix = nullmatrix;
dir3dDev->SetTransform(D3DTRANSFORMSTATE_WORLD, &worldmatrix);
}
void gxScene::setRenderState(const RenderState& rs)
{
bool setmat = false;
if (memcmp(rs.color, &material.diffuse.r, 12)) {
memcpy(&material.diffuse.r, rs.color, 12);
memcpy(&material.ambient.r, rs.color, 12);
setmat = true;
}
if (rs.alpha != material.diffuse.a) {
material.diffuse.a = rs.alpha;
if (rs.fx & FX_ALPHATEST) {
int alpharef = (rs.fx & FX_VERTEXALPHA) ? 0 : 128 * rs.alpha;
setRS(D3DRENDERSTATE_ALPHAREF, alpharef);
}
setmat = true;
}
if (rs.shininess != shininess) {
shininess = rs.shininess;
float t = shininess > 0 ? (shininess < 1 ? shininess : 1) : 0;
material.specular.r = material.specular.g = material.specular.b = t;
material.power = shininess * 128;
setRS(D3DRENDERSTATE_SPECULARENABLE, shininess > 0 ? true : false);
setmat = true;
}
if (rs.blend != blend) {
blend = rs.blend;
switch (blend) {
case BLEND_REPLACE:
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, false);
break;
case BLEND_ALPHA:
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, true);
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
break;
case BLEND_MULTIPLY:
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, true);
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
break;
case BLEND_ADD:
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, true);
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
break;
}
}
if (rs.fx != fx) {
int t = rs.fx ^ fx;
fx = rs.fx;
if (t & (FX_FULLBRIGHT | FX_CONDLIGHT)) {
setLights();
setAmbient();
}
if (t & FX_VERTEXCOLOR) {
setRS(D3DRENDERSTATE_COLORVERTEX, fx & FX_VERTEXCOLOR ? true : false);
}
if (t & FX_FLATSHADED) {
setRS(D3DRENDERSTATE_SHADEMODE, fx & FX_FLATSHADED ? D3DSHADE_FLAT : D3DSHADE_GOURAUD);
}
if (t & FX_NOFOG) {
setFogMode();
}
if (t & FX_DOUBLESIDED) {
setTriCull();
}
if (t & FX_EMISSIVE) {
//Q3 Hack!
int n = fx & FX_EMISSIVE;
setRS(D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, n ? D3DMCS_MATERIAL : D3DMCS_COLOR1);
setRS(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, n ? D3DMCS_MATERIAL : D3DMCS_COLOR1);
setRS(D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, n ? D3DMCS_COLOR1 : D3DMCS_MATERIAL);
setRS(D3DRENDERSTATE_COLORVERTEX, n ? true : false);
}
if (t & FX_ALPHATEST) {
if (fx & FX_ALPHATEST) {
int alpharef = (rs.fx & FX_VERTEXALPHA) ? 0 : 128 * rs.alpha;
setRS(D3DRENDERSTATE_ALPHAREF, alpharef);
}
setRS(D3DRENDERSTATE_ALPHATESTENABLE, fx & FX_ALPHATEST ? true : false);
}
}
if (setmat) {
dir3dDev->SetMaterial(&material);
}
n_texs = 0;
TexState* hw = texstate;
for (int k = 0; k < MAX_TEXTURES; ++k) {
const RenderState::TexState& ts = rs.tex_states[k];
if (!ts.canvas || !ts.blend)
continue;
bool settex = false;
ts.canvas->getTexSurface(); //force mipmap rebuild
if (ts.canvas != hw->canvas) {
hw->canvas = ts.canvas;
settex = true;
}
if (ts.blend != hw->blend) {
hw->blend = ts.blend;
settex = true;
}
if (ts.flags != hw->flags) {
hw->flags = ts.flags;
settex = true;
}
if (ts.matrix || hw->mat_valid) {
if (ts.matrix) {
memcpy(&hw->matrix._11, ts.matrix->elements[0], 12);
memcpy(&hw->matrix._21, ts.matrix->elements[1], 12);
memcpy(&hw->matrix._31, ts.matrix->elements[2], 12);
memcpy(&hw->matrix._41, ts.matrix->elements[3], 12);
hw->mat_valid = true;
} else {
hw->mat_valid = false;
}
settex = true;
}
if (settex && n_texs < tex_stages) {
setTexState(n_texs, *hw, true);
}
++hw;
++n_texs;
}
if (n_texs < tex_stages && hw->canvas) {
hw->canvas = 0;
setTSS(n_texs, D3DTSS_COLOROP, D3DTOP_DISABLE);
setTSS(n_texs, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
dir3dDev->SetTexture(n_texs, 0);
}
}
bool gxScene::begin(const vector<gxLight*>& lights)
{
if (dir3dDev->BeginScene() != D3D_OK)
return false;
//clear textures!
int n;
for (n = 0; n < tex_stages; ++n) {
texstate[n].canvas = 0;
setTSS(n, D3DTSS_COLOROP, D3DTOP_DISABLE);
setTSS(n, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
dir3dDev->SetTexture(n, 0);
}
//set light states
_curLights.clear();
for (n = 0; n < 8; ++n) {
if (n < lights.size()) {
_curLights.push_back(lights[n]);
dir3dDev->SetLight(n, &_curLights[n]->d3d_light);
} else {
dir3dDev->LightEnable(n, false);
}
}
setLights();
return true;
}
void gxScene::clear(const float rgb[3], float alpha, float z, bool clear_argb, bool clear_z)
{
if (!clear_argb && !clear_z)
return;
int flags = (clear_argb ? D3DCLEAR_TARGET : 0) | (clear_z ? D3DCLEAR_ZBUFFER : 0);
unsigned argb =
(int(alpha * 255.0f) << 24) | (int(rgb[0] * 255.0f) << 16) | (int(rgb[1] * 255.0f) << 8) | int(rgb[2] * 255.0f);
dir3dDev->Clear(0, 0, flags, argb, z, 0);
}
void gxScene::render(gxMesh* m, int first_vert, int vert_cnt, int first_tri, int tri_cnt)
{
m->render(first_vert, vert_cnt, first_tri, tri_cnt);
tris_drawn += tri_cnt;
if (n_texs <= tex_stages)
return;
setTSS(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
setTSS(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
if (tex_stages > 1) {
setTSS(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
setTSS(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
}
setRS(D3DRENDERSTATE_LIGHTING, false);
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, true);
for (int k = tex_stages; k < n_texs; ++k) {
const TexState& state = texstate[k];
switch (state.blend) {
case BLEND_ALPHA:
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
break;
case BLEND_MULTIPLY:
case BLEND_DOT3:
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_DESTCOLOR);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ZERO);
break;
case BLEND_ADD:
setRS(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE);
setRS(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);
break;
}
setTexState(0, state, false);
m->render(first_vert, vert_cnt, first_tri, tri_cnt);
tris_drawn += tri_cnt;
}
setRS(D3DRENDERSTATE_ALPHABLENDENABLE, false);
setRS(D3DRENDERSTATE_LIGHTING, true);
if (tex_stages > 1)
setTexState(1, texstate[1], true);
setTexState(0, texstate[0], true);
}
void gxScene::end()
{
dir3dDev->EndScene();
RECT r = {viewport.dwX, viewport.dwY, viewport.dwX + viewport.dwWidth, viewport.dwY + viewport.dwHeight};
target->damage(r);
}
gxLight* gxScene::createLight(int flags)
{
gxLight* l = new gxLight(this, flags);
_allLights.insert(l);
return l;
}
void gxScene::freeLight(gxLight* l)
{
_allLights.erase(l);
}
int gxScene::getTrianglesDrawn() const
{
return tris_drawn;
}