absence_thelab
diff src/3deng/3dengine.cpp @ 0:1cffe3409164
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 23 Oct 2014 01:46:07 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/3deng/3dengine.cpp Thu Oct 23 01:46:07 2014 +0300 1.3 @@ -0,0 +1,1388 @@ 1.4 +#include <fstream> 1.5 +#include <string> 1.6 +#include <cmath> 1.7 +#include <cassert> 1.8 +#include "d3dx8.h" 1.9 +#include "3dengine.h" 1.10 +#include "exceptions.h" 1.11 +#include "3dgeom.h" 1.12 +#include "lights.h" 1.13 + 1.14 +// local helper functions 1.15 +ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt); 1.16 +D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha=false); 1.17 +D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil); 1.18 + 1.19 +///////////// Graphics Context Member Functions ///////////////// 1.20 + 1.21 +GraphicsContext::GraphicsContext() { 1.22 + D3DDevice = 0; 1.23 + BackfaceCulling = true; 1.24 +} 1.25 + 1.26 +/////////////////////////////////// 1.27 +// ----==( SetDefaultStates )==---- 1.28 +// (Public Member Function) 1.29 +// Sets the default render states 1.30 +/////////////////////////////////// 1.31 +void GraphicsContext::SetDefaultStates() { 1.32 + D3DDevice->SetRenderState(D3DRS_LOCALVIEWER, true); 1.33 + SetPrimitiveType(TriangleList); 1.34 + SetBackfaceCulling(true); 1.35 + SetFrontFace(Clockwise); 1.36 + SetLighting(true); 1.37 + SetColorVertex(false); 1.38 + SetAmbientLight(0.0f); 1.39 + SetMipMapping(true); 1.40 + SetTextureFiltering(BilinearFiltering); 1.41 + SetBillboarding(false); 1.42 + SetSpecular(true); 1.43 + 1.44 + Matrix4x4 ProjMat; 1.45 + CreateProjectionMatrix(&ProjMat, QuarterPi, 1.33333333f, 1.0f, 10000.0f); 1.46 + SetProjectionMatrix(ProjMat); 1.47 +} 1.48 + 1.49 + 1.50 +bool GraphicsContext::CreateVertexBuffer(uint32 VertexCount, UsageFlags usage, VertexBuffer **vb) const { 1.51 + long hr = D3DDevice->CreateVertexBuffer(VertexCount * sizeof(Vertex), (dword)usage, VertexFormat, D3DPOOL_DEFAULT, vb); 1.52 + return (hr == D3D_OK); 1.53 +} 1.54 + 1.55 +bool GraphicsContext::CreateIndexBuffer(uint32 IndexCount, UsageFlags usage, IndexBuffer **ib) const { 1.56 + long hr = D3DDevice->CreateIndexBuffer(IndexCount * IndexSize, (dword)usage, IndexFormat, D3DPOOL_DEFAULT, ib); 1.57 + return (hr == D3D_OK); 1.58 +} 1.59 + 1.60 +bool GraphicsContext::CreateSurface(uint32 Width, uint32 Height, Surface **surf) const { 1.61 + long hr = D3DDevice->CreateImageSurface(Width, Height, ColorFormat, surf); 1.62 + return (hr == D3D_OK); 1.63 +} 1.64 + 1.65 +bool GraphicsContext::CreateDepthStencil(uint32 Width, uint32 Height, Surface **zsurf) const { 1.66 + long hr = D3DDevice->CreateDepthStencilSurface(Width, Height, ZFormat, (D3DMULTISAMPLE_TYPE)AASamples, zsurf); 1.67 + return (hr == D3D_OK); 1.68 +} 1.69 + 1.70 +void GraphicsContext::Clear(dword color) const { 1.71 + D3DDevice->Clear(0, 0, D3DCLEAR_TARGET, color, 1.0f, 0); 1.72 +} 1.73 + 1.74 +void GraphicsContext::ClearZBuffer(float zval) const { 1.75 + D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, zval, 0); 1.76 +} 1.77 + 1.78 +void GraphicsContext::ClearStencil(byte sval) const { 1.79 + D3DDevice->Clear(0, 0, D3DCLEAR_STENCIL, 0, 1.0f, sval); 1.80 +} 1.81 + 1.82 +void GraphicsContext::ClearZBufferStencil(float zval, byte sval) const { 1.83 + D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, zval, sval); 1.84 +} 1.85 + 1.86 +void GraphicsContext::Flip() const { 1.87 + D3DDevice->Present(0, 0, 0, 0); 1.88 +} 1.89 + 1.90 + 1.91 +bool GraphicsContext::Draw(VertexBuffer *vb) { 1.92 + D3DVERTEXBUFFER_DESC desc; 1.93 + vb->GetDesc(&desc); 1.94 + unsigned int verts = desc.Size / sizeof(Vertex); 1.95 + 1.96 + D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); 1.97 + long res = D3DDevice->DrawPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts / 3); 1.98 + D3DDevice->SetStreamSource(0, 0, 0); 1.99 + return res == D3D_OK; 1.100 +} 1.101 + 1.102 +bool GraphicsContext::Draw(Vertex *varray, unsigned int VertexCount) { 1.103 + long res = D3DDevice->DrawPrimitiveUP((D3DPRIMITIVETYPE)ptype, VertexCount / 3, varray, sizeof(Vertex)); 1.104 + return res == D3D_OK; 1.105 +} 1.106 + 1.107 +bool GraphicsContext::Draw(VertexBuffer *vb, IndexBuffer *ib) { 1.108 + D3DVERTEXBUFFER_DESC vbdesc; 1.109 + vb->GetDesc(&vbdesc); 1.110 + unsigned int verts = vbdesc.Size / sizeof(Vertex); 1.111 + 1.112 + D3DINDEXBUFFER_DESC ibdesc; 1.113 + ib->GetDesc(&ibdesc); 1.114 + unsigned int indices = ibdesc.Size / sizeof(Index); 1.115 + 1.116 + D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); 1.117 + D3DDevice->SetIndices(ib, 0); 1.118 + long res = D3DDevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts, 0, indices / 3); 1.119 + D3DDevice->SetIndices(0, 0); 1.120 + D3DDevice->SetStreamSource(0, 0, 0); 1.121 + return res == D3D_OK; 1.122 +} 1.123 + 1.124 +bool GraphicsContext::Draw(Vertex *varray, Index *iarray, unsigned int VertexCount, unsigned int IndexCount) { 1.125 + long res = D3DDevice->DrawIndexedPrimitiveUP((D3DPRIMITIVETYPE)ptype, 0, VertexCount, IndexCount / 3, iarray, IndexFormat, varray, sizeof(Vertex)); 1.126 + return res == D3D_OK; 1.127 +} 1.128 + 1.129 +bool GraphicsContext::Draw(Vertex *varray, Triangle *triarray, unsigned int VertexCount, unsigned int TriCount) { 1.130 + unsigned int IndexCount = TriCount * 3; 1.131 + Index *iarray = new Index[IndexCount]; 1.132 + for(dword i=0; i<TriCount; i++) { 1.133 + iarray[i*3] = triarray[i].vertices[0]; 1.134 + iarray[i*3+1] = triarray[i].vertices[1]; 1.135 + iarray[i*3+2] = triarray[i].vertices[2]; 1.136 + } 1.137 + long res = Draw(varray, iarray, VertexCount, IndexCount); 1.138 + return res == D3D_OK; 1.139 +} 1.140 + 1.141 +////////////// State Setting Interface /////////////// 1.142 + 1.143 +void GraphicsContext::SetPrimitiveType(PrimitiveType pt) { 1.144 + ptype = pt; 1.145 +} 1.146 + 1.147 +void GraphicsContext::SetBackfaceCulling(bool enable) { 1.148 + if(enable) { 1.149 + D3DDevice->SetRenderState(D3DRS_CULLMODE, CullOrder); 1.150 + } else { 1.151 + D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); 1.152 + } 1.153 + BackfaceCulling = enable; 1.154 +} 1.155 + 1.156 +void GraphicsContext::SetFrontFace(FaceOrder order) { 1.157 + if(order == Clockwise) { 1.158 + CullOrder = CounterClockwise; 1.159 + } else { 1.160 + CullOrder = Clockwise; 1.161 + } 1.162 + if(BackfaceCulling) SetBackfaceCulling(BackfaceCulling); 1.163 +} 1.164 + 1.165 +void GraphicsContext::SetAutoNormalize(bool enable) { 1.166 + D3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, enable); 1.167 +} 1.168 + 1.169 +void GraphicsContext::SetBillboarding(bool enable) { 1.170 + BillBoardingEnabled = enable; 1.171 + if(enable) { 1.172 + 1.173 + Vector3 pos; 1.174 + pos.Transform(WorldMat[0]); 1.175 + 1.176 + Matrix4x4 world; 1.177 + world.Translate(pos.x, pos.y, pos.z); 1.178 + Matrix4x4 BillBoardRot; 1.179 + 1.180 + Vector3 dir = ViewMat.Inverse().GetRowVector(2); 1.181 + float yangle = dir.x > 0.0f ? -atanf(dir.z / dir.x) + HalfPi : -atanf(dir.z / dir.x) - HalfPi; 1.182 + 1.183 + BillBoardRot.Rotate(0.0f, yangle, 0.0f); 1.184 + Vector3 xaxis = VECTOR3_I; 1.185 + Vector3 normal = -VECTOR3_K; 1.186 + xaxis.Transform(BillBoardRot); 1.187 + normal.Transform(BillBoardRot); 1.188 + 1.189 + // find angle between quad normal and view direction 1.190 + float xangle = acosf(DotProduct(normal, dir.Normalized())); 1.191 + BillBoardRot.Rotate(xaxis, xangle); 1.192 + 1.193 + world = BillBoardRot * world; 1.194 + 1.195 + D3DDevice->SetTransform(D3DTS_WORLD, &world); 1.196 + //D3DDevice->SetTransform(D3DTS_VIEW, &BillboardViewMatrix); 1.197 + } else { 1.198 + D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat[0]); 1.199 + //D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat); 1.200 + } 1.201 +} 1.202 + 1.203 +void GraphicsContext::SetColorWrite(bool red, bool green, bool blue, bool alpha) { 1.204 + dword channels = 0; 1.205 + if(red) channels |= D3DCOLORWRITEENABLE_RED; 1.206 + if(green) channels |= D3DCOLORWRITEENABLE_GREEN; 1.207 + if(blue) channels |= D3DCOLORWRITEENABLE_BLUE; 1.208 + if(alpha) channels |= D3DCOLORWRITEENABLE_ALPHA; 1.209 + 1.210 + D3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, channels); 1.211 +} 1.212 + 1.213 +// blending states 1.214 +void GraphicsContext::SetAlphaBlending(bool enable) { 1.215 + D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, enable); 1.216 +} 1.217 + 1.218 +void GraphicsContext::SetBlendFunc(BlendingFactor src, BlendingFactor dest) { 1.219 + D3DDevice->SetRenderState(D3DRS_SRCBLEND, src); 1.220 + D3DDevice->SetRenderState(D3DRS_DESTBLEND, dest); 1.221 +} 1.222 + 1.223 +// zbuffer states 1.224 +void GraphicsContext::SetZBuffering(bool enable) { 1.225 + D3DDevice->SetRenderState(D3DRS_ZENABLE, enable); 1.226 +} 1.227 + 1.228 +void GraphicsContext::SetZWrite(bool enable) { 1.229 + D3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, enable); 1.230 +} 1.231 + 1.232 +void GraphicsContext::SetZFunc(CmpFunc func) { 1.233 + D3DDevice->SetRenderState(D3DRS_ZFUNC, func); 1.234 +} 1.235 + 1.236 +// set stencil buffer states 1.237 +void GraphicsContext::SetStencilBuffering(bool enable) { 1.238 + D3DDevice->SetRenderState(D3DRS_STENCILENABLE, enable); 1.239 +} 1.240 + 1.241 +void GraphicsContext::SetStencilPassOp(StencilOp sop) { 1.242 + D3DDevice->SetRenderState(D3DRS_STENCILPASS, sop); 1.243 +} 1.244 + 1.245 +void GraphicsContext::SetStencilFailOp(StencilOp sop) { 1.246 + D3DDevice->SetRenderState(D3DRS_STENCILFAIL, sop); 1.247 +} 1.248 + 1.249 +void GraphicsContext::SetStencilPassZFailOp(StencilOp sop) { 1.250 + D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, sop); 1.251 +} 1.252 + 1.253 +void GraphicsContext::SetStencilOp(StencilOp Fail, StencilOp StencilPassZFail, StencilOp Pass) { 1.254 + D3DDevice->SetRenderState(D3DRS_STENCILPASS, Pass); 1.255 + D3DDevice->SetRenderState(D3DRS_STENCILFAIL, Fail); 1.256 + D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, StencilPassZFail); 1.257 +} 1.258 + 1.259 +void GraphicsContext::SetStencilFunc(CmpFunc func) { 1.260 + D3DDevice->SetRenderState(D3DRS_STENCILFUNC, func); 1.261 +} 1.262 + 1.263 +void GraphicsContext::SetStencilReference(dword value) { 1.264 + D3DDevice->SetRenderState(D3DRS_STENCILREF, value); 1.265 +} 1.266 + 1.267 +// texture & material states 1.268 + 1.269 +void GraphicsContext::SetTextureFactor(dword factor) { 1.270 + D3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, factor); 1.271 +} 1.272 + 1.273 +void GraphicsContext::SetTextureFiltering(TextureFilteringType texfilter, int TextureStage) { 1.274 + dword TexFilter, MipFilter; 1.275 + 1.276 + switch(texfilter) { 1.277 + case PointSampling: 1.278 + TexFilter = MipFilter = D3DTEXF_POINT; 1.279 + break; 1.280 + 1.281 + case BilinearFiltering: 1.282 + TexFilter = D3DTEXF_LINEAR; 1.283 + MipFilter = D3DTEXF_POINT; 1.284 + break; 1.285 + 1.286 + case TrilinearFiltering: 1.287 + TexFilter = MipFilter = D3DTEXF_LINEAR; 1.288 + break; 1.289 + 1.290 + case AnisotropicFiltering: 1.291 + TexFilter = D3DTEXF_ANISOTROPIC; 1.292 + MipFilter = D3DTEXF_LINEAR; 1.293 + break; 1.294 + 1.295 + default: break; 1.296 + } 1.297 + 1.298 + this->MipFilter = MipFilter; 1.299 + 1.300 + if(!MipMapEnabled) MipFilter = D3DTEXF_NONE; 1.301 + 1.302 + if(TextureStage == 0xa11) { 1.303 + for(int i=0; i<MaxTextureStages; i++) { 1.304 + D3DDevice->SetTextureStageState(i, D3DTSS_MINFILTER, TexFilter); 1.305 + D3DDevice->SetTextureStageState(i, D3DTSS_MAGFILTER, TexFilter); 1.306 + D3DDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, MipFilter); 1.307 + } 1.308 + } else { 1.309 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MINFILTER, TexFilter); 1.310 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MAGFILTER, TexFilter); 1.311 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, MipFilter); 1.312 + } 1.313 +} 1.314 + 1.315 +void GraphicsContext::SetTextureAddressing(TextureAddressing uaddr, TextureAddressing vaddr, int TextureStage) { 1.316 + if(TextureStage == 0xa11) { 1.317 + for(int i=0; i<MaxTextureStages; i++) { 1.318 + D3DDevice->SetTextureStageState(i, D3DTSS_ADDRESSU, uaddr); 1.319 + D3DDevice->SetTextureStageState(i, D3DTSS_ADDRESSV, vaddr); 1.320 + } 1.321 + } else { 1.322 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSU, uaddr); 1.323 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSV, vaddr); 1.324 + } 1.325 +} 1.326 + 1.327 +void GraphicsContext::SetTextureBorderColor(dword color, int TextureStage) { 1.328 + if(TextureStage == 0xa11) { 1.329 + for(int i=0; i<MaxTextureStages; i++) { 1.330 + D3DDevice->SetTextureStageState(i, D3DTSS_BORDERCOLOR, color); 1.331 + } 1.332 + } else { 1.333 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_BORDERCOLOR, color); 1.334 + } 1.335 +} 1.336 + 1.337 +void GraphicsContext::SetTexture(int index, Texture *tex) { 1.338 + D3DDevice->SetTexture(index, tex); 1.339 +} 1.340 + 1.341 +void GraphicsContext::SetMipMapping(bool enable, int TextureStage) { 1.342 + MipMapEnabled = enable; 1.343 + dword mip = (enable ? MipFilter : D3DTEXF_NONE); 1.344 + 1.345 + if(TextureStage == 0xa11) { 1.346 + for(int i=0; i<MaxTextureStages; i++) { 1.347 + D3DDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, mip); 1.348 + } 1.349 + } else { 1.350 + D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, mip); 1.351 + } 1.352 +} 1.353 + 1.354 +void GraphicsContext::SetMaterial(const Material &mat) { 1.355 + D3DDevice->SetMaterial(&mat); 1.356 +} 1.357 + 1.358 +static unsigned long TLVertexFVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1; 1.359 + 1.360 +struct TLVertex { 1.361 + Vector3 pos; 1.362 + float rhw; 1.363 + unsigned long color; 1.364 + TexCoord tex; 1.365 + 1.366 + TLVertex() { 1.367 + pos = Vector3(0.0f, 0.0f, 0.0f); 1.368 + color = 0xffffffff; 1.369 + tex.u = tex.v = 0.0f; 1.370 + rhw = pos.z; 1.371 + } 1.372 + 1.373 + TLVertex(const Vector3 &pos, const Color &col, float u=0.0f, float v=0.0f) { 1.374 + this->pos = pos; 1.375 + rhw = pos.z; 1.376 + color = col.GetPacked32(); 1.377 + tex.u = u; 1.378 + tex.v = v; 1.379 + } 1.380 +}; 1.381 + 1.382 +void GraphicsContext::BlitTexture(const Texture *texture, RECT *rect, const Color &col) { 1.383 + bool norect = rect ? false : true; 1.384 + if(norect) { 1.385 + rect = new RECT; 1.386 + rect->left = rect->top = 0; 1.387 + rect->right = ContextParams.x; 1.388 + rect->bottom = ContextParams.y; 1.389 + } 1.390 + 1.391 + SetVertexProgram(TLVertexFVF); 1.392 + 1.393 + TLVertex tlverts[4]; 1.394 + tlverts[0] = TLVertex(Vector3((float)rect->right, (float)rect->top, 1.0f), col, 1.0f, 0.0f); 1.395 + tlverts[1] = TLVertex(Vector3((float)rect->right, (float)rect->bottom, 1.0f), col, 1.0f, 1.0f); 1.396 + tlverts[2] = TLVertex(Vector3((float)rect->left, (float)rect->top, 1.0f), col, 0.0f, 0.0f); 1.397 + tlverts[3] = TLVertex(Vector3((float)rect->left, (float)rect->bottom, 1.0f), col, 0.0f, 1.0f); 1.398 + 1.399 + EnableTextureStage(0); 1.400 + DisableTextureStage(1); 1.401 + SetTexture(0, const_cast<Texture*>(texture)); 1.402 + 1.403 + SetZBuffering(false); 1.404 + D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, tlverts, sizeof(TLVertex)); 1.405 + SetZBuffering(true); 1.406 + 1.407 + SetTexture(0, 0); 1.408 + 1.409 + SetVertexProgram(VertexFormat); 1.410 + 1.411 + if(norect) { 1.412 + delete rect; 1.413 + } 1.414 +} 1.415 + 1.416 +// multitexturing interface 1.417 +void GraphicsContext::EnableTextureStage(int stage) { 1.418 + SetTextureStageColor(stage, TexBlendModulate, TexArgTexture, TexArgCurrent); 1.419 +} 1.420 + 1.421 +void GraphicsContext::DisableTextureStage(int stage) { 1.422 + D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE); 1.423 +} 1.424 + 1.425 +void GraphicsContext::SetTextureStageColor(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) { 1.426 + D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, op); 1.427 + D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, arg1); 1.428 + D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, arg2); 1.429 + if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, arg3); 1.430 +} 1.431 + 1.432 +void GraphicsContext::SetTextureStageAlpha(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) { 1.433 + D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, op); 1.434 + D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, arg1); 1.435 + D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, arg2); 1.436 + if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, arg3); 1.437 +} 1.438 + 1.439 +void GraphicsContext::SetTextureCoordIndex(int stage, int index) { 1.440 + D3DDevice->SetTextureStageState(stage, D3DTSS_TEXCOORDINDEX, index); 1.441 +} 1.442 + 1.443 +void GraphicsContext::SetTextureTransformState(int stage, TexTransformState TexXForm) { 1.444 + D3DDevice->SetTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS, TexXForm); 1.445 +} 1.446 + 1.447 +// programmable pipeline interface 1.448 +void GraphicsContext::SetVertexProgram(dword vs) { 1.449 + D3DDevice->SetVertexShader(vs); 1.450 +} 1.451 + 1.452 +void GraphicsContext::SetPixelProgram(dword ps) { 1.453 + D3DDevice->SetPixelShader(ps); 1.454 +} 1.455 + 1.456 +dword GraphicsContext::CreateVertexProgram(const char *fname) { 1.457 + 1.458 + // vertex format declaration 1.459 + dword VertDecl[] = { 1.460 + D3DVSD_STREAM(0), 1.461 + D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), 1.462 + D3DVSD_REG(D3DVSDE_BLENDWEIGHT, D3DVSDT_FLOAT1), 1.463 + D3DVSD_REG(D3DVSDE_BLENDINDICES, D3DVSDT_UBYTE4), 1.464 + D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3), 1.465 + D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR), 1.466 + D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2), 1.467 + D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2), 1.468 + D3DVSD_REG(D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT2), 1.469 + D3DVSD_REG(D3DVSDE_TEXCOORD3, D3DVSDT_FLOAT2), 1.470 + D3DVSD_END() 1.471 + }; 1.472 + 1.473 + 1.474 + ID3DXBuffer *code, *errors; 1.475 + if(D3DXAssembleShaderFromFile(fname, 0, 0, &code, &errors) != D3D_OK) { 1.476 + return 0xffffffff; 1.477 + } 1.478 + 1.479 + dword vprog; 1.480 + if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, 0) != D3D_OK) { 1.481 + // could not create hardware vertex shader, try driver emulation... 1.482 + if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, D3DUSAGE_SOFTWAREPROCESSING) != D3D_OK) { 1.483 + throw EngineGeneralException("The system lacks required programmable vertex processing unit support"); 1.484 + } 1.485 + } 1.486 + 1.487 + return vprog; 1.488 +} 1.489 + 1.490 +void GraphicsContext::DestroyVertexProgram(dword vprog) { 1.491 + D3DDevice->DeleteVertexShader(vprog); 1.492 +} 1.493 + 1.494 +void GraphicsContext::SetVertexProgramConstant(dword creg, float val) { 1.495 + float block[4] = {val, 0.0f, 0.0f, 1.0f}; 1.496 + D3DDevice->SetVertexShaderConstant(creg, &block, 1); 1.497 +} 1.498 + 1.499 +void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector3 &val) { 1.500 + Vector4 vec(val); 1.501 + D3DDevice->SetVertexShaderConstant(creg, &vec, 1); 1.502 +} 1.503 + 1.504 +void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector4 &val) { 1.505 + D3DDevice->SetVertexShaderConstant(creg, &val, 1); 1.506 +} 1.507 + 1.508 +void GraphicsContext::SetVertexProgramConstant(dword creg, const Color &val) { 1.509 + D3DDevice->SetVertexShaderConstant(creg, &val, 1); 1.510 +} 1.511 + 1.512 +void GraphicsContext::SetVertexProgramConstant(dword creg, const Matrix4x4 &val) { 1.513 + D3DDevice->SetVertexShaderConstant(creg, &val, 4); 1.514 +} 1.515 + 1.516 +void GraphicsContext::SetVertexProgramConstant(dword creg, const void *data, dword size) { 1.517 + D3DDevice->SetVertexShaderConstant(creg, data, size); 1.518 +} 1.519 + 1.520 + 1.521 +// Lighting states 1.522 +void GraphicsContext::SetLighting(bool enable) { 1.523 + D3DDevice->SetRenderState(D3DRS_LIGHTING, enable); 1.524 +} 1.525 + 1.526 +void GraphicsContext::SetColorVertex(bool enable) { 1.527 + D3DDevice->SetRenderState(D3DRS_COLORVERTEX, enable); 1.528 +} 1.529 + 1.530 +void GraphicsContext::SetAmbientLight(Color AmbientColor) { 1.531 + D3DDevice->SetRenderState(D3DRS_AMBIENT, AmbientColor.GetPacked32()); 1.532 +} 1.533 + 1.534 +void GraphicsContext::SetShadingMode(ShadeMode mode) { 1.535 + D3DDevice->SetRenderState(D3DRS_SHADEMODE, mode); 1.536 +} 1.537 + 1.538 +void GraphicsContext::SetSpecular(bool enable) { 1.539 + D3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable); 1.540 +} 1.541 + 1.542 +// transformation states 1.543 +void GraphicsContext::SetWorldMatrix(const Matrix4x4 &WorldMat, unsigned int BlendIndex) { 1.544 + assert(BlendIndex < 256); 1.545 + this->WorldMat[BlendIndex] = WorldMat; 1.546 + if(!BillBoardingEnabled) { 1.547 + D3DDevice->SetTransform(D3DTS_WORLDMATRIX(BlendIndex), &WorldMat); 1.548 + } else { 1.549 + SetBillboarding(true); 1.550 + } 1.551 +} 1.552 + 1.553 +void GraphicsContext::SetViewMatrix(const Matrix4x4 &ViewMat) { 1.554 + this->ViewMat = ViewMat; 1.555 + if(!BillBoardingEnabled) { 1.556 + D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat); 1.557 + } else { 1.558 + SetBillboarding(true); 1.559 + } 1.560 +} 1.561 + 1.562 +void GraphicsContext::SetProjectionMatrix(const Matrix4x4 &ProjMat) { 1.563 + this->ProjMat = ProjMat; 1.564 + D3DDevice->SetTransform(D3DTS_PROJECTION, &ProjMat); 1.565 +} 1.566 + 1.567 +void GraphicsContext::SetTextureMatrix(const Matrix4x4 &TexMat, unsigned int TextureStage) { 1.568 + assert(TextureStage < 8); 1.569 + this->TexMat[TextureStage] = TexMat; 1.570 + D3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)((int)D3DTS_TEXTURE0 + TextureStage), &TexMat); 1.571 +} 1.572 + 1.573 +void GraphicsContext::SetViewport(unsigned int x, unsigned int y, unsigned int xsize, unsigned int ysize, float MinZ, float MaxZ) { 1.574 + D3DVIEWPORT8 viewport; 1.575 + viewport.X = x; 1.576 + viewport.Y = y; 1.577 + viewport.Width = xsize; 1.578 + viewport.Height = ysize; 1.579 + viewport.MinZ = MinZ; 1.580 + viewport.MaxZ = MaxZ; 1.581 + 1.582 + D3DDevice->SetViewport(&viewport); 1.583 +} 1.584 + 1.585 + 1.586 +const Matrix4x4 &GraphicsContext::GetWorldMatrix(unsigned int BlendIndex) { 1.587 + assert(BlendIndex < 256); 1.588 + return WorldMat[BlendIndex]; 1.589 +} 1.590 + 1.591 +const Matrix4x4 &GraphicsContext::GetViewMatrix() { 1.592 + return ViewMat; 1.593 +} 1.594 + 1.595 +const Matrix4x4 &GraphicsContext::GetProjectionMatrix() { 1.596 + return ProjMat; 1.597 +} 1.598 + 1.599 +const Matrix4x4 &GraphicsContext::GetTextureMatrix(unsigned int TextureStage) { 1.600 + assert(TextureStage < 8); 1.601 + return TexMat[TextureStage]; 1.602 +} 1.603 + 1.604 + 1.605 +// render target 1.606 +void GraphicsContext::ResetRenderTarget() { 1.607 + D3DDevice->SetRenderTarget(MainRenderTarget.ColorSurface, MainRenderTarget.DepthStencilSurface); 1.608 +} 1.609 + 1.610 +void GraphicsContext::SetRenderTarget(RenderTarget &rtarg) { 1.611 + D3DDevice->SetRenderTarget(rtarg.ColorSurface, rtarg.DepthStencilSurface); 1.612 +} 1.613 + 1.614 +void GraphicsContext::SetRenderTarget(Texture *rtarg, Texture *ztarg) { 1.615 + Surface *rendsurf, *zsurf = 0; 1.616 + rtarg->GetSurfaceLevel(0, &rendsurf); 1.617 + if(ztarg) ztarg->GetSurfaceLevel(0, &zsurf); 1.618 + 1.619 + D3DDevice->SetRenderTarget(rendsurf, zsurf); 1.620 +} 1.621 + 1.622 +void GraphicsContext::SetRenderTarget(Texture *rtarg, Surface *ztarg) { 1.623 + Surface *rendsurf; 1.624 + rtarg->GetSurfaceLevel(0, &rendsurf); 1.625 + 1.626 + D3DDevice->SetRenderTarget(rendsurf, ztarg); 1.627 +} 1.628 + 1.629 + 1.630 +//////////////////////////////////////////////////// 1.631 +//////////// Engine3D Member Functions ///////////// 1.632 +//////////////////////////////////////////////////// 1.633 + 1.634 +Engine3D::Engine3D() { 1.635 + 1.636 + if(!(d3d = Direct3DCreate8(D3D_SDK_VERSION))) { 1.637 + // actually this will never occur, if directx8 is not available in the system then 1.638 + // the OS loader will hit the problem first when it'll try to load d3d8.dll that is 1.639 + // linked through d3d8.lib, and complain for missing imports 1.640 + throw EngineInitException("DirectX 8.1 is required to run this program"); 1.641 + } 1.642 + 1.643 + RetrieveAdapterInfo(); 1.644 +} 1.645 + 1.646 +Engine3D::~Engine3D() { 1.647 + 1.648 + GraphicsContexts.erase(GraphicsContexts.begin(), GraphicsContexts.end()); 1.649 + 1.650 + if(d3d) { 1.651 + d3d->Release(); 1.652 + d3d = 0; 1.653 + } 1.654 +} 1.655 + 1.656 + 1.657 +//////////////////////////////////// 1.658 +// ----==( RetrieveAdapterInfo )==---- 1.659 +// (Private Member Function) 1.660 +// Gets the list of adapters on the system and additional 1.661 +// information for each adapter including its capabilities 1.662 +//////////////////////////////////// 1.663 +void Engine3D::RetrieveAdapterInfo() { 1.664 + 1.665 + // retrieve adapter list 1.666 + AdapterCount = d3d->GetAdapterCount(); 1.667 + adapters = new Adapter[AdapterCount]; 1.668 + 1.669 + for(unsigned int i=0; i<AdapterCount; i++) { 1.670 + 1.671 + // get adapter identifier and driver information 1.672 + D3DADAPTER_IDENTIFIER8 AdapterIdentifier; 1.673 + d3d->GetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &AdapterIdentifier); 1.674 + adapters[i].Description = new char[strlen(AdapterIdentifier.Description)+1]; 1.675 + strcpy(adapters[i].Description, AdapterIdentifier.Description); 1.676 + adapters[i].Driver = new char[strlen(AdapterIdentifier.Driver)+1]; 1.677 + strcpy(adapters[i].Driver, AdapterIdentifier.Driver); 1.678 + 1.679 + adapters[i].DeviceGUID = AdapterIdentifier.DeviceIdentifier; 1.680 + adapters[i].DeviceID = AdapterIdentifier.DeviceId; 1.681 + adapters[i].DriverVersion = AdapterIdentifier.DriverVersion.QuadPart; 1.682 + adapters[i].Revision = AdapterIdentifier.Revision; 1.683 + adapters[i].SubSysID = AdapterIdentifier.SubSysId; 1.684 + adapters[i].VentorID = AdapterIdentifier.VendorId; 1.685 + 1.686 + // get a list of display modes for this adapter 1.687 + LinkedList<DisplayMode> dmlist; 1.688 + adapters[i].ModeCount = d3d->GetAdapterModeCount(i); 1.689 + for(unsigned int j=0; j<adapters[i].ModeCount; j++) { 1.690 + D3DDISPLAYMODE d3dmode; 1.691 + DisplayMode mode; 1.692 + d3d->EnumAdapterModes(i, j, &d3dmode); 1.693 + mode.XRes = d3dmode.Width; 1.694 + mode.YRes = d3dmode.Height; 1.695 + mode.RefreshRate = d3dmode.RefreshRate; 1.696 + mode.ColorFormat = GetColorDepthFromPixelFormat(d3dmode.Format); 1.697 + 1.698 + // check if this mode is supported from the HAL device 1.699 + D3DFORMAT dispfmt = GetPixelFormatFromColorDepth(mode.ColorFormat, true); 1.700 + if(d3d->CheckDeviceType(i, D3DDEVTYPE_HAL, dispfmt, d3dmode.Format, false) == D3D_OK) { 1.701 + dmlist.PushBack(mode); 1.702 + } 1.703 + } 1.704 + adapters[i].ModeCount = dmlist.Size(); // count of the modes that are supported through HW 1.705 + adapters[i].Modes = new DisplayMode[adapters[i].ModeCount]; 1.706 + ListNode<DisplayMode> *iter = dmlist.Begin(); 1.707 + int j = 0; 1.708 + while(iter) { 1.709 + adapters[i].Modes[j++] = iter->data; 1.710 + iter = iter->next; 1.711 + } 1.712 + 1.713 + // get the device capabilities 1.714 + d3d->GetDeviceCaps(i, D3DDEVTYPE_HAL, &adapters[i].Capabilities); 1.715 + int vsver_major = D3DSHADER_VERSION_MAJOR(adapters[i].Capabilities.VertexShaderVersion); 1.716 + int vsver_minor = D3DSHADER_VERSION_MINOR(adapters[i].Capabilities.VertexShaderVersion); 1.717 + } 1.718 +} 1.719 + 1.720 +//////////////////////////////////// 1.721 +// ----==( CreateModesList )==---- 1.722 +// (Private Member Function) 1.723 +// Creates a linked list of the available modes 1.724 +// of a single adapter for further processing 1.725 +//////////////////////////////////// 1.726 +LinkedList<DisplayMode> *Engine3D::CreateModesList(unsigned int AdapterID) const { 1.727 + 1.728 + if(AdapterID >= AdapterCount) return 0; 1.729 + 1.730 + LinkedList<DisplayMode> *newlist = new LinkedList<DisplayMode>; 1.731 + for(unsigned int i=0; i<adapters[AdapterID].ModeCount; i++) { 1.732 + newlist->PushBack(adapters[AdapterID].Modes[i]); 1.733 + } 1.734 + return newlist; 1.735 +} 1.736 + 1.737 +//////////////////////////////////// 1.738 +// ----==( NarrowModesList )==---- 1.739 +// (Private Member Function) 1.740 +// Narrows down the list of available modes 1.741 +// to those that have the requested item 1.742 +//////////////////////////////////// 1.743 +void Engine3D::NarrowModesList(LinkedList<DisplayMode> *list, DisplayModeItem item, long value, long value2) const { 1.744 + 1.745 + ListNode<DisplayMode> *iter = list->Begin(); 1.746 + while(iter) { 1.747 + switch(item) { 1.748 + case ModeItemSize: 1.749 + if(iter->data.XRes != value || iter->data.YRes != value2) { 1.750 + iter = list->Erase(iter); 1.751 + } else { 1.752 + if(iter) iter = iter->next; 1.753 + } 1.754 + break; 1.755 + 1.756 + case ModeItemBpp: 1.757 + if(iter->data.ColorFormat.bpp != value) { 1.758 + iter = list->Erase(iter); 1.759 + } else { 1.760 + if(iter) iter = iter->next; 1.761 + } 1.762 + break; 1.763 + 1.764 + case ModeItemAlpha: 1.765 + if(!iter->data.ColorFormat.alpha && value) { 1.766 + iter = list->Erase(iter); 1.767 + } else { 1.768 + if(iter) iter = iter->next; 1.769 + } 1.770 + break; 1.771 + 1.772 + case ModeItemRefresh: 1.773 + if(iter->data.RefreshRate != value) { 1.774 + iter = list->Erase(iter); 1.775 + } else { 1.776 + if(iter) iter = iter->next; 1.777 + } 1.778 + break; 1.779 + 1.780 + default: break; 1.781 + } 1.782 + } 1.783 +} 1.784 + 1.785 +/////////////////////////////////// 1.786 +// ----==( ChooseBestMode )==---- 1.787 +// (Private Member Function) 1.788 +// given a (ideally) narrowed down modes list 1.789 +// choose the best possible among them 1.790 +/////////////////////////////////// 1.791 +DisplayMode Engine3D::ChooseBestMode(LinkedList<DisplayMode> *modes) const { 1.792 + 1.793 + DisplayMode dmode; 1.794 + memset(&dmode, 0, sizeof(DisplayMode)); 1.795 + 1.796 + if(!modes || !modes->Size()) return dmode; 1.797 + 1.798 + // find the highest resolution and get only the modes with that resolution 1.799 + ListNode<DisplayMode> *iter = modes->Begin(); 1.800 + unsigned int maxx = 0, maxy = 0; 1.801 + while(iter) { 1.802 + if(iter->data.XRes > maxx) maxx = iter->data.XRes; 1.803 + if(iter->data.YRes > maxy) maxy = iter->data.YRes; 1.804 + iter = iter->next; 1.805 + } 1.806 + NarrowModesList(modes, ModeItemSize, maxx, maxy); 1.807 + 1.808 + // find the modes with alpha if any 1.809 + iter = modes->Begin(); 1.810 + bool AnyWithAlpha = false; 1.811 + while(iter) { 1.812 + if(iter->data.ColorFormat.alpha) { 1.813 + AnyWithAlpha = true; 1.814 + break; 1.815 + } 1.816 + iter = iter->next; 1.817 + } 1.818 + if(AnyWithAlpha) NarrowModesList(modes, ModeItemAlpha, 1); 1.819 + 1.820 + // find the modes with the highest bpp 1.821 + iter = modes->Begin(); 1.822 + int maxbpp = 0; 1.823 + while(iter) { 1.824 + if(iter->data.ColorFormat.bpp > maxbpp) maxbpp = iter->data.ColorFormat.bpp; 1.825 + iter = iter->next; 1.826 + } 1.827 + NarrowModesList(modes, ModeItemBpp, maxbpp); 1.828 + 1.829 + // find the modes with the highest refresh rate 1.830 + iter = modes->Begin(); 1.831 + unsigned int maxrefresh = 0; 1.832 + while(iter) { 1.833 + if(iter->data.RefreshRate > maxrefresh) maxrefresh = iter->data.RefreshRate; 1.834 + iter = iter->next; 1.835 + } 1.836 + NarrowModesList(modes, ModeItemRefresh, maxrefresh); 1.837 + 1.838 + // if there is more than one mode left, then there is a problem :) 1.839 + assert(modes->Size() == 1); 1.840 + 1.841 + dmode = modes->Begin()->data; 1.842 + return dmode; 1.843 +} 1.844 + 1.845 +////////////////////////////////////////// 1.846 +// ----==( CreateGraphicsContext )==---- 1.847 +// (Public Member Function) 1.848 +// Creates a graphics context with the specified parameters 1.849 +////////////////////////////////////////// 1.850 +GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, unsigned int AdapterID, ContextInitParameters *GCParams) { 1.851 + 1.852 + if(AdapterID >= AdapterCount) return 0; 1.853 + 1.854 + // check adapter's Transformation & Lighting capability 1.855 + bool hwtnl = (bool)(adapters[AdapterID].Capabilities.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT); 1.856 + if(!(GCParams->DontCareFlags & GCPDONTCARE_TNL)) { // bit not set, we want specific TnL mode 1.857 + if(hwtnl != GCParams->HardwareTnL && !hwtnl) return 0; // we asked for hw tnl and is not available 1.858 + // else either we asked for sw and found hw so we continue with our initial sw setting 1.859 + // or we found exactly what we asked, so we still continue with our choice 1.860 + } else { 1.861 + GCParams->HardwareTnL = hwtnl; // if we don't care use what we have available 1.862 + } 1.863 + 1.864 + // decide which mode to use 1.865 + LinkedList<DisplayMode> *modes = CreateModesList(AdapterID); 1.866 + NarrowModesList(modes, ModeItemSize, GCParams->x, GCParams->y); 1.867 + 1.868 + if(!(GCParams->DontCareFlags & GCPDONTCARE_BPP)) { // we want specific bpp 1.869 + NarrowModesList(modes, ModeItemBpp, GCParams->bpp); 1.870 + } 1.871 + 1.872 + if(!(GCParams->DontCareFlags & GCPDONTCARE_ALPHA)) { // alpha setting exactly as asked 1.873 + NarrowModesList(modes, ModeItemAlpha, (long)GCParams->AlphaChannel); 1.874 + } 1.875 + 1.876 + if(!(GCParams->DontCareFlags & GCPDONTCARE_REFRESH)) { // specific refresh rate 1.877 + NarrowModesList(modes, ModeItemRefresh, GCParams->RefreshRate); 1.878 + } 1.879 + 1.880 + if(!modes->Size()) { // didn't find any mode with the properties that we asked 1.881 + throw EngineInitException("Requested video mode parameters not available"); 1.882 + } 1.883 + 1.884 + DisplayMode mode = ChooseBestMode(modes); 1.885 + delete modes; // delete the list of modes 1.886 + 1.887 + D3DFORMAT PixelFormat = GetPixelFormatFromColorDepth(mode.ColorFormat); 1.888 + 1.889 + // find out if we have the requested zbuffer format avaialble 1.890 + if(!GCParams->DepthBits) GCParams->DepthBits = 32; // not specified, trying highest possible first 1.891 + D3DFORMAT zfmt = GetDepthStencilFormat(GCParams->DepthBits, true); 1.892 + 1.893 + bool res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); 1.894 + if(!res) { // try a format without stencil 1.895 + zfmt = GetDepthStencilFormat(GCParams->DepthBits, false); 1.896 + res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); 1.897 + } 1.898 + 1.899 + if(!res) { // didn't find requested zbuffer even with no stencil 1.900 + // if we asked for specific zformat and didn't find it or if the zbuffer that 1.901 + // we failed to set was 16bits and can't go less, bail out 1.902 + if(!(GCParams->DontCareFlags & GCPDONTCARE_DEPTH) || GCParams->DepthBits == 16) return 0; 1.903 + 1.904 + // try to set a smaller zbuffer with stencil 1.905 + GCParams->DepthBits = 16; 1.906 + zfmt = GetDepthStencilFormat(GCParams->DepthBits, true); 1.907 + res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); 1.908 + if(!res) { // try a format without stencil 1.909 + zfmt = GetDepthStencilFormat(GCParams->DepthBits, false); 1.910 + res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); 1.911 + } 1.912 + 1.913 + if(!res) throw EngineInitException("Requested ZBuffer depth not available"); 1.914 + } 1.915 + 1.916 + int AASamples = 0; 1.917 + if(GCParams->Antialiasing) { 1.918 + if(GCParams->BestAA) { 1.919 + // find the best supported AA mode 1.920 + for(AASamples=16; AASamples > 0; AASamples--) { 1.921 + long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples); 1.922 + if(result == D3D_OK) break; 1.923 + } 1.924 + } else { 1.925 + // check for cheap AA 1.926 + AASamples = 2; 1.927 + long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples); 1.928 + if(result != D3D_OK) AASamples = 0; 1.929 + } 1.930 + 1.931 + if(!AASamples && !(GCParams->DontCareFlags & GCPDONTCARE_AA)) { 1.932 + throw EngineInitException("Requested Antialiasing mode not available"); 1.933 + } 1.934 + } 1.935 + 1.936 + D3DFORMAT FinalColorFormat; 1.937 + if(GCParams->FullScreen) { 1.938 + FinalColorFormat = GetPixelFormatFromColorDepth(mode.ColorFormat); 1.939 + } else { 1.940 + D3DDISPLAYMODE CurrentMode; 1.941 + d3d->GetAdapterDisplayMode(AdapterID, &CurrentMode); 1.942 + FinalColorFormat = CurrentMode.Format; 1.943 + } 1.944 + 1.945 + // if everything went well, now we can set that mode 1.946 + D3DPRESENT_PARAMETERS d3dppar; 1.947 + d3dppar.BackBufferWidth = GCParams->x; 1.948 + d3dppar.BackBufferHeight = GCParams->y; 1.949 + d3dppar.BackBufferFormat = FinalColorFormat; 1.950 + d3dppar.BackBufferCount = (unsigned int)GCParams->Buffers; 1.951 + d3dppar.MultiSampleType = (D3DMULTISAMPLE_TYPE)AASamples; 1.952 + d3dppar.SwapEffect = D3DSWAPEFFECT_DISCARD; 1.953 + d3dppar.hDeviceWindow = WindowHandle; 1.954 + d3dppar.Windowed = !GCParams->FullScreen; 1.955 + d3dppar.EnableAutoDepthStencil = true; 1.956 + d3dppar.AutoDepthStencilFormat = zfmt; 1.957 + d3dppar.Flags = 0; 1.958 + d3dppar.FullScreen_RefreshRateInHz = (GCParams->FullScreen) ? mode.RefreshRate : 0; 1.959 + if(GCParams->FullScreen) { 1.960 + d3dppar.FullScreen_PresentationInterval = (GCParams->VSync) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; 1.961 + } else { 1.962 + d3dppar.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; 1.963 + } 1.964 + 1.965 + // create the rendering context 1.966 + GraphicsContext *gc = new GraphicsContext; 1.967 + 1.968 + TnLMode tnlmode = (GCParams->HardwareTnL) ? HardwareTnL : SoftwareTnL; 1.969 + 1.970 + long result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice); 1.971 + if(result != D3D_OK) { 1.972 + if(d3dppar.BackBufferCount != GCParams->Buffers) { 1.973 + if((GCParams->DontCareFlags & GCPDONTCARE_BUFFERS)) { 1.974 + result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice); 1.975 + } else { 1.976 + throw EngineInitException("Could not create Direct3D device"); 1.977 + } 1.978 + } 1.979 + } 1.980 + 1.981 + if(result != D3D_OK) { 1.982 + throw EngineInitException("Could not create Direct3D device"); 1.983 + } 1.984 + 1.985 + gc->WindowHandle = WindowHandle; 1.986 + gc->D3DDevice->GetRenderTarget(&gc->MainRenderTarget.ColorSurface); 1.987 + gc->D3DDevice->GetDepthStencilSurface(&gc->MainRenderTarget.DepthStencilSurface); 1.988 + gc->ContextParams = *GCParams; 1.989 + gc->ZFormat = zfmt; 1.990 + gc->AASamples = AASamples; 1.991 + gc->ColorFormat = FinalColorFormat; 1.992 + gc->MaxTextureStages = adapters[AdapterID].Capabilities.MaxSimultaneousTextures; 1.993 + gc->texman = new TextureManager(gc); 1.994 + 1.995 + gc->SetDefaultStates(); 1.996 + 1.997 + GraphicsContexts.push_back(gc); 1.998 + 1.999 + return gc; 1.1000 +} 1.1001 + 1.1002 +////////////////////////////////////////// 1.1003 +// ----==( CreateGraphicsContext )==---- 1.1004 +// (Public Member Function) 1.1005 +// Creates a graphics context with the specified parameters 1.1006 +// Light version, basic info passed, fills in the rest 1.1007 +////////////////////////////////////////// 1.1008 +GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, int x, int y, int bpp, word flags) { 1.1009 + 1.1010 + ContextInitParameters gcp; 1.1011 + gcp.x = x; 1.1012 + gcp.y = y; 1.1013 + gcp.bpp = bpp; 1.1014 + gcp.DepthBits = 24; 1.1015 + gcp.DevType = DeviceHardware; 1.1016 + gcp.FullScreen = (flags & GCCREATE_FULLSCREEN) ? true : false; 1.1017 + gcp.HardwareTnL = true; 1.1018 + gcp.RefreshRate = 75; 1.1019 + gcp.Antialiasing = false; 1.1020 + gcp.Buffers = DoubleBuffering; 1.1021 + gcp.VSync = false; 1.1022 + gcp.DontCareFlags = GCPDONTCARE_DEPTH | GCPDONTCARE_REFRESH | GCPDONTCARE_ALPHA | GCPDONTCARE_VSYNC; 1.1023 + 1.1024 + return CreateGraphicsContext(WindowHandle, D3DADAPTER_DEFAULT, &gcp); 1.1025 +} 1.1026 + 1.1027 +using std::string; 1.1028 +using std::getline; 1.1029 + 1.1030 +string GetValue(string line) { 1.1031 + int nexttoken = (int)line.find("=") + 1; 1.1032 + while(line[++nexttoken] == ' '); 1.1033 + int tokenend = (int)line.find_first_of(" \n\r\t"); 1.1034 + return line.substr(nexttoken, tokenend - nexttoken); 1.1035 +} 1.1036 + 1.1037 +ContextInitParameters Engine3D::LoadContextParamsConfigFile(const char *cfgfilename) { 1.1038 + ContextInitParameters cip; 1.1039 + memset(&cip, 0, sizeof(ContextInitParameters)); 1.1040 + 1.1041 + std::ifstream file(cfgfilename); 1.1042 + if(!file.is_open()) throw EngineInitException("Could not open configuration file"); 1.1043 + 1.1044 + string line; 1.1045 + getline(file, line); 1.1046 + while(!file.eof()) { 1.1047 + if(line[0] != ';' && line[0] != '\n' && line[0] != '\r' && line[0] != ' ') { 1.1048 + int tokenend = (int)line.find(" "); 1.1049 + string token = line.substr(0, tokenend); 1.1050 + 1.1051 + if(token == "fullscreen") { 1.1052 + string value = GetValue(line); 1.1053 + cip.FullScreen = (value == "true") ? true : false; 1.1054 + } else if(token == "resolution") { 1.1055 + string value = GetValue(line); 1.1056 + int x = (int)value.find("x"); 1.1057 + cip.x = atoi(value.substr(0, x).c_str()); 1.1058 + cip.y = atoi(value.substr(x+1, value.size()).c_str()); 1.1059 + } else if(token == "bpp") { 1.1060 + cip.bpp = atoi(GetValue(line).c_str()); 1.1061 + } else if(token == "zbufferdepth") { 1.1062 + cip.DepthBits = atoi(GetValue(line).c_str()); 1.1063 + } else if(token == "device") { 1.1064 + cip.DevType = (GetValue(line) == "ref") ? DeviceReference : DeviceHardware; 1.1065 + } else if(token == "tnl") { 1.1066 + cip.HardwareTnL = (GetValue(line) == "false") ? false : true; 1.1067 + } else if(token == "refresh") { 1.1068 + cip.RefreshRate = atoi(GetValue(line).c_str()); 1.1069 + } else if(token == "antialiasing") { 1.1070 + string value = GetValue(line); 1.1071 + cip.Antialiasing = (value == "none") ? false : true; 1.1072 + if(cip.Antialiasing) { 1.1073 + cip.BestAA = (value == "speed" || value == "low") ? false : true; 1.1074 + } 1.1075 + } else if(token == "flipchain") { 1.1076 + cip.Buffers = (GetValue(line) == "triplebuffering") ? TripleBuffering : DoubleBuffering; 1.1077 + } else if(token == "vsync") { 1.1078 + cip.VSync = (GetValue(line) == "true") ? true : false; 1.1079 + } else if(token == "dontcareabout") { 1.1080 + cip.DontCareFlags = 0; 1.1081 + string flags = GetValue(line); 1.1082 + string part; 1.1083 + while(1) { 1.1084 + int begin = (int)flags.find_first_not_of(", "); 1.1085 + int end = (int)flags.find(",", begin) - begin; 1.1086 + part = flags.substr(begin, end); 1.1087 + //part = flags.substr(0, flags.find(","));// \n\r\t")); 1.1088 + if(part.empty()) break; 1.1089 + if(part == "bpp") cip.DontCareFlags |= GCPDONTCARE_BPP; 1.1090 + if(part == "refresh") cip.DontCareFlags |= GCPDONTCARE_REFRESH; 1.1091 + if(part == "alpha") cip.DontCareFlags |= GCPDONTCARE_ALPHA; 1.1092 + if(part == "zbufferdepth") cip.DontCareFlags |= GCPDONTCARE_DEPTH; 1.1093 + if(part == "tnl") cip.DontCareFlags |= GCPDONTCARE_TNL; 1.1094 + if(part == "flipchain") cip.DontCareFlags |= GCPDONTCARE_BUFFERS; 1.1095 + if(part == "aamode") cip.DontCareFlags |= GCPDONTCARE_AA; 1.1096 + if(part == "vsync") cip.DontCareFlags |= GCPDONTCARE_VSYNC; 1.1097 + int temp = (int)flags.find_first_of(",\n\r"); 1.1098 + if(temp == string::npos) break; 1.1099 + flags.erase(0, temp+1); 1.1100 + } 1.1101 + } 1.1102 + 1.1103 + } 1.1104 + 1.1105 + getline(file, line); 1.1106 + } 1.1107 + 1.1108 + return cip; 1.1109 +} 1.1110 + 1.1111 +void Engine3D::DestroyGraphicsContext(GraphicsContext *gc) { 1.1112 + gc->D3DDevice->Release(); 1.1113 +} 1.1114 + 1.1115 +int Engine3D::GetAdapterCount() const { 1.1116 + return AdapterCount; 1.1117 +} 1.1118 + 1.1119 +const Adapter *Engine3D::GetAdapterInfo(int adapter) const { 1.1120 + return &adapters[adapter]; 1.1121 +} 1.1122 + 1.1123 + 1.1124 +////////////////////////////////////////////////////////////////////////////// 1.1125 +// helper functions 1.1126 + 1.1127 +bool Lock(VertexBuffer *vb, Vertex **data) { 1.1128 + D3DVERTEXBUFFER_DESC desc; 1.1129 + vb->GetDesc(&desc); 1.1130 + dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0; 1.1131 + 1.1132 + return (vb->Lock(0, 0, (byte**)data, flags) == D3D_OK); 1.1133 +} 1.1134 + 1.1135 +bool Lock(IndexBuffer *ib, Index **data) { 1.1136 + D3DINDEXBUFFER_DESC desc; 1.1137 + ib->GetDesc(&desc); 1.1138 + dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0; 1.1139 + 1.1140 + return (ib->Lock(0, 0, (byte**)data, flags) == D3D_OK); 1.1141 +} 1.1142 + 1.1143 +void Unlock(VertexBuffer *vb) { 1.1144 + vb->Unlock(); 1.1145 +} 1.1146 + 1.1147 +void Unlock(IndexBuffer *ib) { 1.1148 + ib->Unlock(); 1.1149 +} 1.1150 + 1.1151 + 1.1152 +void CreateProjectionMatrix(Matrix4x4 *mat, float yFOV, float Aspect, float NearClip, float FarClip) { 1.1153 + 1.1154 + float h, w, Q; 1.1155 + float xFOV = yFOV * Aspect; 1.1156 + 1.1157 + w = (float)(1.0f/tan(xFOV*0.5f)); // 1/tan(x) == cot(x) 1.1158 + h = (float)(1.0f/tan(yFOV*0.5f)); // 1/tan(x) == cot(x) 1.1159 + Q = FarClip / (FarClip - NearClip); 1.1160 + 1.1161 + /* Projection Matrix 1.1162 + [ w 0.0f 0.0f 0.0f] 1.1163 + |0.0f h 0.0f 0.0f| 1.1164 + |0.0f 0.0f Q 1.0f| 1.1165 + [0.0f 0.0f -Q*NearClip 0.0f] 1.1166 + */ 1.1167 + 1.1168 + mat->ResetIdentity(); 1.1169 + mat->m[0][0] = w; 1.1170 + mat->m[1][1] = h; 1.1171 + mat->m[2][2] = Q; 1.1172 + mat->m[3][2] = -Q*NearClip; 1.1173 + mat->m[2][3] = 1.0f; 1.1174 +} 1.1175 + 1.1176 +dword PackVector(const Vector3 &vec, float Height) { 1.1177 + dword r = (dword)(127.0f * vec.x + 128.0f); 1.1178 + dword g = (dword)(127.0f * vec.y + 128.0f); 1.1179 + dword b = (dword)(127.0f * vec.z + 128.0f); 1.1180 + dword a = (dword)(255.0f * Height); 1.1181 + 1.1182 + return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) ); 1.1183 +} 1.1184 + 1.1185 +void NormalMapFromHeightField(Texture *tex) { 1.1186 + 1.1187 + // Lock the texture 1.1188 + D3DLOCKED_RECT d3dlr; 1.1189 + D3DSURFACE_DESC d3dsd; 1.1190 + 1.1191 + int LevelCount = tex->GetLevelCount(); 1.1192 + for(int i=0; i<LevelCount; i++) { 1.1193 + 1.1194 + tex->GetLevelDesc(i, &d3dsd); 1.1195 + tex->LockRect(i, &d3dlr, 0, 0); 1.1196 + DWORD* pPixel = (DWORD*)d3dlr.pBits; 1.1197 + 1.1198 + // For each pixel, generate a vector normal that represents the change 1.1199 + // in thea height field at that pixel 1.1200 + for( DWORD j=0; j<d3dsd.Height; j++ ) { 1.1201 + for( DWORD i=0; i<d3dsd.Width; i++ ) { 1.1202 + DWORD color00 = pPixel[0]; 1.1203 + DWORD color10 = pPixel[1]; 1.1204 + DWORD color01 = pPixel[d3dlr.Pitch/sizeof(DWORD)]; 1.1205 + 1.1206 + float fHeight00 = (float)((color00 & 0x00ff0000) >> 16) / 255.0f; 1.1207 + float fHeight10 = (float)((color10 & 0x00ff0000) >> 16) / 255.0f; 1.1208 + float fHeight01 = (float)((color01 & 0x00ff0000) >> 16) / 255.0f; 1.1209 + 1.1210 + Vector3 vPoint00(i+0.0f, j+0.0f, fHeight00); 1.1211 + Vector3 vPoint10(i+1.0f, j+0.0f, fHeight10); 1.1212 + Vector3 vPoint01(i+0.0f, j+1.0f, fHeight01); 1.1213 + Vector3 v10 = vPoint10 - vPoint00; 1.1214 + Vector3 v01 = vPoint01 - vPoint00; 1.1215 + 1.1216 + Vector3 Normal = v10.CrossProduct(v01); 1.1217 + Normal.Normalize(); 1.1218 + 1.1219 + // Store the normal as an RGBA value in the normal map 1.1220 + *pPixel++ = PackVector(Normal, fHeight00); 1.1221 + } 1.1222 + } 1.1223 + tex->UnlockRect(i); 1.1224 + } 1.1225 +} 1.1226 + 1.1227 +void UpdateMipmapChain(Texture *tex) { 1.1228 + D3DXFilterTexture(tex, 0, 0, D3DX_FILTER_BOX); 1.1229 +} 1.1230 + 1.1231 +dword AddEdge(Edge *edges, dword EdgeCount, const Edge &newedge) { 1.1232 + // remove internal edges 1.1233 + for(dword i=0; i<EdgeCount; i++) { 1.1234 + if((edges[i].vertices[0] == newedge.vertices[0] && edges[i].vertices[1] == newedge.vertices[1]) || (edges[i].vertices[0] == newedge.vertices[1] && edges[i].vertices[1] == newedge.vertices[0])) { 1.1235 + edges[i] = edges[--EdgeCount]; 1.1236 + return EdgeCount; 1.1237 + } 1.1238 + } 1.1239 + 1.1240 + edges[EdgeCount++] = newedge; 1.1241 + return EdgeCount; 1.1242 +} 1.1243 + 1.1244 +//#define LIGHTDIR(l, p) (l->GetType() == LTDir ? l->GetDirection() : p - l->GetPosition()) 1.1245 +inline Vector3 GetLightDir(const Light *light, const Vector3 &pos, const Matrix4x4 &mat) { 1.1246 + if(light->GetType() == LTDir) { 1.1247 + return light->GetDirection(); 1.1248 + } else { 1.1249 + Vector3 lpos = light->GetPosition(); 1.1250 + lpos.Transform(mat); 1.1251 + return pos - lpos; 1.1252 + } 1.1253 + return Vector3(); 1.1254 +} 1.1255 + 1.1256 + 1.1257 +////////////////////////////////////////// 1.1258 +// ----==( CreateShadowVolume )==---- 1.1259 +// (Helper Function) 1.1260 +// Creates a graphics context with the specified parameters 1.1261 +// Light version, basic info passed, fills in the rest 1.1262 +////////////////////////////////////////// 1.1263 + 1.1264 +TriMesh *CreateShadowVolume(const TriMesh &mesh, const Light *light, const Matrix4x4 &MeshXForm, bool WorldCoords) { 1.1265 + 1.1266 + // transform light into object's local coordinate system 1.1267 + //const_cast<Light*>(light)->Transform(MeshXForm.Inverse()); 1.1268 + Matrix4x4 InvXForm = MeshXForm.Inverse(); 1.1269 + 1.1270 + const Vertex *varray = mesh.GetVertexArray(); 1.1271 + const Triangle *triarray = mesh.GetTriangleArray(); 1.1272 + 1.1273 + dword VertexCount = mesh.GetVertexCount(); 1.1274 + dword TriangleCount = mesh.GetTriangleCount(); 1.1275 + 1.1276 + Edge *edges = new Edge[TriangleCount]; 1.1277 + dword EdgeCount = 0; 1.1278 + 1.1279 + // first find the contour edges 1.1280 + 1.1281 + for(dword i=0; i<TriangleCount; i++) { 1.1282 + 1.1283 + // find the light vector incident at this triangle 1.1284 + Vertex TriVerts[3]; 1.1285 + TriVerts[0] = varray[triarray[i].vertices[0]]; 1.1286 + TriVerts[1] = varray[triarray[i].vertices[1]]; 1.1287 + TriVerts[2] = varray[triarray[i].vertices[2]]; 1.1288 + 1.1289 + Vector3 pos = (TriVerts[0].pos + TriVerts[1].pos + TriVerts[2].pos) / 3.0f; 1.1290 + //Vector3 LightDir = LIGHTDIR(light, pos); 1.1291 + Vector3 LightDir = GetLightDir(light, pos, InvXForm); 1.1292 + 1.1293 + // if it looks away from the light... 1.1294 + if(DotProduct(triarray[i].normal, LightDir) >= 0.0f) { 1.1295 + EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[0], triarray[i].vertices[1])); 1.1296 + EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[1], triarray[i].vertices[2])); 1.1297 + EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[2], triarray[i].vertices[0])); 1.1298 + } 1.1299 + } 1.1300 + 1.1301 + // now extract the contour edges to build the shadow volume boundrary 1.1302 + const float ExtrudeMagnitude = 100000.0f; 1.1303 + Vertex *ShadowVertices = new Vertex[EdgeCount * 6]; 1.1304 + 1.1305 + for(dword i=0; i<EdgeCount; i++) { 1.1306 + Vertex QuadVert[4]; 1.1307 + QuadVert[0] = varray[edges[i].vertices[0]]; 1.1308 + QuadVert[1] = varray[edges[i].vertices[1]]; 1.1309 + //QuadVert[2] = QuadVert[1].pos + (Vector3)LIGHTDIR(light, QuadVert[1].pos) * ExtrudeMagnitude; 1.1310 + //QuadVert[3] = QuadVert[0].pos + (Vector3)LIGHTDIR(light, QuadVert[0].pos) * ExtrudeMagnitude; 1.1311 + QuadVert[2] = QuadVert[1].pos + GetLightDir(light, QuadVert[1].pos, InvXForm) * ExtrudeMagnitude; 1.1312 + QuadVert[3] = QuadVert[0].pos + GetLightDir(light, QuadVert[0].pos, InvXForm) * ExtrudeMagnitude; 1.1313 + 1.1314 + ShadowVertices[i*6] = QuadVert[0]; 1.1315 + ShadowVertices[i*6+1] = QuadVert[1]; 1.1316 + ShadowVertices[i*6+2] = QuadVert[2]; 1.1317 + 1.1318 + ShadowVertices[i*6+3] = QuadVert[0]; 1.1319 + ShadowVertices[i*6+4] = QuadVert[2]; 1.1320 + ShadowVertices[i*6+5] = QuadVert[3]; 1.1321 + 1.1322 + if(WorldCoords) { 1.1323 + for(int j=0; j<6; j++) { 1.1324 + ShadowVertices[i*6+j].pos.Transform(MeshXForm); 1.1325 + } 1.1326 + } 1.1327 + } 1.1328 + 1.1329 + TriMesh *ShadowMesh = new TriMesh(1); 1.1330 + ShadowMesh->SetData(ShadowVertices, 0, EdgeCount * 6, 0); 1.1331 + 1.1332 + delete [] ShadowVertices; 1.1333 + delete [] edges; 1.1334 + 1.1335 + //const_cast<Light*>(light)->Transform(MeshXForm); // return light to world coordinate system 1.1336 + 1.1337 + return ShadowMesh; 1.1338 +} 1.1339 + 1.1340 + 1.1341 +///////////// local ////////////// 1.1342 + 1.1343 +ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt) { 1.1344 + switch(fmt) { 1.1345 + case D3DFMT_R8G8B8: return ColorDepth(24, 24, 0); 1.1346 + case D3DFMT_A8R8G8B8: return ColorDepth(32, 24, 8); 1.1347 + case D3DFMT_X8R8G8B8: return ColorDepth(32, 24, 0); 1.1348 + case D3DFMT_R5G6B5: return ColorDepth(16, 16, 0); 1.1349 + case D3DFMT_X1R5G5B5: return ColorDepth(16, 15, 0); 1.1350 + case D3DFMT_A1R5G5B5: return ColorDepth(16, 15, 1); 1.1351 + case D3DFMT_P8: return ColorDepth(8, 8, 0); 1.1352 + default: return ColorDepth(0, 0, 0); 1.1353 + } 1.1354 +} 1.1355 + 1.1356 +bool operator ==(const ColorDepth &lhs, const ColorDepth &rhs) { 1.1357 + return (lhs.bpp == rhs.bpp && lhs.colorbits == rhs.colorbits && lhs.alpha == rhs.alpha); 1.1358 +} 1.1359 + 1.1360 +D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha) { 1.1361 + if(cd == ColorDepth(24, 24, 0)) return D3DFMT_R8G8B8; 1.1362 + if(cd == ColorDepth(32, 24, 8)) return noalpha ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8; 1.1363 + if(cd == ColorDepth(32, 24, 0)) return D3DFMT_X8R8G8B8; 1.1364 + if(cd == ColorDepth(16, 16, 0)) return D3DFMT_R5G6B5; 1.1365 + if(cd == ColorDepth(16, 15, 0)) return D3DFMT_X1R5G5B5; 1.1366 + if(cd == ColorDepth(16, 15, 1)) return noalpha ? D3DFMT_X1R5G5B5 : D3DFMT_A1R5G5B5; 1.1367 + if(cd == ColorDepth(8, 8, 0)) return D3DFMT_P8; 1.1368 + return (D3DFORMAT)0; 1.1369 +} 1.1370 + 1.1371 + 1.1372 +D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil) { 1.1373 + switch(depthbits) { 1.1374 + case 32: 1.1375 + return (stencil) ? D3DFMT_D24S8 : D3DFMT_D32; 1.1376 + break; 1.1377 + 1.1378 + case 24: 1.1379 + return (stencil) ? D3DFMT_D24S8 : D3DFMT_D24X8; 1.1380 + break; 1.1381 + 1.1382 + case 16: 1.1383 + return (stencil) ? D3DFMT_D15S1 : D3DFMT_D16; 1.1384 + break; 1.1385 + 1.1386 + default: 1.1387 + break; 1.1388 + } 1.1389 + 1.1390 + return (D3DFORMAT)0; 1.1391 +} 1.1392 \ No newline at end of file