nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "d3dx8.h" nuclear@0: #include "3dengine.h" nuclear@0: #include "exceptions.h" nuclear@0: #include "3dgeom.h" nuclear@0: #include "lights.h" nuclear@0: nuclear@0: // local helper functions nuclear@0: ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt); nuclear@0: D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha=false); nuclear@0: D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil); nuclear@0: nuclear@0: ///////////// Graphics Context Member Functions ///////////////// nuclear@0: nuclear@0: GraphicsContext::GraphicsContext() { nuclear@0: D3DDevice = 0; nuclear@0: BackfaceCulling = true; nuclear@0: } nuclear@0: nuclear@0: /////////////////////////////////// nuclear@0: // ----==( SetDefaultStates )==---- nuclear@0: // (Public Member Function) nuclear@0: // Sets the default render states nuclear@0: /////////////////////////////////// nuclear@0: void GraphicsContext::SetDefaultStates() { nuclear@0: D3DDevice->SetRenderState(D3DRS_LOCALVIEWER, true); nuclear@0: SetPrimitiveType(TriangleList); nuclear@0: SetBackfaceCulling(true); nuclear@0: SetFrontFace(Clockwise); nuclear@0: SetLighting(true); nuclear@0: SetColorVertex(false); nuclear@0: SetAmbientLight(0.0f); nuclear@0: SetMipMapping(true); nuclear@0: SetTextureFiltering(BilinearFiltering); nuclear@0: SetBillboarding(false); nuclear@0: SetSpecular(true); nuclear@0: nuclear@0: Matrix4x4 ProjMat; nuclear@0: CreateProjectionMatrix(&ProjMat, QuarterPi, 1.33333333f, 1.0f, 10000.0f); nuclear@0: SetProjectionMatrix(ProjMat); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: bool GraphicsContext::CreateVertexBuffer(uint32 VertexCount, UsageFlags usage, VertexBuffer **vb) const { nuclear@0: long hr = D3DDevice->CreateVertexBuffer(VertexCount * sizeof(Vertex), (dword)usage, VertexFormat, D3DPOOL_DEFAULT, vb); nuclear@0: return (hr == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::CreateIndexBuffer(uint32 IndexCount, UsageFlags usage, IndexBuffer **ib) const { nuclear@0: long hr = D3DDevice->CreateIndexBuffer(IndexCount * IndexSize, (dword)usage, IndexFormat, D3DPOOL_DEFAULT, ib); nuclear@0: return (hr == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::CreateSurface(uint32 Width, uint32 Height, Surface **surf) const { nuclear@0: long hr = D3DDevice->CreateImageSurface(Width, Height, ColorFormat, surf); nuclear@0: return (hr == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::CreateDepthStencil(uint32 Width, uint32 Height, Surface **zsurf) const { nuclear@0: long hr = D3DDevice->CreateDepthStencilSurface(Width, Height, ZFormat, (D3DMULTISAMPLE_TYPE)AASamples, zsurf); nuclear@0: return (hr == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::Clear(dword color) const { nuclear@0: D3DDevice->Clear(0, 0, D3DCLEAR_TARGET, color, 1.0f, 0); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::ClearZBuffer(float zval) const { nuclear@0: D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, zval, 0); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::ClearStencil(byte sval) const { nuclear@0: D3DDevice->Clear(0, 0, D3DCLEAR_STENCIL, 0, 1.0f, sval); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::ClearZBufferStencil(float zval, byte sval) const { nuclear@0: D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, zval, sval); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::Flip() const { nuclear@0: D3DDevice->Present(0, 0, 0, 0); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: bool GraphicsContext::Draw(VertexBuffer *vb) { nuclear@0: D3DVERTEXBUFFER_DESC desc; nuclear@0: vb->GetDesc(&desc); nuclear@0: unsigned int verts = desc.Size / sizeof(Vertex); nuclear@0: nuclear@0: D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); nuclear@0: long res = D3DDevice->DrawPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts / 3); nuclear@0: D3DDevice->SetStreamSource(0, 0, 0); nuclear@0: return res == D3D_OK; nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::Draw(Vertex *varray, unsigned int VertexCount) { nuclear@0: long res = D3DDevice->DrawPrimitiveUP((D3DPRIMITIVETYPE)ptype, VertexCount / 3, varray, sizeof(Vertex)); nuclear@0: return res == D3D_OK; nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::Draw(VertexBuffer *vb, IndexBuffer *ib) { nuclear@0: D3DVERTEXBUFFER_DESC vbdesc; nuclear@0: vb->GetDesc(&vbdesc); nuclear@0: unsigned int verts = vbdesc.Size / sizeof(Vertex); nuclear@0: nuclear@0: D3DINDEXBUFFER_DESC ibdesc; nuclear@0: ib->GetDesc(&ibdesc); nuclear@0: unsigned int indices = ibdesc.Size / sizeof(Index); nuclear@0: nuclear@0: D3DDevice->SetStreamSource(0, vb, sizeof(Vertex)); nuclear@0: D3DDevice->SetIndices(ib, 0); nuclear@0: long res = D3DDevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts, 0, indices / 3); nuclear@0: D3DDevice->SetIndices(0, 0); nuclear@0: D3DDevice->SetStreamSource(0, 0, 0); nuclear@0: return res == D3D_OK; nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::Draw(Vertex *varray, Index *iarray, unsigned int VertexCount, unsigned int IndexCount) { nuclear@0: long res = D3DDevice->DrawIndexedPrimitiveUP((D3DPRIMITIVETYPE)ptype, 0, VertexCount, IndexCount / 3, iarray, IndexFormat, varray, sizeof(Vertex)); nuclear@0: return res == D3D_OK; nuclear@0: } nuclear@0: nuclear@0: bool GraphicsContext::Draw(Vertex *varray, Triangle *triarray, unsigned int VertexCount, unsigned int TriCount) { nuclear@0: unsigned int IndexCount = TriCount * 3; nuclear@0: Index *iarray = new Index[IndexCount]; nuclear@0: for(dword i=0; iSetRenderState(D3DRS_CULLMODE, CullOrder); nuclear@0: } else { nuclear@0: D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); nuclear@0: } nuclear@0: BackfaceCulling = enable; nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetFrontFace(FaceOrder order) { nuclear@0: if(order == Clockwise) { nuclear@0: CullOrder = CounterClockwise; nuclear@0: } else { nuclear@0: CullOrder = Clockwise; nuclear@0: } nuclear@0: if(BackfaceCulling) SetBackfaceCulling(BackfaceCulling); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetAutoNormalize(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetBillboarding(bool enable) { nuclear@0: BillBoardingEnabled = enable; nuclear@0: if(enable) { nuclear@0: nuclear@0: Vector3 pos; nuclear@0: pos.Transform(WorldMat[0]); nuclear@0: nuclear@0: Matrix4x4 world; nuclear@0: world.Translate(pos.x, pos.y, pos.z); nuclear@0: Matrix4x4 BillBoardRot; nuclear@0: nuclear@0: Vector3 dir = ViewMat.Inverse().GetRowVector(2); nuclear@0: float yangle = dir.x > 0.0f ? -atanf(dir.z / dir.x) + HalfPi : -atanf(dir.z / dir.x) - HalfPi; nuclear@0: nuclear@0: BillBoardRot.Rotate(0.0f, yangle, 0.0f); nuclear@0: Vector3 xaxis = VECTOR3_I; nuclear@0: Vector3 normal = -VECTOR3_K; nuclear@0: xaxis.Transform(BillBoardRot); nuclear@0: normal.Transform(BillBoardRot); nuclear@0: nuclear@0: // find angle between quad normal and view direction nuclear@0: float xangle = acosf(DotProduct(normal, dir.Normalized())); nuclear@0: BillBoardRot.Rotate(xaxis, xangle); nuclear@0: nuclear@0: world = BillBoardRot * world; nuclear@0: nuclear@0: D3DDevice->SetTransform(D3DTS_WORLD, &world); nuclear@0: //D3DDevice->SetTransform(D3DTS_VIEW, &BillboardViewMatrix); nuclear@0: } else { nuclear@0: D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat[0]); nuclear@0: //D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetColorWrite(bool red, bool green, bool blue, bool alpha) { nuclear@0: dword channels = 0; nuclear@0: if(red) channels |= D3DCOLORWRITEENABLE_RED; nuclear@0: if(green) channels |= D3DCOLORWRITEENABLE_GREEN; nuclear@0: if(blue) channels |= D3DCOLORWRITEENABLE_BLUE; nuclear@0: if(alpha) channels |= D3DCOLORWRITEENABLE_ALPHA; nuclear@0: nuclear@0: D3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, channels); nuclear@0: } nuclear@0: nuclear@0: // blending states nuclear@0: void GraphicsContext::SetAlphaBlending(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetBlendFunc(BlendingFactor src, BlendingFactor dest) { nuclear@0: D3DDevice->SetRenderState(D3DRS_SRCBLEND, src); nuclear@0: D3DDevice->SetRenderState(D3DRS_DESTBLEND, dest); nuclear@0: } nuclear@0: nuclear@0: // zbuffer states nuclear@0: void GraphicsContext::SetZBuffering(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_ZENABLE, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetZWrite(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetZFunc(CmpFunc func) { nuclear@0: D3DDevice->SetRenderState(D3DRS_ZFUNC, func); nuclear@0: } nuclear@0: nuclear@0: // set stencil buffer states nuclear@0: void GraphicsContext::SetStencilBuffering(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILENABLE, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilPassOp(StencilOp sop) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILPASS, sop); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilFailOp(StencilOp sop) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILFAIL, sop); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilPassZFailOp(StencilOp sop) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, sop); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilOp(StencilOp Fail, StencilOp StencilPassZFail, StencilOp Pass) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILPASS, Pass); nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILFAIL, Fail); nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, StencilPassZFail); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilFunc(CmpFunc func) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILFUNC, func); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetStencilReference(dword value) { nuclear@0: D3DDevice->SetRenderState(D3DRS_STENCILREF, value); nuclear@0: } nuclear@0: nuclear@0: // texture & material states nuclear@0: nuclear@0: void GraphicsContext::SetTextureFactor(dword factor) { nuclear@0: D3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, factor); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureFiltering(TextureFilteringType texfilter, int TextureStage) { nuclear@0: dword TexFilter, MipFilter; nuclear@0: nuclear@0: switch(texfilter) { nuclear@0: case PointSampling: nuclear@0: TexFilter = MipFilter = D3DTEXF_POINT; nuclear@0: break; nuclear@0: nuclear@0: case BilinearFiltering: nuclear@0: TexFilter = D3DTEXF_LINEAR; nuclear@0: MipFilter = D3DTEXF_POINT; nuclear@0: break; nuclear@0: nuclear@0: case TrilinearFiltering: nuclear@0: TexFilter = MipFilter = D3DTEXF_LINEAR; nuclear@0: break; nuclear@0: nuclear@0: case AnisotropicFiltering: nuclear@0: TexFilter = D3DTEXF_ANISOTROPIC; nuclear@0: MipFilter = D3DTEXF_LINEAR; nuclear@0: break; nuclear@0: nuclear@0: default: break; nuclear@0: } nuclear@0: nuclear@0: this->MipFilter = MipFilter; nuclear@0: nuclear@0: if(!MipMapEnabled) MipFilter = D3DTEXF_NONE; nuclear@0: nuclear@0: if(TextureStage == 0xa11) { nuclear@0: for(int i=0; iSetTextureStageState(i, D3DTSS_MINFILTER, TexFilter); nuclear@0: D3DDevice->SetTextureStageState(i, D3DTSS_MAGFILTER, TexFilter); nuclear@0: D3DDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, MipFilter); nuclear@0: } nuclear@0: } else { nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MINFILTER, TexFilter); nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MAGFILTER, TexFilter); nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, MipFilter); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureAddressing(TextureAddressing uaddr, TextureAddressing vaddr, int TextureStage) { nuclear@0: if(TextureStage == 0xa11) { nuclear@0: for(int i=0; iSetTextureStageState(i, D3DTSS_ADDRESSU, uaddr); nuclear@0: D3DDevice->SetTextureStageState(i, D3DTSS_ADDRESSV, vaddr); nuclear@0: } nuclear@0: } else { nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSU, uaddr); nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSV, vaddr); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureBorderColor(dword color, int TextureStage) { nuclear@0: if(TextureStage == 0xa11) { nuclear@0: for(int i=0; iSetTextureStageState(i, D3DTSS_BORDERCOLOR, color); nuclear@0: } nuclear@0: } else { nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_BORDERCOLOR, color); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTexture(int index, Texture *tex) { nuclear@0: D3DDevice->SetTexture(index, tex); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetMipMapping(bool enable, int TextureStage) { nuclear@0: MipMapEnabled = enable; nuclear@0: dword mip = (enable ? MipFilter : D3DTEXF_NONE); nuclear@0: nuclear@0: if(TextureStage == 0xa11) { nuclear@0: for(int i=0; iSetTextureStageState(i, D3DTSS_MIPFILTER, mip); nuclear@0: } nuclear@0: } else { nuclear@0: D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, mip); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetMaterial(const Material &mat) { nuclear@0: D3DDevice->SetMaterial(&mat); nuclear@0: } nuclear@0: nuclear@0: static unsigned long TLVertexFVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1; nuclear@0: nuclear@0: struct TLVertex { nuclear@0: Vector3 pos; nuclear@0: float rhw; nuclear@0: unsigned long color; nuclear@0: TexCoord tex; nuclear@0: nuclear@0: TLVertex() { nuclear@0: pos = Vector3(0.0f, 0.0f, 0.0f); nuclear@0: color = 0xffffffff; nuclear@0: tex.u = tex.v = 0.0f; nuclear@0: rhw = pos.z; nuclear@0: } nuclear@0: nuclear@0: TLVertex(const Vector3 &pos, const Color &col, float u=0.0f, float v=0.0f) { nuclear@0: this->pos = pos; nuclear@0: rhw = pos.z; nuclear@0: color = col.GetPacked32(); nuclear@0: tex.u = u; nuclear@0: tex.v = v; nuclear@0: } nuclear@0: }; nuclear@0: nuclear@0: void GraphicsContext::BlitTexture(const Texture *texture, RECT *rect, const Color &col) { nuclear@0: bool norect = rect ? false : true; nuclear@0: if(norect) { nuclear@0: rect = new RECT; nuclear@0: rect->left = rect->top = 0; nuclear@0: rect->right = ContextParams.x; nuclear@0: rect->bottom = ContextParams.y; nuclear@0: } nuclear@0: nuclear@0: SetVertexProgram(TLVertexFVF); nuclear@0: nuclear@0: TLVertex tlverts[4]; nuclear@0: tlverts[0] = TLVertex(Vector3((float)rect->right, (float)rect->top, 1.0f), col, 1.0f, 0.0f); nuclear@0: tlverts[1] = TLVertex(Vector3((float)rect->right, (float)rect->bottom, 1.0f), col, 1.0f, 1.0f); nuclear@0: tlverts[2] = TLVertex(Vector3((float)rect->left, (float)rect->top, 1.0f), col, 0.0f, 0.0f); nuclear@0: tlverts[3] = TLVertex(Vector3((float)rect->left, (float)rect->bottom, 1.0f), col, 0.0f, 1.0f); nuclear@0: nuclear@0: EnableTextureStage(0); nuclear@0: DisableTextureStage(1); nuclear@0: SetTexture(0, const_cast(texture)); nuclear@0: nuclear@0: SetZBuffering(false); nuclear@0: D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, tlverts, sizeof(TLVertex)); nuclear@0: SetZBuffering(true); nuclear@0: nuclear@0: SetTexture(0, 0); nuclear@0: nuclear@0: SetVertexProgram(VertexFormat); nuclear@0: nuclear@0: if(norect) { nuclear@0: delete rect; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // multitexturing interface nuclear@0: void GraphicsContext::EnableTextureStage(int stage) { nuclear@0: SetTextureStageColor(stage, TexBlendModulate, TexArgTexture, TexArgCurrent); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::DisableTextureStage(int stage) { nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureStageColor(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) { nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, op); nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, arg1); nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, arg2); nuclear@0: if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, arg3); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureStageAlpha(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) { nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, op); nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, arg1); nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, arg2); nuclear@0: if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, arg3); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureCoordIndex(int stage, int index) { nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_TEXCOORDINDEX, index); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureTransformState(int stage, TexTransformState TexXForm) { nuclear@0: D3DDevice->SetTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS, TexXForm); nuclear@0: } nuclear@0: nuclear@0: // programmable pipeline interface nuclear@0: void GraphicsContext::SetVertexProgram(dword vs) { nuclear@0: D3DDevice->SetVertexShader(vs); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetPixelProgram(dword ps) { nuclear@0: D3DDevice->SetPixelShader(ps); nuclear@0: } nuclear@0: nuclear@0: dword GraphicsContext::CreateVertexProgram(const char *fname) { nuclear@0: nuclear@0: // vertex format declaration nuclear@0: dword VertDecl[] = { nuclear@0: D3DVSD_STREAM(0), nuclear@0: D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3), nuclear@0: D3DVSD_REG(D3DVSDE_BLENDWEIGHT, D3DVSDT_FLOAT1), nuclear@0: D3DVSD_REG(D3DVSDE_BLENDINDICES, D3DVSDT_UBYTE4), nuclear@0: D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3), nuclear@0: D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR), nuclear@0: D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2), nuclear@0: D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2), nuclear@0: D3DVSD_REG(D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT2), nuclear@0: D3DVSD_REG(D3DVSDE_TEXCOORD3, D3DVSDT_FLOAT2), nuclear@0: D3DVSD_END() nuclear@0: }; nuclear@0: nuclear@0: nuclear@0: ID3DXBuffer *code, *errors; nuclear@0: if(D3DXAssembleShaderFromFile(fname, 0, 0, &code, &errors) != D3D_OK) { nuclear@0: return 0xffffffff; nuclear@0: } nuclear@0: nuclear@0: dword vprog; nuclear@0: if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, 0) != D3D_OK) { nuclear@0: // could not create hardware vertex shader, try driver emulation... nuclear@0: if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, D3DUSAGE_SOFTWAREPROCESSING) != D3D_OK) { nuclear@0: throw EngineGeneralException("The system lacks required programmable vertex processing unit support"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return vprog; nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::DestroyVertexProgram(dword vprog) { nuclear@0: D3DDevice->DeleteVertexShader(vprog); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, float val) { nuclear@0: float block[4] = {val, 0.0f, 0.0f, 1.0f}; nuclear@0: D3DDevice->SetVertexShaderConstant(creg, &block, 1); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector3 &val) { nuclear@0: Vector4 vec(val); nuclear@0: D3DDevice->SetVertexShaderConstant(creg, &vec, 1); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector4 &val) { nuclear@0: D3DDevice->SetVertexShaderConstant(creg, &val, 1); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, const Color &val) { nuclear@0: D3DDevice->SetVertexShaderConstant(creg, &val, 1); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, const Matrix4x4 &val) { nuclear@0: D3DDevice->SetVertexShaderConstant(creg, &val, 4); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetVertexProgramConstant(dword creg, const void *data, dword size) { nuclear@0: D3DDevice->SetVertexShaderConstant(creg, data, size); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // Lighting states nuclear@0: void GraphicsContext::SetLighting(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_LIGHTING, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetColorVertex(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_COLORVERTEX, enable); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetAmbientLight(Color AmbientColor) { nuclear@0: D3DDevice->SetRenderState(D3DRS_AMBIENT, AmbientColor.GetPacked32()); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetShadingMode(ShadeMode mode) { nuclear@0: D3DDevice->SetRenderState(D3DRS_SHADEMODE, mode); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetSpecular(bool enable) { nuclear@0: D3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable); nuclear@0: } nuclear@0: nuclear@0: // transformation states nuclear@0: void GraphicsContext::SetWorldMatrix(const Matrix4x4 &WorldMat, unsigned int BlendIndex) { nuclear@0: assert(BlendIndex < 256); nuclear@0: this->WorldMat[BlendIndex] = WorldMat; nuclear@0: if(!BillBoardingEnabled) { nuclear@0: D3DDevice->SetTransform(D3DTS_WORLDMATRIX(BlendIndex), &WorldMat); nuclear@0: } else { nuclear@0: SetBillboarding(true); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetViewMatrix(const Matrix4x4 &ViewMat) { nuclear@0: this->ViewMat = ViewMat; nuclear@0: if(!BillBoardingEnabled) { nuclear@0: D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat); nuclear@0: } else { nuclear@0: SetBillboarding(true); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetProjectionMatrix(const Matrix4x4 &ProjMat) { nuclear@0: this->ProjMat = ProjMat; nuclear@0: D3DDevice->SetTransform(D3DTS_PROJECTION, &ProjMat); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetTextureMatrix(const Matrix4x4 &TexMat, unsigned int TextureStage) { nuclear@0: assert(TextureStage < 8); nuclear@0: this->TexMat[TextureStage] = TexMat; nuclear@0: D3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)((int)D3DTS_TEXTURE0 + TextureStage), &TexMat); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetViewport(unsigned int x, unsigned int y, unsigned int xsize, unsigned int ysize, float MinZ, float MaxZ) { nuclear@0: D3DVIEWPORT8 viewport; nuclear@0: viewport.X = x; nuclear@0: viewport.Y = y; nuclear@0: viewport.Width = xsize; nuclear@0: viewport.Height = ysize; nuclear@0: viewport.MinZ = MinZ; nuclear@0: viewport.MaxZ = MaxZ; nuclear@0: nuclear@0: D3DDevice->SetViewport(&viewport); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: const Matrix4x4 &GraphicsContext::GetWorldMatrix(unsigned int BlendIndex) { nuclear@0: assert(BlendIndex < 256); nuclear@0: return WorldMat[BlendIndex]; nuclear@0: } nuclear@0: nuclear@0: const Matrix4x4 &GraphicsContext::GetViewMatrix() { nuclear@0: return ViewMat; nuclear@0: } nuclear@0: nuclear@0: const Matrix4x4 &GraphicsContext::GetProjectionMatrix() { nuclear@0: return ProjMat; nuclear@0: } nuclear@0: nuclear@0: const Matrix4x4 &GraphicsContext::GetTextureMatrix(unsigned int TextureStage) { nuclear@0: assert(TextureStage < 8); nuclear@0: return TexMat[TextureStage]; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // render target nuclear@0: void GraphicsContext::ResetRenderTarget() { nuclear@0: D3DDevice->SetRenderTarget(MainRenderTarget.ColorSurface, MainRenderTarget.DepthStencilSurface); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetRenderTarget(RenderTarget &rtarg) { nuclear@0: D3DDevice->SetRenderTarget(rtarg.ColorSurface, rtarg.DepthStencilSurface); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetRenderTarget(Texture *rtarg, Texture *ztarg) { nuclear@0: Surface *rendsurf, *zsurf = 0; nuclear@0: rtarg->GetSurfaceLevel(0, &rendsurf); nuclear@0: if(ztarg) ztarg->GetSurfaceLevel(0, &zsurf); nuclear@0: nuclear@0: D3DDevice->SetRenderTarget(rendsurf, zsurf); nuclear@0: } nuclear@0: nuclear@0: void GraphicsContext::SetRenderTarget(Texture *rtarg, Surface *ztarg) { nuclear@0: Surface *rendsurf; nuclear@0: rtarg->GetSurfaceLevel(0, &rendsurf); nuclear@0: nuclear@0: D3DDevice->SetRenderTarget(rendsurf, ztarg); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //////////////////////////////////////////////////// nuclear@0: //////////// Engine3D Member Functions ///////////// nuclear@0: //////////////////////////////////////////////////// nuclear@0: nuclear@0: Engine3D::Engine3D() { nuclear@0: nuclear@0: if(!(d3d = Direct3DCreate8(D3D_SDK_VERSION))) { nuclear@0: // actually this will never occur, if directx8 is not available in the system then nuclear@0: // the OS loader will hit the problem first when it'll try to load d3d8.dll that is nuclear@0: // linked through d3d8.lib, and complain for missing imports nuclear@0: throw EngineInitException("DirectX 8.1 is required to run this program"); nuclear@0: } nuclear@0: nuclear@0: RetrieveAdapterInfo(); nuclear@0: } nuclear@0: nuclear@0: Engine3D::~Engine3D() { nuclear@0: nuclear@0: GraphicsContexts.erase(GraphicsContexts.begin(), GraphicsContexts.end()); nuclear@0: nuclear@0: if(d3d) { nuclear@0: d3d->Release(); nuclear@0: d3d = 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: //////////////////////////////////// nuclear@0: // ----==( RetrieveAdapterInfo )==---- nuclear@0: // (Private Member Function) nuclear@0: // Gets the list of adapters on the system and additional nuclear@0: // information for each adapter including its capabilities nuclear@0: //////////////////////////////////// nuclear@0: void Engine3D::RetrieveAdapterInfo() { nuclear@0: nuclear@0: // retrieve adapter list nuclear@0: AdapterCount = d3d->GetAdapterCount(); nuclear@0: adapters = new Adapter[AdapterCount]; nuclear@0: nuclear@0: for(unsigned int i=0; iGetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &AdapterIdentifier); nuclear@0: adapters[i].Description = new char[strlen(AdapterIdentifier.Description)+1]; nuclear@0: strcpy(adapters[i].Description, AdapterIdentifier.Description); nuclear@0: adapters[i].Driver = new char[strlen(AdapterIdentifier.Driver)+1]; nuclear@0: strcpy(adapters[i].Driver, AdapterIdentifier.Driver); nuclear@0: nuclear@0: adapters[i].DeviceGUID = AdapterIdentifier.DeviceIdentifier; nuclear@0: adapters[i].DeviceID = AdapterIdentifier.DeviceId; nuclear@0: adapters[i].DriverVersion = AdapterIdentifier.DriverVersion.QuadPart; nuclear@0: adapters[i].Revision = AdapterIdentifier.Revision; nuclear@0: adapters[i].SubSysID = AdapterIdentifier.SubSysId; nuclear@0: adapters[i].VentorID = AdapterIdentifier.VendorId; nuclear@0: nuclear@0: // get a list of display modes for this adapter nuclear@0: LinkedList dmlist; nuclear@0: adapters[i].ModeCount = d3d->GetAdapterModeCount(i); nuclear@0: for(unsigned int j=0; jEnumAdapterModes(i, j, &d3dmode); nuclear@0: mode.XRes = d3dmode.Width; nuclear@0: mode.YRes = d3dmode.Height; nuclear@0: mode.RefreshRate = d3dmode.RefreshRate; nuclear@0: mode.ColorFormat = GetColorDepthFromPixelFormat(d3dmode.Format); nuclear@0: nuclear@0: // check if this mode is supported from the HAL device nuclear@0: D3DFORMAT dispfmt = GetPixelFormatFromColorDepth(mode.ColorFormat, true); nuclear@0: if(d3d->CheckDeviceType(i, D3DDEVTYPE_HAL, dispfmt, d3dmode.Format, false) == D3D_OK) { nuclear@0: dmlist.PushBack(mode); nuclear@0: } nuclear@0: } nuclear@0: adapters[i].ModeCount = dmlist.Size(); // count of the modes that are supported through HW nuclear@0: adapters[i].Modes = new DisplayMode[adapters[i].ModeCount]; nuclear@0: ListNode *iter = dmlist.Begin(); nuclear@0: int j = 0; nuclear@0: while(iter) { nuclear@0: adapters[i].Modes[j++] = iter->data; nuclear@0: iter = iter->next; nuclear@0: } nuclear@0: nuclear@0: // get the device capabilities nuclear@0: d3d->GetDeviceCaps(i, D3DDEVTYPE_HAL, &adapters[i].Capabilities); nuclear@0: int vsver_major = D3DSHADER_VERSION_MAJOR(adapters[i].Capabilities.VertexShaderVersion); nuclear@0: int vsver_minor = D3DSHADER_VERSION_MINOR(adapters[i].Capabilities.VertexShaderVersion); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: //////////////////////////////////// nuclear@0: // ----==( CreateModesList )==---- nuclear@0: // (Private Member Function) nuclear@0: // Creates a linked list of the available modes nuclear@0: // of a single adapter for further processing nuclear@0: //////////////////////////////////// nuclear@0: LinkedList *Engine3D::CreateModesList(unsigned int AdapterID) const { nuclear@0: nuclear@0: if(AdapterID >= AdapterCount) return 0; nuclear@0: nuclear@0: LinkedList *newlist = new LinkedList; nuclear@0: for(unsigned int i=0; iPushBack(adapters[AdapterID].Modes[i]); nuclear@0: } nuclear@0: return newlist; nuclear@0: } nuclear@0: nuclear@0: //////////////////////////////////// nuclear@0: // ----==( NarrowModesList )==---- nuclear@0: // (Private Member Function) nuclear@0: // Narrows down the list of available modes nuclear@0: // to those that have the requested item nuclear@0: //////////////////////////////////// nuclear@0: void Engine3D::NarrowModesList(LinkedList *list, DisplayModeItem item, long value, long value2) const { nuclear@0: nuclear@0: ListNode *iter = list->Begin(); nuclear@0: while(iter) { nuclear@0: switch(item) { nuclear@0: case ModeItemSize: nuclear@0: if(iter->data.XRes != value || iter->data.YRes != value2) { nuclear@0: iter = list->Erase(iter); nuclear@0: } else { nuclear@0: if(iter) iter = iter->next; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ModeItemBpp: nuclear@0: if(iter->data.ColorFormat.bpp != value) { nuclear@0: iter = list->Erase(iter); nuclear@0: } else { nuclear@0: if(iter) iter = iter->next; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ModeItemAlpha: nuclear@0: if(!iter->data.ColorFormat.alpha && value) { nuclear@0: iter = list->Erase(iter); nuclear@0: } else { nuclear@0: if(iter) iter = iter->next; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case ModeItemRefresh: nuclear@0: if(iter->data.RefreshRate != value) { nuclear@0: iter = list->Erase(iter); nuclear@0: } else { nuclear@0: if(iter) iter = iter->next; nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: default: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /////////////////////////////////// nuclear@0: // ----==( ChooseBestMode )==---- nuclear@0: // (Private Member Function) nuclear@0: // given a (ideally) narrowed down modes list nuclear@0: // choose the best possible among them nuclear@0: /////////////////////////////////// nuclear@0: DisplayMode Engine3D::ChooseBestMode(LinkedList *modes) const { nuclear@0: nuclear@0: DisplayMode dmode; nuclear@0: memset(&dmode, 0, sizeof(DisplayMode)); nuclear@0: nuclear@0: if(!modes || !modes->Size()) return dmode; nuclear@0: nuclear@0: // find the highest resolution and get only the modes with that resolution nuclear@0: ListNode *iter = modes->Begin(); nuclear@0: unsigned int maxx = 0, maxy = 0; nuclear@0: while(iter) { nuclear@0: if(iter->data.XRes > maxx) maxx = iter->data.XRes; nuclear@0: if(iter->data.YRes > maxy) maxy = iter->data.YRes; nuclear@0: iter = iter->next; nuclear@0: } nuclear@0: NarrowModesList(modes, ModeItemSize, maxx, maxy); nuclear@0: nuclear@0: // find the modes with alpha if any nuclear@0: iter = modes->Begin(); nuclear@0: bool AnyWithAlpha = false; nuclear@0: while(iter) { nuclear@0: if(iter->data.ColorFormat.alpha) { nuclear@0: AnyWithAlpha = true; nuclear@0: break; nuclear@0: } nuclear@0: iter = iter->next; nuclear@0: } nuclear@0: if(AnyWithAlpha) NarrowModesList(modes, ModeItemAlpha, 1); nuclear@0: nuclear@0: // find the modes with the highest bpp nuclear@0: iter = modes->Begin(); nuclear@0: int maxbpp = 0; nuclear@0: while(iter) { nuclear@0: if(iter->data.ColorFormat.bpp > maxbpp) maxbpp = iter->data.ColorFormat.bpp; nuclear@0: iter = iter->next; nuclear@0: } nuclear@0: NarrowModesList(modes, ModeItemBpp, maxbpp); nuclear@0: nuclear@0: // find the modes with the highest refresh rate nuclear@0: iter = modes->Begin(); nuclear@0: unsigned int maxrefresh = 0; nuclear@0: while(iter) { nuclear@0: if(iter->data.RefreshRate > maxrefresh) maxrefresh = iter->data.RefreshRate; nuclear@0: iter = iter->next; nuclear@0: } nuclear@0: NarrowModesList(modes, ModeItemRefresh, maxrefresh); nuclear@0: nuclear@0: // if there is more than one mode left, then there is a problem :) nuclear@0: assert(modes->Size() == 1); nuclear@0: nuclear@0: dmode = modes->Begin()->data; nuclear@0: return dmode; nuclear@0: } nuclear@0: nuclear@0: ////////////////////////////////////////// nuclear@0: // ----==( CreateGraphicsContext )==---- nuclear@0: // (Public Member Function) nuclear@0: // Creates a graphics context with the specified parameters nuclear@0: ////////////////////////////////////////// nuclear@0: GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, unsigned int AdapterID, ContextInitParameters *GCParams) { nuclear@0: nuclear@0: if(AdapterID >= AdapterCount) return 0; nuclear@0: nuclear@0: // check adapter's Transformation & Lighting capability nuclear@0: bool hwtnl = (bool)(adapters[AdapterID].Capabilities.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT); nuclear@0: if(!(GCParams->DontCareFlags & GCPDONTCARE_TNL)) { // bit not set, we want specific TnL mode nuclear@0: if(hwtnl != GCParams->HardwareTnL && !hwtnl) return 0; // we asked for hw tnl and is not available nuclear@0: // else either we asked for sw and found hw so we continue with our initial sw setting nuclear@0: // or we found exactly what we asked, so we still continue with our choice nuclear@0: } else { nuclear@0: GCParams->HardwareTnL = hwtnl; // if we don't care use what we have available nuclear@0: } nuclear@0: nuclear@0: // decide which mode to use nuclear@0: LinkedList *modes = CreateModesList(AdapterID); nuclear@0: NarrowModesList(modes, ModeItemSize, GCParams->x, GCParams->y); nuclear@0: nuclear@0: if(!(GCParams->DontCareFlags & GCPDONTCARE_BPP)) { // we want specific bpp nuclear@0: NarrowModesList(modes, ModeItemBpp, GCParams->bpp); nuclear@0: } nuclear@0: nuclear@0: if(!(GCParams->DontCareFlags & GCPDONTCARE_ALPHA)) { // alpha setting exactly as asked nuclear@0: NarrowModesList(modes, ModeItemAlpha, (long)GCParams->AlphaChannel); nuclear@0: } nuclear@0: nuclear@0: if(!(GCParams->DontCareFlags & GCPDONTCARE_REFRESH)) { // specific refresh rate nuclear@0: NarrowModesList(modes, ModeItemRefresh, GCParams->RefreshRate); nuclear@0: } nuclear@0: nuclear@0: if(!modes->Size()) { // didn't find any mode with the properties that we asked nuclear@0: throw EngineInitException("Requested video mode parameters not available"); nuclear@0: } nuclear@0: nuclear@0: DisplayMode mode = ChooseBestMode(modes); nuclear@0: delete modes; // delete the list of modes nuclear@0: nuclear@0: D3DFORMAT PixelFormat = GetPixelFormatFromColorDepth(mode.ColorFormat); nuclear@0: nuclear@0: // find out if we have the requested zbuffer format avaialble nuclear@0: if(!GCParams->DepthBits) GCParams->DepthBits = 32; // not specified, trying highest possible first nuclear@0: D3DFORMAT zfmt = GetDepthStencilFormat(GCParams->DepthBits, true); nuclear@0: nuclear@0: bool res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); nuclear@0: if(!res) { // try a format without stencil nuclear@0: zfmt = GetDepthStencilFormat(GCParams->DepthBits, false); nuclear@0: res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); nuclear@0: } nuclear@0: nuclear@0: if(!res) { // didn't find requested zbuffer even with no stencil nuclear@0: // if we asked for specific zformat and didn't find it or if the zbuffer that nuclear@0: // we failed to set was 16bits and can't go less, bail out nuclear@0: if(!(GCParams->DontCareFlags & GCPDONTCARE_DEPTH) || GCParams->DepthBits == 16) return 0; nuclear@0: nuclear@0: // try to set a smaller zbuffer with stencil nuclear@0: GCParams->DepthBits = 16; nuclear@0: zfmt = GetDepthStencilFormat(GCParams->DepthBits, true); nuclear@0: res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); nuclear@0: if(!res) { // try a format without stencil nuclear@0: zfmt = GetDepthStencilFormat(GCParams->DepthBits, false); nuclear@0: res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt); nuclear@0: } nuclear@0: nuclear@0: if(!res) throw EngineInitException("Requested ZBuffer depth not available"); nuclear@0: } nuclear@0: nuclear@0: int AASamples = 0; nuclear@0: if(GCParams->Antialiasing) { nuclear@0: if(GCParams->BestAA) { nuclear@0: // find the best supported AA mode nuclear@0: for(AASamples=16; AASamples > 0; AASamples--) { nuclear@0: long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples); nuclear@0: if(result == D3D_OK) break; nuclear@0: } nuclear@0: } else { nuclear@0: // check for cheap AA nuclear@0: AASamples = 2; nuclear@0: long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples); nuclear@0: if(result != D3D_OK) AASamples = 0; nuclear@0: } nuclear@0: nuclear@0: if(!AASamples && !(GCParams->DontCareFlags & GCPDONTCARE_AA)) { nuclear@0: throw EngineInitException("Requested Antialiasing mode not available"); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: D3DFORMAT FinalColorFormat; nuclear@0: if(GCParams->FullScreen) { nuclear@0: FinalColorFormat = GetPixelFormatFromColorDepth(mode.ColorFormat); nuclear@0: } else { nuclear@0: D3DDISPLAYMODE CurrentMode; nuclear@0: d3d->GetAdapterDisplayMode(AdapterID, &CurrentMode); nuclear@0: FinalColorFormat = CurrentMode.Format; nuclear@0: } nuclear@0: nuclear@0: // if everything went well, now we can set that mode nuclear@0: D3DPRESENT_PARAMETERS d3dppar; nuclear@0: d3dppar.BackBufferWidth = GCParams->x; nuclear@0: d3dppar.BackBufferHeight = GCParams->y; nuclear@0: d3dppar.BackBufferFormat = FinalColorFormat; nuclear@0: d3dppar.BackBufferCount = (unsigned int)GCParams->Buffers; nuclear@0: d3dppar.MultiSampleType = (D3DMULTISAMPLE_TYPE)AASamples; nuclear@0: d3dppar.SwapEffect = D3DSWAPEFFECT_DISCARD; nuclear@0: d3dppar.hDeviceWindow = WindowHandle; nuclear@0: d3dppar.Windowed = !GCParams->FullScreen; nuclear@0: d3dppar.EnableAutoDepthStencil = true; nuclear@0: d3dppar.AutoDepthStencilFormat = zfmt; nuclear@0: d3dppar.Flags = 0; nuclear@0: d3dppar.FullScreen_RefreshRateInHz = (GCParams->FullScreen) ? mode.RefreshRate : 0; nuclear@0: if(GCParams->FullScreen) { nuclear@0: d3dppar.FullScreen_PresentationInterval = (GCParams->VSync) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; nuclear@0: } else { nuclear@0: d3dppar.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; nuclear@0: } nuclear@0: nuclear@0: // create the rendering context nuclear@0: GraphicsContext *gc = new GraphicsContext; nuclear@0: nuclear@0: TnLMode tnlmode = (GCParams->HardwareTnL) ? HardwareTnL : SoftwareTnL; nuclear@0: nuclear@0: long result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice); nuclear@0: if(result != D3D_OK) { nuclear@0: if(d3dppar.BackBufferCount != GCParams->Buffers) { nuclear@0: if((GCParams->DontCareFlags & GCPDONTCARE_BUFFERS)) { nuclear@0: result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice); nuclear@0: } else { nuclear@0: throw EngineInitException("Could not create Direct3D device"); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(result != D3D_OK) { nuclear@0: throw EngineInitException("Could not create Direct3D device"); nuclear@0: } nuclear@0: nuclear@0: gc->WindowHandle = WindowHandle; nuclear@0: gc->D3DDevice->GetRenderTarget(&gc->MainRenderTarget.ColorSurface); nuclear@0: gc->D3DDevice->GetDepthStencilSurface(&gc->MainRenderTarget.DepthStencilSurface); nuclear@0: gc->ContextParams = *GCParams; nuclear@0: gc->ZFormat = zfmt; nuclear@0: gc->AASamples = AASamples; nuclear@0: gc->ColorFormat = FinalColorFormat; nuclear@0: gc->MaxTextureStages = adapters[AdapterID].Capabilities.MaxSimultaneousTextures; nuclear@0: gc->texman = new TextureManager(gc); nuclear@0: nuclear@0: gc->SetDefaultStates(); nuclear@0: nuclear@0: GraphicsContexts.push_back(gc); nuclear@0: nuclear@0: return gc; nuclear@0: } nuclear@0: nuclear@0: ////////////////////////////////////////// nuclear@0: // ----==( CreateGraphicsContext )==---- nuclear@0: // (Public Member Function) nuclear@0: // Creates a graphics context with the specified parameters nuclear@0: // Light version, basic info passed, fills in the rest nuclear@0: ////////////////////////////////////////// nuclear@0: GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, int x, int y, int bpp, word flags) { nuclear@0: nuclear@0: ContextInitParameters gcp; nuclear@0: gcp.x = x; nuclear@0: gcp.y = y; nuclear@0: gcp.bpp = bpp; nuclear@0: gcp.DepthBits = 24; nuclear@0: gcp.DevType = DeviceHardware; nuclear@0: gcp.FullScreen = (flags & GCCREATE_FULLSCREEN) ? true : false; nuclear@0: gcp.HardwareTnL = true; nuclear@0: gcp.RefreshRate = 75; nuclear@0: gcp.Antialiasing = false; nuclear@0: gcp.Buffers = DoubleBuffering; nuclear@0: gcp.VSync = false; nuclear@0: gcp.DontCareFlags = GCPDONTCARE_DEPTH | GCPDONTCARE_REFRESH | GCPDONTCARE_ALPHA | GCPDONTCARE_VSYNC; nuclear@0: nuclear@0: return CreateGraphicsContext(WindowHandle, D3DADAPTER_DEFAULT, &gcp); nuclear@0: } nuclear@0: nuclear@0: using std::string; nuclear@0: using std::getline; nuclear@0: nuclear@0: string GetValue(string line) { nuclear@0: int nexttoken = (int)line.find("=") + 1; nuclear@0: while(line[++nexttoken] == ' '); nuclear@0: int tokenend = (int)line.find_first_of(" \n\r\t"); nuclear@0: return line.substr(nexttoken, tokenend - nexttoken); nuclear@0: } nuclear@0: nuclear@0: ContextInitParameters Engine3D::LoadContextParamsConfigFile(const char *cfgfilename) { nuclear@0: ContextInitParameters cip; nuclear@0: memset(&cip, 0, sizeof(ContextInitParameters)); nuclear@0: nuclear@0: std::ifstream file(cfgfilename); nuclear@0: if(!file.is_open()) throw EngineInitException("Could not open configuration file"); nuclear@0: nuclear@0: string line; nuclear@0: getline(file, line); nuclear@0: while(!file.eof()) { nuclear@0: if(line[0] != ';' && line[0] != '\n' && line[0] != '\r' && line[0] != ' ') { nuclear@0: int tokenend = (int)line.find(" "); nuclear@0: string token = line.substr(0, tokenend); nuclear@0: nuclear@0: if(token == "fullscreen") { nuclear@0: string value = GetValue(line); nuclear@0: cip.FullScreen = (value == "true") ? true : false; nuclear@0: } else if(token == "resolution") { nuclear@0: string value = GetValue(line); nuclear@0: int x = (int)value.find("x"); nuclear@0: cip.x = atoi(value.substr(0, x).c_str()); nuclear@0: cip.y = atoi(value.substr(x+1, value.size()).c_str()); nuclear@0: } else if(token == "bpp") { nuclear@0: cip.bpp = atoi(GetValue(line).c_str()); nuclear@0: } else if(token == "zbufferdepth") { nuclear@0: cip.DepthBits = atoi(GetValue(line).c_str()); nuclear@0: } else if(token == "device") { nuclear@0: cip.DevType = (GetValue(line) == "ref") ? DeviceReference : DeviceHardware; nuclear@0: } else if(token == "tnl") { nuclear@0: cip.HardwareTnL = (GetValue(line) == "false") ? false : true; nuclear@0: } else if(token == "refresh") { nuclear@0: cip.RefreshRate = atoi(GetValue(line).c_str()); nuclear@0: } else if(token == "antialiasing") { nuclear@0: string value = GetValue(line); nuclear@0: cip.Antialiasing = (value == "none") ? false : true; nuclear@0: if(cip.Antialiasing) { nuclear@0: cip.BestAA = (value == "speed" || value == "low") ? false : true; nuclear@0: } nuclear@0: } else if(token == "flipchain") { nuclear@0: cip.Buffers = (GetValue(line) == "triplebuffering") ? TripleBuffering : DoubleBuffering; nuclear@0: } else if(token == "vsync") { nuclear@0: cip.VSync = (GetValue(line) == "true") ? true : false; nuclear@0: } else if(token == "dontcareabout") { nuclear@0: cip.DontCareFlags = 0; nuclear@0: string flags = GetValue(line); nuclear@0: string part; nuclear@0: while(1) { nuclear@0: int begin = (int)flags.find_first_not_of(", "); nuclear@0: int end = (int)flags.find(",", begin) - begin; nuclear@0: part = flags.substr(begin, end); nuclear@0: //part = flags.substr(0, flags.find(","));// \n\r\t")); nuclear@0: if(part.empty()) break; nuclear@0: if(part == "bpp") cip.DontCareFlags |= GCPDONTCARE_BPP; nuclear@0: if(part == "refresh") cip.DontCareFlags |= GCPDONTCARE_REFRESH; nuclear@0: if(part == "alpha") cip.DontCareFlags |= GCPDONTCARE_ALPHA; nuclear@0: if(part == "zbufferdepth") cip.DontCareFlags |= GCPDONTCARE_DEPTH; nuclear@0: if(part == "tnl") cip.DontCareFlags |= GCPDONTCARE_TNL; nuclear@0: if(part == "flipchain") cip.DontCareFlags |= GCPDONTCARE_BUFFERS; nuclear@0: if(part == "aamode") cip.DontCareFlags |= GCPDONTCARE_AA; nuclear@0: if(part == "vsync") cip.DontCareFlags |= GCPDONTCARE_VSYNC; nuclear@0: int temp = (int)flags.find_first_of(",\n\r"); nuclear@0: if(temp == string::npos) break; nuclear@0: flags.erase(0, temp+1); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: nuclear@0: getline(file, line); nuclear@0: } nuclear@0: nuclear@0: return cip; nuclear@0: } nuclear@0: nuclear@0: void Engine3D::DestroyGraphicsContext(GraphicsContext *gc) { nuclear@0: gc->D3DDevice->Release(); nuclear@0: } nuclear@0: nuclear@0: int Engine3D::GetAdapterCount() const { nuclear@0: return AdapterCount; nuclear@0: } nuclear@0: nuclear@0: const Adapter *Engine3D::GetAdapterInfo(int adapter) const { nuclear@0: return &adapters[adapter]; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: ////////////////////////////////////////////////////////////////////////////// nuclear@0: // helper functions nuclear@0: nuclear@0: bool Lock(VertexBuffer *vb, Vertex **data) { nuclear@0: D3DVERTEXBUFFER_DESC desc; nuclear@0: vb->GetDesc(&desc); nuclear@0: dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0; nuclear@0: nuclear@0: return (vb->Lock(0, 0, (byte**)data, flags) == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: bool Lock(IndexBuffer *ib, Index **data) { nuclear@0: D3DINDEXBUFFER_DESC desc; nuclear@0: ib->GetDesc(&desc); nuclear@0: dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0; nuclear@0: nuclear@0: return (ib->Lock(0, 0, (byte**)data, flags) == D3D_OK); nuclear@0: } nuclear@0: nuclear@0: void Unlock(VertexBuffer *vb) { nuclear@0: vb->Unlock(); nuclear@0: } nuclear@0: nuclear@0: void Unlock(IndexBuffer *ib) { nuclear@0: ib->Unlock(); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void CreateProjectionMatrix(Matrix4x4 *mat, float yFOV, float Aspect, float NearClip, float FarClip) { nuclear@0: nuclear@0: float h, w, Q; nuclear@0: float xFOV = yFOV * Aspect; nuclear@0: nuclear@0: w = (float)(1.0f/tan(xFOV*0.5f)); // 1/tan(x) == cot(x) nuclear@0: h = (float)(1.0f/tan(yFOV*0.5f)); // 1/tan(x) == cot(x) nuclear@0: Q = FarClip / (FarClip - NearClip); nuclear@0: nuclear@0: /* Projection Matrix nuclear@0: [ w 0.0f 0.0f 0.0f] nuclear@0: |0.0f h 0.0f 0.0f| nuclear@0: |0.0f 0.0f Q 1.0f| nuclear@0: [0.0f 0.0f -Q*NearClip 0.0f] nuclear@0: */ nuclear@0: nuclear@0: mat->ResetIdentity(); nuclear@0: mat->m[0][0] = w; nuclear@0: mat->m[1][1] = h; nuclear@0: mat->m[2][2] = Q; nuclear@0: mat->m[3][2] = -Q*NearClip; nuclear@0: mat->m[2][3] = 1.0f; nuclear@0: } nuclear@0: nuclear@0: dword PackVector(const Vector3 &vec, float Height) { nuclear@0: dword r = (dword)(127.0f * vec.x + 128.0f); nuclear@0: dword g = (dword)(127.0f * vec.y + 128.0f); nuclear@0: dword b = (dword)(127.0f * vec.z + 128.0f); nuclear@0: dword a = (dword)(255.0f * Height); nuclear@0: nuclear@0: return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) ); nuclear@0: } nuclear@0: nuclear@0: void NormalMapFromHeightField(Texture *tex) { nuclear@0: nuclear@0: // Lock the texture nuclear@0: D3DLOCKED_RECT d3dlr; nuclear@0: D3DSURFACE_DESC d3dsd; nuclear@0: nuclear@0: int LevelCount = tex->GetLevelCount(); nuclear@0: for(int i=0; iGetLevelDesc(i, &d3dsd); nuclear@0: tex->LockRect(i, &d3dlr, 0, 0); nuclear@0: DWORD* pPixel = (DWORD*)d3dlr.pBits; nuclear@0: nuclear@0: // For each pixel, generate a vector normal that represents the change nuclear@0: // in thea height field at that pixel nuclear@0: for( DWORD j=0; j> 16) / 255.0f; nuclear@0: float fHeight10 = (float)((color10 & 0x00ff0000) >> 16) / 255.0f; nuclear@0: float fHeight01 = (float)((color01 & 0x00ff0000) >> 16) / 255.0f; nuclear@0: nuclear@0: Vector3 vPoint00(i+0.0f, j+0.0f, fHeight00); nuclear@0: Vector3 vPoint10(i+1.0f, j+0.0f, fHeight10); nuclear@0: Vector3 vPoint01(i+0.0f, j+1.0f, fHeight01); nuclear@0: Vector3 v10 = vPoint10 - vPoint00; nuclear@0: Vector3 v01 = vPoint01 - vPoint00; nuclear@0: nuclear@0: Vector3 Normal = v10.CrossProduct(v01); nuclear@0: Normal.Normalize(); nuclear@0: nuclear@0: // Store the normal as an RGBA value in the normal map nuclear@0: *pPixel++ = PackVector(Normal, fHeight00); nuclear@0: } nuclear@0: } nuclear@0: tex->UnlockRect(i); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void UpdateMipmapChain(Texture *tex) { nuclear@0: D3DXFilterTexture(tex, 0, 0, D3DX_FILTER_BOX); nuclear@0: } nuclear@0: nuclear@0: dword AddEdge(Edge *edges, dword EdgeCount, const Edge &newedge) { nuclear@0: // remove internal edges nuclear@0: for(dword i=0; iGetType() == LTDir ? l->GetDirection() : p - l->GetPosition()) nuclear@0: inline Vector3 GetLightDir(const Light *light, const Vector3 &pos, const Matrix4x4 &mat) { nuclear@0: if(light->GetType() == LTDir) { nuclear@0: return light->GetDirection(); nuclear@0: } else { nuclear@0: Vector3 lpos = light->GetPosition(); nuclear@0: lpos.Transform(mat); nuclear@0: return pos - lpos; nuclear@0: } nuclear@0: return Vector3(); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: ////////////////////////////////////////// nuclear@0: // ----==( CreateShadowVolume )==---- nuclear@0: // (Helper Function) nuclear@0: // Creates a graphics context with the specified parameters nuclear@0: // Light version, basic info passed, fills in the rest nuclear@0: ////////////////////////////////////////// nuclear@0: nuclear@0: TriMesh *CreateShadowVolume(const TriMesh &mesh, const Light *light, const Matrix4x4 &MeshXForm, bool WorldCoords) { nuclear@0: nuclear@0: // transform light into object's local coordinate system nuclear@0: //const_cast(light)->Transform(MeshXForm.Inverse()); nuclear@0: Matrix4x4 InvXForm = MeshXForm.Inverse(); nuclear@0: nuclear@0: const Vertex *varray = mesh.GetVertexArray(); nuclear@0: const Triangle *triarray = mesh.GetTriangleArray(); nuclear@0: nuclear@0: dword VertexCount = mesh.GetVertexCount(); nuclear@0: dword TriangleCount = mesh.GetTriangleCount(); nuclear@0: nuclear@0: Edge *edges = new Edge[TriangleCount]; nuclear@0: dword EdgeCount = 0; nuclear@0: nuclear@0: // first find the contour edges nuclear@0: nuclear@0: for(dword i=0; i= 0.0f) { nuclear@0: EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[0], triarray[i].vertices[1])); nuclear@0: EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[1], triarray[i].vertices[2])); nuclear@0: EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[2], triarray[i].vertices[0])); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // now extract the contour edges to build the shadow volume boundrary nuclear@0: const float ExtrudeMagnitude = 100000.0f; nuclear@0: Vertex *ShadowVertices = new Vertex[EdgeCount * 6]; nuclear@0: nuclear@0: for(dword i=0; iSetData(ShadowVertices, 0, EdgeCount * 6, 0); nuclear@0: nuclear@0: delete [] ShadowVertices; nuclear@0: delete [] edges; nuclear@0: nuclear@0: //const_cast(light)->Transform(MeshXForm); // return light to world coordinate system nuclear@0: nuclear@0: return ShadowMesh; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: ///////////// local ////////////// nuclear@0: nuclear@0: ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt) { nuclear@0: switch(fmt) { nuclear@0: case D3DFMT_R8G8B8: return ColorDepth(24, 24, 0); nuclear@0: case D3DFMT_A8R8G8B8: return ColorDepth(32, 24, 8); nuclear@0: case D3DFMT_X8R8G8B8: return ColorDepth(32, 24, 0); nuclear@0: case D3DFMT_R5G6B5: return ColorDepth(16, 16, 0); nuclear@0: case D3DFMT_X1R5G5B5: return ColorDepth(16, 15, 0); nuclear@0: case D3DFMT_A1R5G5B5: return ColorDepth(16, 15, 1); nuclear@0: case D3DFMT_P8: return ColorDepth(8, 8, 0); nuclear@0: default: return ColorDepth(0, 0, 0); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: bool operator ==(const ColorDepth &lhs, const ColorDepth &rhs) { nuclear@0: return (lhs.bpp == rhs.bpp && lhs.colorbits == rhs.colorbits && lhs.alpha == rhs.alpha); nuclear@0: } nuclear@0: nuclear@0: D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha) { nuclear@0: if(cd == ColorDepth(24, 24, 0)) return D3DFMT_R8G8B8; nuclear@0: if(cd == ColorDepth(32, 24, 8)) return noalpha ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8; nuclear@0: if(cd == ColorDepth(32, 24, 0)) return D3DFMT_X8R8G8B8; nuclear@0: if(cd == ColorDepth(16, 16, 0)) return D3DFMT_R5G6B5; nuclear@0: if(cd == ColorDepth(16, 15, 0)) return D3DFMT_X1R5G5B5; nuclear@0: if(cd == ColorDepth(16, 15, 1)) return noalpha ? D3DFMT_X1R5G5B5 : D3DFMT_A1R5G5B5; nuclear@0: if(cd == ColorDepth(8, 8, 0)) return D3DFMT_P8; nuclear@0: return (D3DFORMAT)0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil) { nuclear@0: switch(depthbits) { nuclear@0: case 32: nuclear@0: return (stencil) ? D3DFMT_D24S8 : D3DFMT_D32; nuclear@0: break; nuclear@0: nuclear@0: case 24: nuclear@0: return (stencil) ? D3DFMT_D24S8 : D3DFMT_D24X8; nuclear@0: break; nuclear@0: nuclear@0: case 16: nuclear@0: return (stencil) ? D3DFMT_D15S1 : D3DFMT_D16; nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: return (D3DFORMAT)0; nuclear@0: }