#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& 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; }