absence_thelab

annotate 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
rev   line source
nuclear@0 1 #include <fstream>
nuclear@0 2 #include <string>
nuclear@0 3 #include <cmath>
nuclear@0 4 #include <cassert>
nuclear@0 5 #include "d3dx8.h"
nuclear@0 6 #include "3dengine.h"
nuclear@0 7 #include "exceptions.h"
nuclear@0 8 #include "3dgeom.h"
nuclear@0 9 #include "lights.h"
nuclear@0 10
nuclear@0 11 // local helper functions
nuclear@0 12 ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt);
nuclear@0 13 D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha=false);
nuclear@0 14 D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil);
nuclear@0 15
nuclear@0 16 ///////////// Graphics Context Member Functions /////////////////
nuclear@0 17
nuclear@0 18 GraphicsContext::GraphicsContext() {
nuclear@0 19 D3DDevice = 0;
nuclear@0 20 BackfaceCulling = true;
nuclear@0 21 }
nuclear@0 22
nuclear@0 23 ///////////////////////////////////
nuclear@0 24 // ----==( SetDefaultStates )==----
nuclear@0 25 // (Public Member Function)
nuclear@0 26 // Sets the default render states
nuclear@0 27 ///////////////////////////////////
nuclear@0 28 void GraphicsContext::SetDefaultStates() {
nuclear@0 29 D3DDevice->SetRenderState(D3DRS_LOCALVIEWER, true);
nuclear@0 30 SetPrimitiveType(TriangleList);
nuclear@0 31 SetBackfaceCulling(true);
nuclear@0 32 SetFrontFace(Clockwise);
nuclear@0 33 SetLighting(true);
nuclear@0 34 SetColorVertex(false);
nuclear@0 35 SetAmbientLight(0.0f);
nuclear@0 36 SetMipMapping(true);
nuclear@0 37 SetTextureFiltering(BilinearFiltering);
nuclear@0 38 SetBillboarding(false);
nuclear@0 39 SetSpecular(true);
nuclear@0 40
nuclear@0 41 Matrix4x4 ProjMat;
nuclear@0 42 CreateProjectionMatrix(&ProjMat, QuarterPi, 1.33333333f, 1.0f, 10000.0f);
nuclear@0 43 SetProjectionMatrix(ProjMat);
nuclear@0 44 }
nuclear@0 45
nuclear@0 46
nuclear@0 47 bool GraphicsContext::CreateVertexBuffer(uint32 VertexCount, UsageFlags usage, VertexBuffer **vb) const {
nuclear@0 48 long hr = D3DDevice->CreateVertexBuffer(VertexCount * sizeof(Vertex), (dword)usage, VertexFormat, D3DPOOL_DEFAULT, vb);
nuclear@0 49 return (hr == D3D_OK);
nuclear@0 50 }
nuclear@0 51
nuclear@0 52 bool GraphicsContext::CreateIndexBuffer(uint32 IndexCount, UsageFlags usage, IndexBuffer **ib) const {
nuclear@0 53 long hr = D3DDevice->CreateIndexBuffer(IndexCount * IndexSize, (dword)usage, IndexFormat, D3DPOOL_DEFAULT, ib);
nuclear@0 54 return (hr == D3D_OK);
nuclear@0 55 }
nuclear@0 56
nuclear@0 57 bool GraphicsContext::CreateSurface(uint32 Width, uint32 Height, Surface **surf) const {
nuclear@0 58 long hr = D3DDevice->CreateImageSurface(Width, Height, ColorFormat, surf);
nuclear@0 59 return (hr == D3D_OK);
nuclear@0 60 }
nuclear@0 61
nuclear@0 62 bool GraphicsContext::CreateDepthStencil(uint32 Width, uint32 Height, Surface **zsurf) const {
nuclear@0 63 long hr = D3DDevice->CreateDepthStencilSurface(Width, Height, ZFormat, (D3DMULTISAMPLE_TYPE)AASamples, zsurf);
nuclear@0 64 return (hr == D3D_OK);
nuclear@0 65 }
nuclear@0 66
nuclear@0 67 void GraphicsContext::Clear(dword color) const {
nuclear@0 68 D3DDevice->Clear(0, 0, D3DCLEAR_TARGET, color, 1.0f, 0);
nuclear@0 69 }
nuclear@0 70
nuclear@0 71 void GraphicsContext::ClearZBuffer(float zval) const {
nuclear@0 72 D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER, 0, zval, 0);
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 void GraphicsContext::ClearStencil(byte sval) const {
nuclear@0 76 D3DDevice->Clear(0, 0, D3DCLEAR_STENCIL, 0, 1.0f, sval);
nuclear@0 77 }
nuclear@0 78
nuclear@0 79 void GraphicsContext::ClearZBufferStencil(float zval, byte sval) const {
nuclear@0 80 D3DDevice->Clear(0, 0, D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, zval, sval);
nuclear@0 81 }
nuclear@0 82
nuclear@0 83 void GraphicsContext::Flip() const {
nuclear@0 84 D3DDevice->Present(0, 0, 0, 0);
nuclear@0 85 }
nuclear@0 86
nuclear@0 87
nuclear@0 88 bool GraphicsContext::Draw(VertexBuffer *vb) {
nuclear@0 89 D3DVERTEXBUFFER_DESC desc;
nuclear@0 90 vb->GetDesc(&desc);
nuclear@0 91 unsigned int verts = desc.Size / sizeof(Vertex);
nuclear@0 92
nuclear@0 93 D3DDevice->SetStreamSource(0, vb, sizeof(Vertex));
nuclear@0 94 long res = D3DDevice->DrawPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts / 3);
nuclear@0 95 D3DDevice->SetStreamSource(0, 0, 0);
nuclear@0 96 return res == D3D_OK;
nuclear@0 97 }
nuclear@0 98
nuclear@0 99 bool GraphicsContext::Draw(Vertex *varray, unsigned int VertexCount) {
nuclear@0 100 long res = D3DDevice->DrawPrimitiveUP((D3DPRIMITIVETYPE)ptype, VertexCount / 3, varray, sizeof(Vertex));
nuclear@0 101 return res == D3D_OK;
nuclear@0 102 }
nuclear@0 103
nuclear@0 104 bool GraphicsContext::Draw(VertexBuffer *vb, IndexBuffer *ib) {
nuclear@0 105 D3DVERTEXBUFFER_DESC vbdesc;
nuclear@0 106 vb->GetDesc(&vbdesc);
nuclear@0 107 unsigned int verts = vbdesc.Size / sizeof(Vertex);
nuclear@0 108
nuclear@0 109 D3DINDEXBUFFER_DESC ibdesc;
nuclear@0 110 ib->GetDesc(&ibdesc);
nuclear@0 111 unsigned int indices = ibdesc.Size / sizeof(Index);
nuclear@0 112
nuclear@0 113 D3DDevice->SetStreamSource(0, vb, sizeof(Vertex));
nuclear@0 114 D3DDevice->SetIndices(ib, 0);
nuclear@0 115 long res = D3DDevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)ptype, 0, verts, 0, indices / 3);
nuclear@0 116 D3DDevice->SetIndices(0, 0);
nuclear@0 117 D3DDevice->SetStreamSource(0, 0, 0);
nuclear@0 118 return res == D3D_OK;
nuclear@0 119 }
nuclear@0 120
nuclear@0 121 bool GraphicsContext::Draw(Vertex *varray, Index *iarray, unsigned int VertexCount, unsigned int IndexCount) {
nuclear@0 122 long res = D3DDevice->DrawIndexedPrimitiveUP((D3DPRIMITIVETYPE)ptype, 0, VertexCount, IndexCount / 3, iarray, IndexFormat, varray, sizeof(Vertex));
nuclear@0 123 return res == D3D_OK;
nuclear@0 124 }
nuclear@0 125
nuclear@0 126 bool GraphicsContext::Draw(Vertex *varray, Triangle *triarray, unsigned int VertexCount, unsigned int TriCount) {
nuclear@0 127 unsigned int IndexCount = TriCount * 3;
nuclear@0 128 Index *iarray = new Index[IndexCount];
nuclear@0 129 for(dword i=0; i<TriCount; i++) {
nuclear@0 130 iarray[i*3] = triarray[i].vertices[0];
nuclear@0 131 iarray[i*3+1] = triarray[i].vertices[1];
nuclear@0 132 iarray[i*3+2] = triarray[i].vertices[2];
nuclear@0 133 }
nuclear@0 134 long res = Draw(varray, iarray, VertexCount, IndexCount);
nuclear@0 135 return res == D3D_OK;
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 ////////////// State Setting Interface ///////////////
nuclear@0 139
nuclear@0 140 void GraphicsContext::SetPrimitiveType(PrimitiveType pt) {
nuclear@0 141 ptype = pt;
nuclear@0 142 }
nuclear@0 143
nuclear@0 144 void GraphicsContext::SetBackfaceCulling(bool enable) {
nuclear@0 145 if(enable) {
nuclear@0 146 D3DDevice->SetRenderState(D3DRS_CULLMODE, CullOrder);
nuclear@0 147 } else {
nuclear@0 148 D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
nuclear@0 149 }
nuclear@0 150 BackfaceCulling = enable;
nuclear@0 151 }
nuclear@0 152
nuclear@0 153 void GraphicsContext::SetFrontFace(FaceOrder order) {
nuclear@0 154 if(order == Clockwise) {
nuclear@0 155 CullOrder = CounterClockwise;
nuclear@0 156 } else {
nuclear@0 157 CullOrder = Clockwise;
nuclear@0 158 }
nuclear@0 159 if(BackfaceCulling) SetBackfaceCulling(BackfaceCulling);
nuclear@0 160 }
nuclear@0 161
nuclear@0 162 void GraphicsContext::SetAutoNormalize(bool enable) {
nuclear@0 163 D3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, enable);
nuclear@0 164 }
nuclear@0 165
nuclear@0 166 void GraphicsContext::SetBillboarding(bool enable) {
nuclear@0 167 BillBoardingEnabled = enable;
nuclear@0 168 if(enable) {
nuclear@0 169
nuclear@0 170 Vector3 pos;
nuclear@0 171 pos.Transform(WorldMat[0]);
nuclear@0 172
nuclear@0 173 Matrix4x4 world;
nuclear@0 174 world.Translate(pos.x, pos.y, pos.z);
nuclear@0 175 Matrix4x4 BillBoardRot;
nuclear@0 176
nuclear@0 177 Vector3 dir = ViewMat.Inverse().GetRowVector(2);
nuclear@0 178 float yangle = dir.x > 0.0f ? -atanf(dir.z / dir.x) + HalfPi : -atanf(dir.z / dir.x) - HalfPi;
nuclear@0 179
nuclear@0 180 BillBoardRot.Rotate(0.0f, yangle, 0.0f);
nuclear@0 181 Vector3 xaxis = VECTOR3_I;
nuclear@0 182 Vector3 normal = -VECTOR3_K;
nuclear@0 183 xaxis.Transform(BillBoardRot);
nuclear@0 184 normal.Transform(BillBoardRot);
nuclear@0 185
nuclear@0 186 // find angle between quad normal and view direction
nuclear@0 187 float xangle = acosf(DotProduct(normal, dir.Normalized()));
nuclear@0 188 BillBoardRot.Rotate(xaxis, xangle);
nuclear@0 189
nuclear@0 190 world = BillBoardRot * world;
nuclear@0 191
nuclear@0 192 D3DDevice->SetTransform(D3DTS_WORLD, &world);
nuclear@0 193 //D3DDevice->SetTransform(D3DTS_VIEW, &BillboardViewMatrix);
nuclear@0 194 } else {
nuclear@0 195 D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat[0]);
nuclear@0 196 //D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat);
nuclear@0 197 }
nuclear@0 198 }
nuclear@0 199
nuclear@0 200 void GraphicsContext::SetColorWrite(bool red, bool green, bool blue, bool alpha) {
nuclear@0 201 dword channels = 0;
nuclear@0 202 if(red) channels |= D3DCOLORWRITEENABLE_RED;
nuclear@0 203 if(green) channels |= D3DCOLORWRITEENABLE_GREEN;
nuclear@0 204 if(blue) channels |= D3DCOLORWRITEENABLE_BLUE;
nuclear@0 205 if(alpha) channels |= D3DCOLORWRITEENABLE_ALPHA;
nuclear@0 206
nuclear@0 207 D3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, channels);
nuclear@0 208 }
nuclear@0 209
nuclear@0 210 // blending states
nuclear@0 211 void GraphicsContext::SetAlphaBlending(bool enable) {
nuclear@0 212 D3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, enable);
nuclear@0 213 }
nuclear@0 214
nuclear@0 215 void GraphicsContext::SetBlendFunc(BlendingFactor src, BlendingFactor dest) {
nuclear@0 216 D3DDevice->SetRenderState(D3DRS_SRCBLEND, src);
nuclear@0 217 D3DDevice->SetRenderState(D3DRS_DESTBLEND, dest);
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 // zbuffer states
nuclear@0 221 void GraphicsContext::SetZBuffering(bool enable) {
nuclear@0 222 D3DDevice->SetRenderState(D3DRS_ZENABLE, enable);
nuclear@0 223 }
nuclear@0 224
nuclear@0 225 void GraphicsContext::SetZWrite(bool enable) {
nuclear@0 226 D3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, enable);
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 void GraphicsContext::SetZFunc(CmpFunc func) {
nuclear@0 230 D3DDevice->SetRenderState(D3DRS_ZFUNC, func);
nuclear@0 231 }
nuclear@0 232
nuclear@0 233 // set stencil buffer states
nuclear@0 234 void GraphicsContext::SetStencilBuffering(bool enable) {
nuclear@0 235 D3DDevice->SetRenderState(D3DRS_STENCILENABLE, enable);
nuclear@0 236 }
nuclear@0 237
nuclear@0 238 void GraphicsContext::SetStencilPassOp(StencilOp sop) {
nuclear@0 239 D3DDevice->SetRenderState(D3DRS_STENCILPASS, sop);
nuclear@0 240 }
nuclear@0 241
nuclear@0 242 void GraphicsContext::SetStencilFailOp(StencilOp sop) {
nuclear@0 243 D3DDevice->SetRenderState(D3DRS_STENCILFAIL, sop);
nuclear@0 244 }
nuclear@0 245
nuclear@0 246 void GraphicsContext::SetStencilPassZFailOp(StencilOp sop) {
nuclear@0 247 D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, sop);
nuclear@0 248 }
nuclear@0 249
nuclear@0 250 void GraphicsContext::SetStencilOp(StencilOp Fail, StencilOp StencilPassZFail, StencilOp Pass) {
nuclear@0 251 D3DDevice->SetRenderState(D3DRS_STENCILPASS, Pass);
nuclear@0 252 D3DDevice->SetRenderState(D3DRS_STENCILFAIL, Fail);
nuclear@0 253 D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, StencilPassZFail);
nuclear@0 254 }
nuclear@0 255
nuclear@0 256 void GraphicsContext::SetStencilFunc(CmpFunc func) {
nuclear@0 257 D3DDevice->SetRenderState(D3DRS_STENCILFUNC, func);
nuclear@0 258 }
nuclear@0 259
nuclear@0 260 void GraphicsContext::SetStencilReference(dword value) {
nuclear@0 261 D3DDevice->SetRenderState(D3DRS_STENCILREF, value);
nuclear@0 262 }
nuclear@0 263
nuclear@0 264 // texture & material states
nuclear@0 265
nuclear@0 266 void GraphicsContext::SetTextureFactor(dword factor) {
nuclear@0 267 D3DDevice->SetRenderState(D3DRS_TEXTUREFACTOR, factor);
nuclear@0 268 }
nuclear@0 269
nuclear@0 270 void GraphicsContext::SetTextureFiltering(TextureFilteringType texfilter, int TextureStage) {
nuclear@0 271 dword TexFilter, MipFilter;
nuclear@0 272
nuclear@0 273 switch(texfilter) {
nuclear@0 274 case PointSampling:
nuclear@0 275 TexFilter = MipFilter = D3DTEXF_POINT;
nuclear@0 276 break;
nuclear@0 277
nuclear@0 278 case BilinearFiltering:
nuclear@0 279 TexFilter = D3DTEXF_LINEAR;
nuclear@0 280 MipFilter = D3DTEXF_POINT;
nuclear@0 281 break;
nuclear@0 282
nuclear@0 283 case TrilinearFiltering:
nuclear@0 284 TexFilter = MipFilter = D3DTEXF_LINEAR;
nuclear@0 285 break;
nuclear@0 286
nuclear@0 287 case AnisotropicFiltering:
nuclear@0 288 TexFilter = D3DTEXF_ANISOTROPIC;
nuclear@0 289 MipFilter = D3DTEXF_LINEAR;
nuclear@0 290 break;
nuclear@0 291
nuclear@0 292 default: break;
nuclear@0 293 }
nuclear@0 294
nuclear@0 295 this->MipFilter = MipFilter;
nuclear@0 296
nuclear@0 297 if(!MipMapEnabled) MipFilter = D3DTEXF_NONE;
nuclear@0 298
nuclear@0 299 if(TextureStage == 0xa11) {
nuclear@0 300 for(int i=0; i<MaxTextureStages; i++) {
nuclear@0 301 D3DDevice->SetTextureStageState(i, D3DTSS_MINFILTER, TexFilter);
nuclear@0 302 D3DDevice->SetTextureStageState(i, D3DTSS_MAGFILTER, TexFilter);
nuclear@0 303 D3DDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, MipFilter);
nuclear@0 304 }
nuclear@0 305 } else {
nuclear@0 306 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MINFILTER, TexFilter);
nuclear@0 307 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MAGFILTER, TexFilter);
nuclear@0 308 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, MipFilter);
nuclear@0 309 }
nuclear@0 310 }
nuclear@0 311
nuclear@0 312 void GraphicsContext::SetTextureAddressing(TextureAddressing uaddr, TextureAddressing vaddr, int TextureStage) {
nuclear@0 313 if(TextureStage == 0xa11) {
nuclear@0 314 for(int i=0; i<MaxTextureStages; i++) {
nuclear@0 315 D3DDevice->SetTextureStageState(i, D3DTSS_ADDRESSU, uaddr);
nuclear@0 316 D3DDevice->SetTextureStageState(i, D3DTSS_ADDRESSV, vaddr);
nuclear@0 317 }
nuclear@0 318 } else {
nuclear@0 319 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSU, uaddr);
nuclear@0 320 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_ADDRESSV, vaddr);
nuclear@0 321 }
nuclear@0 322 }
nuclear@0 323
nuclear@0 324 void GraphicsContext::SetTextureBorderColor(dword color, int TextureStage) {
nuclear@0 325 if(TextureStage == 0xa11) {
nuclear@0 326 for(int i=0; i<MaxTextureStages; i++) {
nuclear@0 327 D3DDevice->SetTextureStageState(i, D3DTSS_BORDERCOLOR, color);
nuclear@0 328 }
nuclear@0 329 } else {
nuclear@0 330 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_BORDERCOLOR, color);
nuclear@0 331 }
nuclear@0 332 }
nuclear@0 333
nuclear@0 334 void GraphicsContext::SetTexture(int index, Texture *tex) {
nuclear@0 335 D3DDevice->SetTexture(index, tex);
nuclear@0 336 }
nuclear@0 337
nuclear@0 338 void GraphicsContext::SetMipMapping(bool enable, int TextureStage) {
nuclear@0 339 MipMapEnabled = enable;
nuclear@0 340 dword mip = (enable ? MipFilter : D3DTEXF_NONE);
nuclear@0 341
nuclear@0 342 if(TextureStage == 0xa11) {
nuclear@0 343 for(int i=0; i<MaxTextureStages; i++) {
nuclear@0 344 D3DDevice->SetTextureStageState(i, D3DTSS_MIPFILTER, mip);
nuclear@0 345 }
nuclear@0 346 } else {
nuclear@0 347 D3DDevice->SetTextureStageState(TextureStage, D3DTSS_MIPFILTER, mip);
nuclear@0 348 }
nuclear@0 349 }
nuclear@0 350
nuclear@0 351 void GraphicsContext::SetMaterial(const Material &mat) {
nuclear@0 352 D3DDevice->SetMaterial(&mat);
nuclear@0 353 }
nuclear@0 354
nuclear@0 355 static unsigned long TLVertexFVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;
nuclear@0 356
nuclear@0 357 struct TLVertex {
nuclear@0 358 Vector3 pos;
nuclear@0 359 float rhw;
nuclear@0 360 unsigned long color;
nuclear@0 361 TexCoord tex;
nuclear@0 362
nuclear@0 363 TLVertex() {
nuclear@0 364 pos = Vector3(0.0f, 0.0f, 0.0f);
nuclear@0 365 color = 0xffffffff;
nuclear@0 366 tex.u = tex.v = 0.0f;
nuclear@0 367 rhw = pos.z;
nuclear@0 368 }
nuclear@0 369
nuclear@0 370 TLVertex(const Vector3 &pos, const Color &col, float u=0.0f, float v=0.0f) {
nuclear@0 371 this->pos = pos;
nuclear@0 372 rhw = pos.z;
nuclear@0 373 color = col.GetPacked32();
nuclear@0 374 tex.u = u;
nuclear@0 375 tex.v = v;
nuclear@0 376 }
nuclear@0 377 };
nuclear@0 378
nuclear@0 379 void GraphicsContext::BlitTexture(const Texture *texture, RECT *rect, const Color &col) {
nuclear@0 380 bool norect = rect ? false : true;
nuclear@0 381 if(norect) {
nuclear@0 382 rect = new RECT;
nuclear@0 383 rect->left = rect->top = 0;
nuclear@0 384 rect->right = ContextParams.x;
nuclear@0 385 rect->bottom = ContextParams.y;
nuclear@0 386 }
nuclear@0 387
nuclear@0 388 SetVertexProgram(TLVertexFVF);
nuclear@0 389
nuclear@0 390 TLVertex tlverts[4];
nuclear@0 391 tlverts[0] = TLVertex(Vector3((float)rect->right, (float)rect->top, 1.0f), col, 1.0f, 0.0f);
nuclear@0 392 tlverts[1] = TLVertex(Vector3((float)rect->right, (float)rect->bottom, 1.0f), col, 1.0f, 1.0f);
nuclear@0 393 tlverts[2] = TLVertex(Vector3((float)rect->left, (float)rect->top, 1.0f), col, 0.0f, 0.0f);
nuclear@0 394 tlverts[3] = TLVertex(Vector3((float)rect->left, (float)rect->bottom, 1.0f), col, 0.0f, 1.0f);
nuclear@0 395
nuclear@0 396 EnableTextureStage(0);
nuclear@0 397 DisableTextureStage(1);
nuclear@0 398 SetTexture(0, const_cast<Texture*>(texture));
nuclear@0 399
nuclear@0 400 SetZBuffering(false);
nuclear@0 401 D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, tlverts, sizeof(TLVertex));
nuclear@0 402 SetZBuffering(true);
nuclear@0 403
nuclear@0 404 SetTexture(0, 0);
nuclear@0 405
nuclear@0 406 SetVertexProgram(VertexFormat);
nuclear@0 407
nuclear@0 408 if(norect) {
nuclear@0 409 delete rect;
nuclear@0 410 }
nuclear@0 411 }
nuclear@0 412
nuclear@0 413 // multitexturing interface
nuclear@0 414 void GraphicsContext::EnableTextureStage(int stage) {
nuclear@0 415 SetTextureStageColor(stage, TexBlendModulate, TexArgTexture, TexArgCurrent);
nuclear@0 416 }
nuclear@0 417
nuclear@0 418 void GraphicsContext::DisableTextureStage(int stage) {
nuclear@0 419 D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
nuclear@0 420 }
nuclear@0 421
nuclear@0 422 void GraphicsContext::SetTextureStageColor(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) {
nuclear@0 423 D3DDevice->SetTextureStageState(stage, D3DTSS_COLOROP, op);
nuclear@0 424 D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG1, arg1);
nuclear@0 425 D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG2, arg2);
nuclear@0 426 if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_COLORARG0, arg3);
nuclear@0 427 }
nuclear@0 428
nuclear@0 429 void GraphicsContext::SetTextureStageAlpha(int stage, TextureBlendFunction op, TextureBlendArgument arg1, TextureBlendArgument arg2, TextureBlendArgument arg3) {
nuclear@0 430 D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAOP, op);
nuclear@0 431 D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG1, arg1);
nuclear@0 432 D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG2, arg2);
nuclear@0 433 if(arg3) D3DDevice->SetTextureStageState(stage, D3DTSS_ALPHAARG0, arg3);
nuclear@0 434 }
nuclear@0 435
nuclear@0 436 void GraphicsContext::SetTextureCoordIndex(int stage, int index) {
nuclear@0 437 D3DDevice->SetTextureStageState(stage, D3DTSS_TEXCOORDINDEX, index);
nuclear@0 438 }
nuclear@0 439
nuclear@0 440 void GraphicsContext::SetTextureTransformState(int stage, TexTransformState TexXForm) {
nuclear@0 441 D3DDevice->SetTextureStageState(stage, D3DTSS_TEXTURETRANSFORMFLAGS, TexXForm);
nuclear@0 442 }
nuclear@0 443
nuclear@0 444 // programmable pipeline interface
nuclear@0 445 void GraphicsContext::SetVertexProgram(dword vs) {
nuclear@0 446 D3DDevice->SetVertexShader(vs);
nuclear@0 447 }
nuclear@0 448
nuclear@0 449 void GraphicsContext::SetPixelProgram(dword ps) {
nuclear@0 450 D3DDevice->SetPixelShader(ps);
nuclear@0 451 }
nuclear@0 452
nuclear@0 453 dword GraphicsContext::CreateVertexProgram(const char *fname) {
nuclear@0 454
nuclear@0 455 // vertex format declaration
nuclear@0 456 dword VertDecl[] = {
nuclear@0 457 D3DVSD_STREAM(0),
nuclear@0 458 D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
nuclear@0 459 D3DVSD_REG(D3DVSDE_BLENDWEIGHT, D3DVSDT_FLOAT1),
nuclear@0 460 D3DVSD_REG(D3DVSDE_BLENDINDICES, D3DVSDT_UBYTE4),
nuclear@0 461 D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
nuclear@0 462 D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR),
nuclear@0 463 D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
nuclear@0 464 D3DVSD_REG(D3DVSDE_TEXCOORD1, D3DVSDT_FLOAT2),
nuclear@0 465 D3DVSD_REG(D3DVSDE_TEXCOORD2, D3DVSDT_FLOAT2),
nuclear@0 466 D3DVSD_REG(D3DVSDE_TEXCOORD3, D3DVSDT_FLOAT2),
nuclear@0 467 D3DVSD_END()
nuclear@0 468 };
nuclear@0 469
nuclear@0 470
nuclear@0 471 ID3DXBuffer *code, *errors;
nuclear@0 472 if(D3DXAssembleShaderFromFile(fname, 0, 0, &code, &errors) != D3D_OK) {
nuclear@0 473 return 0xffffffff;
nuclear@0 474 }
nuclear@0 475
nuclear@0 476 dword vprog;
nuclear@0 477 if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, 0) != D3D_OK) {
nuclear@0 478 // could not create hardware vertex shader, try driver emulation...
nuclear@0 479 if(D3DDevice->CreateVertexShader(VertDecl, (dword*)code->GetBufferPointer(), &vprog, D3DUSAGE_SOFTWAREPROCESSING) != D3D_OK) {
nuclear@0 480 throw EngineGeneralException("The system lacks required programmable vertex processing unit support");
nuclear@0 481 }
nuclear@0 482 }
nuclear@0 483
nuclear@0 484 return vprog;
nuclear@0 485 }
nuclear@0 486
nuclear@0 487 void GraphicsContext::DestroyVertexProgram(dword vprog) {
nuclear@0 488 D3DDevice->DeleteVertexShader(vprog);
nuclear@0 489 }
nuclear@0 490
nuclear@0 491 void GraphicsContext::SetVertexProgramConstant(dword creg, float val) {
nuclear@0 492 float block[4] = {val, 0.0f, 0.0f, 1.0f};
nuclear@0 493 D3DDevice->SetVertexShaderConstant(creg, &block, 1);
nuclear@0 494 }
nuclear@0 495
nuclear@0 496 void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector3 &val) {
nuclear@0 497 Vector4 vec(val);
nuclear@0 498 D3DDevice->SetVertexShaderConstant(creg, &vec, 1);
nuclear@0 499 }
nuclear@0 500
nuclear@0 501 void GraphicsContext::SetVertexProgramConstant(dword creg, const Vector4 &val) {
nuclear@0 502 D3DDevice->SetVertexShaderConstant(creg, &val, 1);
nuclear@0 503 }
nuclear@0 504
nuclear@0 505 void GraphicsContext::SetVertexProgramConstant(dword creg, const Color &val) {
nuclear@0 506 D3DDevice->SetVertexShaderConstant(creg, &val, 1);
nuclear@0 507 }
nuclear@0 508
nuclear@0 509 void GraphicsContext::SetVertexProgramConstant(dword creg, const Matrix4x4 &val) {
nuclear@0 510 D3DDevice->SetVertexShaderConstant(creg, &val, 4);
nuclear@0 511 }
nuclear@0 512
nuclear@0 513 void GraphicsContext::SetVertexProgramConstant(dword creg, const void *data, dword size) {
nuclear@0 514 D3DDevice->SetVertexShaderConstant(creg, data, size);
nuclear@0 515 }
nuclear@0 516
nuclear@0 517
nuclear@0 518 // Lighting states
nuclear@0 519 void GraphicsContext::SetLighting(bool enable) {
nuclear@0 520 D3DDevice->SetRenderState(D3DRS_LIGHTING, enable);
nuclear@0 521 }
nuclear@0 522
nuclear@0 523 void GraphicsContext::SetColorVertex(bool enable) {
nuclear@0 524 D3DDevice->SetRenderState(D3DRS_COLORVERTEX, enable);
nuclear@0 525 }
nuclear@0 526
nuclear@0 527 void GraphicsContext::SetAmbientLight(Color AmbientColor) {
nuclear@0 528 D3DDevice->SetRenderState(D3DRS_AMBIENT, AmbientColor.GetPacked32());
nuclear@0 529 }
nuclear@0 530
nuclear@0 531 void GraphicsContext::SetShadingMode(ShadeMode mode) {
nuclear@0 532 D3DDevice->SetRenderState(D3DRS_SHADEMODE, mode);
nuclear@0 533 }
nuclear@0 534
nuclear@0 535 void GraphicsContext::SetSpecular(bool enable) {
nuclear@0 536 D3DDevice->SetRenderState(D3DRS_SPECULARENABLE, enable);
nuclear@0 537 }
nuclear@0 538
nuclear@0 539 // transformation states
nuclear@0 540 void GraphicsContext::SetWorldMatrix(const Matrix4x4 &WorldMat, unsigned int BlendIndex) {
nuclear@0 541 assert(BlendIndex < 256);
nuclear@0 542 this->WorldMat[BlendIndex] = WorldMat;
nuclear@0 543 if(!BillBoardingEnabled) {
nuclear@0 544 D3DDevice->SetTransform(D3DTS_WORLDMATRIX(BlendIndex), &WorldMat);
nuclear@0 545 } else {
nuclear@0 546 SetBillboarding(true);
nuclear@0 547 }
nuclear@0 548 }
nuclear@0 549
nuclear@0 550 void GraphicsContext::SetViewMatrix(const Matrix4x4 &ViewMat) {
nuclear@0 551 this->ViewMat = ViewMat;
nuclear@0 552 if(!BillBoardingEnabled) {
nuclear@0 553 D3DDevice->SetTransform(D3DTS_VIEW, &ViewMat);
nuclear@0 554 } else {
nuclear@0 555 SetBillboarding(true);
nuclear@0 556 }
nuclear@0 557 }
nuclear@0 558
nuclear@0 559 void GraphicsContext::SetProjectionMatrix(const Matrix4x4 &ProjMat) {
nuclear@0 560 this->ProjMat = ProjMat;
nuclear@0 561 D3DDevice->SetTransform(D3DTS_PROJECTION, &ProjMat);
nuclear@0 562 }
nuclear@0 563
nuclear@0 564 void GraphicsContext::SetTextureMatrix(const Matrix4x4 &TexMat, unsigned int TextureStage) {
nuclear@0 565 assert(TextureStage < 8);
nuclear@0 566 this->TexMat[TextureStage] = TexMat;
nuclear@0 567 D3DDevice->SetTransform((D3DTRANSFORMSTATETYPE)((int)D3DTS_TEXTURE0 + TextureStage), &TexMat);
nuclear@0 568 }
nuclear@0 569
nuclear@0 570 void GraphicsContext::SetViewport(unsigned int x, unsigned int y, unsigned int xsize, unsigned int ysize, float MinZ, float MaxZ) {
nuclear@0 571 D3DVIEWPORT8 viewport;
nuclear@0 572 viewport.X = x;
nuclear@0 573 viewport.Y = y;
nuclear@0 574 viewport.Width = xsize;
nuclear@0 575 viewport.Height = ysize;
nuclear@0 576 viewport.MinZ = MinZ;
nuclear@0 577 viewport.MaxZ = MaxZ;
nuclear@0 578
nuclear@0 579 D3DDevice->SetViewport(&viewport);
nuclear@0 580 }
nuclear@0 581
nuclear@0 582
nuclear@0 583 const Matrix4x4 &GraphicsContext::GetWorldMatrix(unsigned int BlendIndex) {
nuclear@0 584 assert(BlendIndex < 256);
nuclear@0 585 return WorldMat[BlendIndex];
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 const Matrix4x4 &GraphicsContext::GetViewMatrix() {
nuclear@0 589 return ViewMat;
nuclear@0 590 }
nuclear@0 591
nuclear@0 592 const Matrix4x4 &GraphicsContext::GetProjectionMatrix() {
nuclear@0 593 return ProjMat;
nuclear@0 594 }
nuclear@0 595
nuclear@0 596 const Matrix4x4 &GraphicsContext::GetTextureMatrix(unsigned int TextureStage) {
nuclear@0 597 assert(TextureStage < 8);
nuclear@0 598 return TexMat[TextureStage];
nuclear@0 599 }
nuclear@0 600
nuclear@0 601
nuclear@0 602 // render target
nuclear@0 603 void GraphicsContext::ResetRenderTarget() {
nuclear@0 604 D3DDevice->SetRenderTarget(MainRenderTarget.ColorSurface, MainRenderTarget.DepthStencilSurface);
nuclear@0 605 }
nuclear@0 606
nuclear@0 607 void GraphicsContext::SetRenderTarget(RenderTarget &rtarg) {
nuclear@0 608 D3DDevice->SetRenderTarget(rtarg.ColorSurface, rtarg.DepthStencilSurface);
nuclear@0 609 }
nuclear@0 610
nuclear@0 611 void GraphicsContext::SetRenderTarget(Texture *rtarg, Texture *ztarg) {
nuclear@0 612 Surface *rendsurf, *zsurf = 0;
nuclear@0 613 rtarg->GetSurfaceLevel(0, &rendsurf);
nuclear@0 614 if(ztarg) ztarg->GetSurfaceLevel(0, &zsurf);
nuclear@0 615
nuclear@0 616 D3DDevice->SetRenderTarget(rendsurf, zsurf);
nuclear@0 617 }
nuclear@0 618
nuclear@0 619 void GraphicsContext::SetRenderTarget(Texture *rtarg, Surface *ztarg) {
nuclear@0 620 Surface *rendsurf;
nuclear@0 621 rtarg->GetSurfaceLevel(0, &rendsurf);
nuclear@0 622
nuclear@0 623 D3DDevice->SetRenderTarget(rendsurf, ztarg);
nuclear@0 624 }
nuclear@0 625
nuclear@0 626
nuclear@0 627 ////////////////////////////////////////////////////
nuclear@0 628 //////////// Engine3D Member Functions /////////////
nuclear@0 629 ////////////////////////////////////////////////////
nuclear@0 630
nuclear@0 631 Engine3D::Engine3D() {
nuclear@0 632
nuclear@0 633 if(!(d3d = Direct3DCreate8(D3D_SDK_VERSION))) {
nuclear@0 634 // actually this will never occur, if directx8 is not available in the system then
nuclear@0 635 // the OS loader will hit the problem first when it'll try to load d3d8.dll that is
nuclear@0 636 // linked through d3d8.lib, and complain for missing imports
nuclear@0 637 throw EngineInitException("DirectX 8.1 is required to run this program");
nuclear@0 638 }
nuclear@0 639
nuclear@0 640 RetrieveAdapterInfo();
nuclear@0 641 }
nuclear@0 642
nuclear@0 643 Engine3D::~Engine3D() {
nuclear@0 644
nuclear@0 645 GraphicsContexts.erase(GraphicsContexts.begin(), GraphicsContexts.end());
nuclear@0 646
nuclear@0 647 if(d3d) {
nuclear@0 648 d3d->Release();
nuclear@0 649 d3d = 0;
nuclear@0 650 }
nuclear@0 651 }
nuclear@0 652
nuclear@0 653
nuclear@0 654 ////////////////////////////////////
nuclear@0 655 // ----==( RetrieveAdapterInfo )==----
nuclear@0 656 // (Private Member Function)
nuclear@0 657 // Gets the list of adapters on the system and additional
nuclear@0 658 // information for each adapter including its capabilities
nuclear@0 659 ////////////////////////////////////
nuclear@0 660 void Engine3D::RetrieveAdapterInfo() {
nuclear@0 661
nuclear@0 662 // retrieve adapter list
nuclear@0 663 AdapterCount = d3d->GetAdapterCount();
nuclear@0 664 adapters = new Adapter[AdapterCount];
nuclear@0 665
nuclear@0 666 for(unsigned int i=0; i<AdapterCount; i++) {
nuclear@0 667
nuclear@0 668 // get adapter identifier and driver information
nuclear@0 669 D3DADAPTER_IDENTIFIER8 AdapterIdentifier;
nuclear@0 670 d3d->GetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &AdapterIdentifier);
nuclear@0 671 adapters[i].Description = new char[strlen(AdapterIdentifier.Description)+1];
nuclear@0 672 strcpy(adapters[i].Description, AdapterIdentifier.Description);
nuclear@0 673 adapters[i].Driver = new char[strlen(AdapterIdentifier.Driver)+1];
nuclear@0 674 strcpy(adapters[i].Driver, AdapterIdentifier.Driver);
nuclear@0 675
nuclear@0 676 adapters[i].DeviceGUID = AdapterIdentifier.DeviceIdentifier;
nuclear@0 677 adapters[i].DeviceID = AdapterIdentifier.DeviceId;
nuclear@0 678 adapters[i].DriverVersion = AdapterIdentifier.DriverVersion.QuadPart;
nuclear@0 679 adapters[i].Revision = AdapterIdentifier.Revision;
nuclear@0 680 adapters[i].SubSysID = AdapterIdentifier.SubSysId;
nuclear@0 681 adapters[i].VentorID = AdapterIdentifier.VendorId;
nuclear@0 682
nuclear@0 683 // get a list of display modes for this adapter
nuclear@0 684 LinkedList<DisplayMode> dmlist;
nuclear@0 685 adapters[i].ModeCount = d3d->GetAdapterModeCount(i);
nuclear@0 686 for(unsigned int j=0; j<adapters[i].ModeCount; j++) {
nuclear@0 687 D3DDISPLAYMODE d3dmode;
nuclear@0 688 DisplayMode mode;
nuclear@0 689 d3d->EnumAdapterModes(i, j, &d3dmode);
nuclear@0 690 mode.XRes = d3dmode.Width;
nuclear@0 691 mode.YRes = d3dmode.Height;
nuclear@0 692 mode.RefreshRate = d3dmode.RefreshRate;
nuclear@0 693 mode.ColorFormat = GetColorDepthFromPixelFormat(d3dmode.Format);
nuclear@0 694
nuclear@0 695 // check if this mode is supported from the HAL device
nuclear@0 696 D3DFORMAT dispfmt = GetPixelFormatFromColorDepth(mode.ColorFormat, true);
nuclear@0 697 if(d3d->CheckDeviceType(i, D3DDEVTYPE_HAL, dispfmt, d3dmode.Format, false) == D3D_OK) {
nuclear@0 698 dmlist.PushBack(mode);
nuclear@0 699 }
nuclear@0 700 }
nuclear@0 701 adapters[i].ModeCount = dmlist.Size(); // count of the modes that are supported through HW
nuclear@0 702 adapters[i].Modes = new DisplayMode[adapters[i].ModeCount];
nuclear@0 703 ListNode<DisplayMode> *iter = dmlist.Begin();
nuclear@0 704 int j = 0;
nuclear@0 705 while(iter) {
nuclear@0 706 adapters[i].Modes[j++] = iter->data;
nuclear@0 707 iter = iter->next;
nuclear@0 708 }
nuclear@0 709
nuclear@0 710 // get the device capabilities
nuclear@0 711 d3d->GetDeviceCaps(i, D3DDEVTYPE_HAL, &adapters[i].Capabilities);
nuclear@0 712 int vsver_major = D3DSHADER_VERSION_MAJOR(adapters[i].Capabilities.VertexShaderVersion);
nuclear@0 713 int vsver_minor = D3DSHADER_VERSION_MINOR(adapters[i].Capabilities.VertexShaderVersion);
nuclear@0 714 }
nuclear@0 715 }
nuclear@0 716
nuclear@0 717 ////////////////////////////////////
nuclear@0 718 // ----==( CreateModesList )==----
nuclear@0 719 // (Private Member Function)
nuclear@0 720 // Creates a linked list of the available modes
nuclear@0 721 // of a single adapter for further processing
nuclear@0 722 ////////////////////////////////////
nuclear@0 723 LinkedList<DisplayMode> *Engine3D::CreateModesList(unsigned int AdapterID) const {
nuclear@0 724
nuclear@0 725 if(AdapterID >= AdapterCount) return 0;
nuclear@0 726
nuclear@0 727 LinkedList<DisplayMode> *newlist = new LinkedList<DisplayMode>;
nuclear@0 728 for(unsigned int i=0; i<adapters[AdapterID].ModeCount; i++) {
nuclear@0 729 newlist->PushBack(adapters[AdapterID].Modes[i]);
nuclear@0 730 }
nuclear@0 731 return newlist;
nuclear@0 732 }
nuclear@0 733
nuclear@0 734 ////////////////////////////////////
nuclear@0 735 // ----==( NarrowModesList )==----
nuclear@0 736 // (Private Member Function)
nuclear@0 737 // Narrows down the list of available modes
nuclear@0 738 // to those that have the requested item
nuclear@0 739 ////////////////////////////////////
nuclear@0 740 void Engine3D::NarrowModesList(LinkedList<DisplayMode> *list, DisplayModeItem item, long value, long value2) const {
nuclear@0 741
nuclear@0 742 ListNode<DisplayMode> *iter = list->Begin();
nuclear@0 743 while(iter) {
nuclear@0 744 switch(item) {
nuclear@0 745 case ModeItemSize:
nuclear@0 746 if(iter->data.XRes != value || iter->data.YRes != value2) {
nuclear@0 747 iter = list->Erase(iter);
nuclear@0 748 } else {
nuclear@0 749 if(iter) iter = iter->next;
nuclear@0 750 }
nuclear@0 751 break;
nuclear@0 752
nuclear@0 753 case ModeItemBpp:
nuclear@0 754 if(iter->data.ColorFormat.bpp != value) {
nuclear@0 755 iter = list->Erase(iter);
nuclear@0 756 } else {
nuclear@0 757 if(iter) iter = iter->next;
nuclear@0 758 }
nuclear@0 759 break;
nuclear@0 760
nuclear@0 761 case ModeItemAlpha:
nuclear@0 762 if(!iter->data.ColorFormat.alpha && value) {
nuclear@0 763 iter = list->Erase(iter);
nuclear@0 764 } else {
nuclear@0 765 if(iter) iter = iter->next;
nuclear@0 766 }
nuclear@0 767 break;
nuclear@0 768
nuclear@0 769 case ModeItemRefresh:
nuclear@0 770 if(iter->data.RefreshRate != value) {
nuclear@0 771 iter = list->Erase(iter);
nuclear@0 772 } else {
nuclear@0 773 if(iter) iter = iter->next;
nuclear@0 774 }
nuclear@0 775 break;
nuclear@0 776
nuclear@0 777 default: break;
nuclear@0 778 }
nuclear@0 779 }
nuclear@0 780 }
nuclear@0 781
nuclear@0 782 ///////////////////////////////////
nuclear@0 783 // ----==( ChooseBestMode )==----
nuclear@0 784 // (Private Member Function)
nuclear@0 785 // given a (ideally) narrowed down modes list
nuclear@0 786 // choose the best possible among them
nuclear@0 787 ///////////////////////////////////
nuclear@0 788 DisplayMode Engine3D::ChooseBestMode(LinkedList<DisplayMode> *modes) const {
nuclear@0 789
nuclear@0 790 DisplayMode dmode;
nuclear@0 791 memset(&dmode, 0, sizeof(DisplayMode));
nuclear@0 792
nuclear@0 793 if(!modes || !modes->Size()) return dmode;
nuclear@0 794
nuclear@0 795 // find the highest resolution and get only the modes with that resolution
nuclear@0 796 ListNode<DisplayMode> *iter = modes->Begin();
nuclear@0 797 unsigned int maxx = 0, maxy = 0;
nuclear@0 798 while(iter) {
nuclear@0 799 if(iter->data.XRes > maxx) maxx = iter->data.XRes;
nuclear@0 800 if(iter->data.YRes > maxy) maxy = iter->data.YRes;
nuclear@0 801 iter = iter->next;
nuclear@0 802 }
nuclear@0 803 NarrowModesList(modes, ModeItemSize, maxx, maxy);
nuclear@0 804
nuclear@0 805 // find the modes with alpha if any
nuclear@0 806 iter = modes->Begin();
nuclear@0 807 bool AnyWithAlpha = false;
nuclear@0 808 while(iter) {
nuclear@0 809 if(iter->data.ColorFormat.alpha) {
nuclear@0 810 AnyWithAlpha = true;
nuclear@0 811 break;
nuclear@0 812 }
nuclear@0 813 iter = iter->next;
nuclear@0 814 }
nuclear@0 815 if(AnyWithAlpha) NarrowModesList(modes, ModeItemAlpha, 1);
nuclear@0 816
nuclear@0 817 // find the modes with the highest bpp
nuclear@0 818 iter = modes->Begin();
nuclear@0 819 int maxbpp = 0;
nuclear@0 820 while(iter) {
nuclear@0 821 if(iter->data.ColorFormat.bpp > maxbpp) maxbpp = iter->data.ColorFormat.bpp;
nuclear@0 822 iter = iter->next;
nuclear@0 823 }
nuclear@0 824 NarrowModesList(modes, ModeItemBpp, maxbpp);
nuclear@0 825
nuclear@0 826 // find the modes with the highest refresh rate
nuclear@0 827 iter = modes->Begin();
nuclear@0 828 unsigned int maxrefresh = 0;
nuclear@0 829 while(iter) {
nuclear@0 830 if(iter->data.RefreshRate > maxrefresh) maxrefresh = iter->data.RefreshRate;
nuclear@0 831 iter = iter->next;
nuclear@0 832 }
nuclear@0 833 NarrowModesList(modes, ModeItemRefresh, maxrefresh);
nuclear@0 834
nuclear@0 835 // if there is more than one mode left, then there is a problem :)
nuclear@0 836 assert(modes->Size() == 1);
nuclear@0 837
nuclear@0 838 dmode = modes->Begin()->data;
nuclear@0 839 return dmode;
nuclear@0 840 }
nuclear@0 841
nuclear@0 842 //////////////////////////////////////////
nuclear@0 843 // ----==( CreateGraphicsContext )==----
nuclear@0 844 // (Public Member Function)
nuclear@0 845 // Creates a graphics context with the specified parameters
nuclear@0 846 //////////////////////////////////////////
nuclear@0 847 GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, unsigned int AdapterID, ContextInitParameters *GCParams) {
nuclear@0 848
nuclear@0 849 if(AdapterID >= AdapterCount) return 0;
nuclear@0 850
nuclear@0 851 // check adapter's Transformation & Lighting capability
nuclear@0 852 bool hwtnl = (bool)(adapters[AdapterID].Capabilities.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT);
nuclear@0 853 if(!(GCParams->DontCareFlags & GCPDONTCARE_TNL)) { // bit not set, we want specific TnL mode
nuclear@0 854 if(hwtnl != GCParams->HardwareTnL && !hwtnl) return 0; // we asked for hw tnl and is not available
nuclear@0 855 // else either we asked for sw and found hw so we continue with our initial sw setting
nuclear@0 856 // or we found exactly what we asked, so we still continue with our choice
nuclear@0 857 } else {
nuclear@0 858 GCParams->HardwareTnL = hwtnl; // if we don't care use what we have available
nuclear@0 859 }
nuclear@0 860
nuclear@0 861 // decide which mode to use
nuclear@0 862 LinkedList<DisplayMode> *modes = CreateModesList(AdapterID);
nuclear@0 863 NarrowModesList(modes, ModeItemSize, GCParams->x, GCParams->y);
nuclear@0 864
nuclear@0 865 if(!(GCParams->DontCareFlags & GCPDONTCARE_BPP)) { // we want specific bpp
nuclear@0 866 NarrowModesList(modes, ModeItemBpp, GCParams->bpp);
nuclear@0 867 }
nuclear@0 868
nuclear@0 869 if(!(GCParams->DontCareFlags & GCPDONTCARE_ALPHA)) { // alpha setting exactly as asked
nuclear@0 870 NarrowModesList(modes, ModeItemAlpha, (long)GCParams->AlphaChannel);
nuclear@0 871 }
nuclear@0 872
nuclear@0 873 if(!(GCParams->DontCareFlags & GCPDONTCARE_REFRESH)) { // specific refresh rate
nuclear@0 874 NarrowModesList(modes, ModeItemRefresh, GCParams->RefreshRate);
nuclear@0 875 }
nuclear@0 876
nuclear@0 877 if(!modes->Size()) { // didn't find any mode with the properties that we asked
nuclear@0 878 throw EngineInitException("Requested video mode parameters not available");
nuclear@0 879 }
nuclear@0 880
nuclear@0 881 DisplayMode mode = ChooseBestMode(modes);
nuclear@0 882 delete modes; // delete the list of modes
nuclear@0 883
nuclear@0 884 D3DFORMAT PixelFormat = GetPixelFormatFromColorDepth(mode.ColorFormat);
nuclear@0 885
nuclear@0 886 // find out if we have the requested zbuffer format avaialble
nuclear@0 887 if(!GCParams->DepthBits) GCParams->DepthBits = 32; // not specified, trying highest possible first
nuclear@0 888 D3DFORMAT zfmt = GetDepthStencilFormat(GCParams->DepthBits, true);
nuclear@0 889
nuclear@0 890 bool res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt);
nuclear@0 891 if(!res) { // try a format without stencil
nuclear@0 892 zfmt = GetDepthStencilFormat(GCParams->DepthBits, false);
nuclear@0 893 res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt);
nuclear@0 894 }
nuclear@0 895
nuclear@0 896 if(!res) { // didn't find requested zbuffer even with no stencil
nuclear@0 897 // if we asked for specific zformat and didn't find it or if the zbuffer that
nuclear@0 898 // we failed to set was 16bits and can't go less, bail out
nuclear@0 899 if(!(GCParams->DontCareFlags & GCPDONTCARE_DEPTH) || GCParams->DepthBits == 16) return 0;
nuclear@0 900
nuclear@0 901 // try to set a smaller zbuffer with stencil
nuclear@0 902 GCParams->DepthBits = 16;
nuclear@0 903 zfmt = GetDepthStencilFormat(GCParams->DepthBits, true);
nuclear@0 904 res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt);
nuclear@0 905 if(!res) { // try a format without stencil
nuclear@0 906 zfmt = GetDepthStencilFormat(GCParams->DepthBits, false);
nuclear@0 907 res = !(bool)d3d->CheckDeviceFormat(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zfmt);
nuclear@0 908 }
nuclear@0 909
nuclear@0 910 if(!res) throw EngineInitException("Requested ZBuffer depth not available");
nuclear@0 911 }
nuclear@0 912
nuclear@0 913 int AASamples = 0;
nuclear@0 914 if(GCParams->Antialiasing) {
nuclear@0 915 if(GCParams->BestAA) {
nuclear@0 916 // find the best supported AA mode
nuclear@0 917 for(AASamples=16; AASamples > 0; AASamples--) {
nuclear@0 918 long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples);
nuclear@0 919 if(result == D3D_OK) break;
nuclear@0 920 }
nuclear@0 921 } else {
nuclear@0 922 // check for cheap AA
nuclear@0 923 AASamples = 2;
nuclear@0 924 long result = d3d->CheckDeviceMultiSampleType(AdapterID, (D3DDEVTYPE)GCParams->DevType, PixelFormat, !GCParams->FullScreen, (D3DMULTISAMPLE_TYPE)AASamples);
nuclear@0 925 if(result != D3D_OK) AASamples = 0;
nuclear@0 926 }
nuclear@0 927
nuclear@0 928 if(!AASamples && !(GCParams->DontCareFlags & GCPDONTCARE_AA)) {
nuclear@0 929 throw EngineInitException("Requested Antialiasing mode not available");
nuclear@0 930 }
nuclear@0 931 }
nuclear@0 932
nuclear@0 933 D3DFORMAT FinalColorFormat;
nuclear@0 934 if(GCParams->FullScreen) {
nuclear@0 935 FinalColorFormat = GetPixelFormatFromColorDepth(mode.ColorFormat);
nuclear@0 936 } else {
nuclear@0 937 D3DDISPLAYMODE CurrentMode;
nuclear@0 938 d3d->GetAdapterDisplayMode(AdapterID, &CurrentMode);
nuclear@0 939 FinalColorFormat = CurrentMode.Format;
nuclear@0 940 }
nuclear@0 941
nuclear@0 942 // if everything went well, now we can set that mode
nuclear@0 943 D3DPRESENT_PARAMETERS d3dppar;
nuclear@0 944 d3dppar.BackBufferWidth = GCParams->x;
nuclear@0 945 d3dppar.BackBufferHeight = GCParams->y;
nuclear@0 946 d3dppar.BackBufferFormat = FinalColorFormat;
nuclear@0 947 d3dppar.BackBufferCount = (unsigned int)GCParams->Buffers;
nuclear@0 948 d3dppar.MultiSampleType = (D3DMULTISAMPLE_TYPE)AASamples;
nuclear@0 949 d3dppar.SwapEffect = D3DSWAPEFFECT_DISCARD;
nuclear@0 950 d3dppar.hDeviceWindow = WindowHandle;
nuclear@0 951 d3dppar.Windowed = !GCParams->FullScreen;
nuclear@0 952 d3dppar.EnableAutoDepthStencil = true;
nuclear@0 953 d3dppar.AutoDepthStencilFormat = zfmt;
nuclear@0 954 d3dppar.Flags = 0;
nuclear@0 955 d3dppar.FullScreen_RefreshRateInHz = (GCParams->FullScreen) ? mode.RefreshRate : 0;
nuclear@0 956 if(GCParams->FullScreen) {
nuclear@0 957 d3dppar.FullScreen_PresentationInterval = (GCParams->VSync) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
nuclear@0 958 } else {
nuclear@0 959 d3dppar.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
nuclear@0 960 }
nuclear@0 961
nuclear@0 962 // create the rendering context
nuclear@0 963 GraphicsContext *gc = new GraphicsContext;
nuclear@0 964
nuclear@0 965 TnLMode tnlmode = (GCParams->HardwareTnL) ? HardwareTnL : SoftwareTnL;
nuclear@0 966
nuclear@0 967 long result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice);
nuclear@0 968 if(result != D3D_OK) {
nuclear@0 969 if(d3dppar.BackBufferCount != GCParams->Buffers) {
nuclear@0 970 if((GCParams->DontCareFlags & GCPDONTCARE_BUFFERS)) {
nuclear@0 971 result = d3d->CreateDevice(AdapterID, (D3DDEVTYPE)GCParams->DevType, WindowHandle, tnlmode, &d3dppar, &gc->D3DDevice);
nuclear@0 972 } else {
nuclear@0 973 throw EngineInitException("Could not create Direct3D device");
nuclear@0 974 }
nuclear@0 975 }
nuclear@0 976 }
nuclear@0 977
nuclear@0 978 if(result != D3D_OK) {
nuclear@0 979 throw EngineInitException("Could not create Direct3D device");
nuclear@0 980 }
nuclear@0 981
nuclear@0 982 gc->WindowHandle = WindowHandle;
nuclear@0 983 gc->D3DDevice->GetRenderTarget(&gc->MainRenderTarget.ColorSurface);
nuclear@0 984 gc->D3DDevice->GetDepthStencilSurface(&gc->MainRenderTarget.DepthStencilSurface);
nuclear@0 985 gc->ContextParams = *GCParams;
nuclear@0 986 gc->ZFormat = zfmt;
nuclear@0 987 gc->AASamples = AASamples;
nuclear@0 988 gc->ColorFormat = FinalColorFormat;
nuclear@0 989 gc->MaxTextureStages = adapters[AdapterID].Capabilities.MaxSimultaneousTextures;
nuclear@0 990 gc->texman = new TextureManager(gc);
nuclear@0 991
nuclear@0 992 gc->SetDefaultStates();
nuclear@0 993
nuclear@0 994 GraphicsContexts.push_back(gc);
nuclear@0 995
nuclear@0 996 return gc;
nuclear@0 997 }
nuclear@0 998
nuclear@0 999 //////////////////////////////////////////
nuclear@0 1000 // ----==( CreateGraphicsContext )==----
nuclear@0 1001 // (Public Member Function)
nuclear@0 1002 // Creates a graphics context with the specified parameters
nuclear@0 1003 // Light version, basic info passed, fills in the rest
nuclear@0 1004 //////////////////////////////////////////
nuclear@0 1005 GraphicsContext *Engine3D::CreateGraphicsContext(HWND WindowHandle, int x, int y, int bpp, word flags) {
nuclear@0 1006
nuclear@0 1007 ContextInitParameters gcp;
nuclear@0 1008 gcp.x = x;
nuclear@0 1009 gcp.y = y;
nuclear@0 1010 gcp.bpp = bpp;
nuclear@0 1011 gcp.DepthBits = 24;
nuclear@0 1012 gcp.DevType = DeviceHardware;
nuclear@0 1013 gcp.FullScreen = (flags & GCCREATE_FULLSCREEN) ? true : false;
nuclear@0 1014 gcp.HardwareTnL = true;
nuclear@0 1015 gcp.RefreshRate = 75;
nuclear@0 1016 gcp.Antialiasing = false;
nuclear@0 1017 gcp.Buffers = DoubleBuffering;
nuclear@0 1018 gcp.VSync = false;
nuclear@0 1019 gcp.DontCareFlags = GCPDONTCARE_DEPTH | GCPDONTCARE_REFRESH | GCPDONTCARE_ALPHA | GCPDONTCARE_VSYNC;
nuclear@0 1020
nuclear@0 1021 return CreateGraphicsContext(WindowHandle, D3DADAPTER_DEFAULT, &gcp);
nuclear@0 1022 }
nuclear@0 1023
nuclear@0 1024 using std::string;
nuclear@0 1025 using std::getline;
nuclear@0 1026
nuclear@0 1027 string GetValue(string line) {
nuclear@0 1028 int nexttoken = (int)line.find("=") + 1;
nuclear@0 1029 while(line[++nexttoken] == ' ');
nuclear@0 1030 int tokenend = (int)line.find_first_of(" \n\r\t");
nuclear@0 1031 return line.substr(nexttoken, tokenend - nexttoken);
nuclear@0 1032 }
nuclear@0 1033
nuclear@0 1034 ContextInitParameters Engine3D::LoadContextParamsConfigFile(const char *cfgfilename) {
nuclear@0 1035 ContextInitParameters cip;
nuclear@0 1036 memset(&cip, 0, sizeof(ContextInitParameters));
nuclear@0 1037
nuclear@0 1038 std::ifstream file(cfgfilename);
nuclear@0 1039 if(!file.is_open()) throw EngineInitException("Could not open configuration file");
nuclear@0 1040
nuclear@0 1041 string line;
nuclear@0 1042 getline(file, line);
nuclear@0 1043 while(!file.eof()) {
nuclear@0 1044 if(line[0] != ';' && line[0] != '\n' && line[0] != '\r' && line[0] != ' ') {
nuclear@0 1045 int tokenend = (int)line.find(" ");
nuclear@0 1046 string token = line.substr(0, tokenend);
nuclear@0 1047
nuclear@0 1048 if(token == "fullscreen") {
nuclear@0 1049 string value = GetValue(line);
nuclear@0 1050 cip.FullScreen = (value == "true") ? true : false;
nuclear@0 1051 } else if(token == "resolution") {
nuclear@0 1052 string value = GetValue(line);
nuclear@0 1053 int x = (int)value.find("x");
nuclear@0 1054 cip.x = atoi(value.substr(0, x).c_str());
nuclear@0 1055 cip.y = atoi(value.substr(x+1, value.size()).c_str());
nuclear@0 1056 } else if(token == "bpp") {
nuclear@0 1057 cip.bpp = atoi(GetValue(line).c_str());
nuclear@0 1058 } else if(token == "zbufferdepth") {
nuclear@0 1059 cip.DepthBits = atoi(GetValue(line).c_str());
nuclear@0 1060 } else if(token == "device") {
nuclear@0 1061 cip.DevType = (GetValue(line) == "ref") ? DeviceReference : DeviceHardware;
nuclear@0 1062 } else if(token == "tnl") {
nuclear@0 1063 cip.HardwareTnL = (GetValue(line) == "false") ? false : true;
nuclear@0 1064 } else if(token == "refresh") {
nuclear@0 1065 cip.RefreshRate = atoi(GetValue(line).c_str());
nuclear@0 1066 } else if(token == "antialiasing") {
nuclear@0 1067 string value = GetValue(line);
nuclear@0 1068 cip.Antialiasing = (value == "none") ? false : true;
nuclear@0 1069 if(cip.Antialiasing) {
nuclear@0 1070 cip.BestAA = (value == "speed" || value == "low") ? false : true;
nuclear@0 1071 }
nuclear@0 1072 } else if(token == "flipchain") {
nuclear@0 1073 cip.Buffers = (GetValue(line) == "triplebuffering") ? TripleBuffering : DoubleBuffering;
nuclear@0 1074 } else if(token == "vsync") {
nuclear@0 1075 cip.VSync = (GetValue(line) == "true") ? true : false;
nuclear@0 1076 } else if(token == "dontcareabout") {
nuclear@0 1077 cip.DontCareFlags = 0;
nuclear@0 1078 string flags = GetValue(line);
nuclear@0 1079 string part;
nuclear@0 1080 while(1) {
nuclear@0 1081 int begin = (int)flags.find_first_not_of(", ");
nuclear@0 1082 int end = (int)flags.find(",", begin) - begin;
nuclear@0 1083 part = flags.substr(begin, end);
nuclear@0 1084 //part = flags.substr(0, flags.find(","));// \n\r\t"));
nuclear@0 1085 if(part.empty()) break;
nuclear@0 1086 if(part == "bpp") cip.DontCareFlags |= GCPDONTCARE_BPP;
nuclear@0 1087 if(part == "refresh") cip.DontCareFlags |= GCPDONTCARE_REFRESH;
nuclear@0 1088 if(part == "alpha") cip.DontCareFlags |= GCPDONTCARE_ALPHA;
nuclear@0 1089 if(part == "zbufferdepth") cip.DontCareFlags |= GCPDONTCARE_DEPTH;
nuclear@0 1090 if(part == "tnl") cip.DontCareFlags |= GCPDONTCARE_TNL;
nuclear@0 1091 if(part == "flipchain") cip.DontCareFlags |= GCPDONTCARE_BUFFERS;
nuclear@0 1092 if(part == "aamode") cip.DontCareFlags |= GCPDONTCARE_AA;
nuclear@0 1093 if(part == "vsync") cip.DontCareFlags |= GCPDONTCARE_VSYNC;
nuclear@0 1094 int temp = (int)flags.find_first_of(",\n\r");
nuclear@0 1095 if(temp == string::npos) break;
nuclear@0 1096 flags.erase(0, temp+1);
nuclear@0 1097 }
nuclear@0 1098 }
nuclear@0 1099
nuclear@0 1100 }
nuclear@0 1101
nuclear@0 1102 getline(file, line);
nuclear@0 1103 }
nuclear@0 1104
nuclear@0 1105 return cip;
nuclear@0 1106 }
nuclear@0 1107
nuclear@0 1108 void Engine3D::DestroyGraphicsContext(GraphicsContext *gc) {
nuclear@0 1109 gc->D3DDevice->Release();
nuclear@0 1110 }
nuclear@0 1111
nuclear@0 1112 int Engine3D::GetAdapterCount() const {
nuclear@0 1113 return AdapterCount;
nuclear@0 1114 }
nuclear@0 1115
nuclear@0 1116 const Adapter *Engine3D::GetAdapterInfo(int adapter) const {
nuclear@0 1117 return &adapters[adapter];
nuclear@0 1118 }
nuclear@0 1119
nuclear@0 1120
nuclear@0 1121 //////////////////////////////////////////////////////////////////////////////
nuclear@0 1122 // helper functions
nuclear@0 1123
nuclear@0 1124 bool Lock(VertexBuffer *vb, Vertex **data) {
nuclear@0 1125 D3DVERTEXBUFFER_DESC desc;
nuclear@0 1126 vb->GetDesc(&desc);
nuclear@0 1127 dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0;
nuclear@0 1128
nuclear@0 1129 return (vb->Lock(0, 0, (byte**)data, flags) == D3D_OK);
nuclear@0 1130 }
nuclear@0 1131
nuclear@0 1132 bool Lock(IndexBuffer *ib, Index **data) {
nuclear@0 1133 D3DINDEXBUFFER_DESC desc;
nuclear@0 1134 ib->GetDesc(&desc);
nuclear@0 1135 dword flags = (desc.Usage & D3DUSAGE_DYNAMIC) ? D3DLOCK_DISCARD | D3DLOCK_NOOVERWRITE : 0;
nuclear@0 1136
nuclear@0 1137 return (ib->Lock(0, 0, (byte**)data, flags) == D3D_OK);
nuclear@0 1138 }
nuclear@0 1139
nuclear@0 1140 void Unlock(VertexBuffer *vb) {
nuclear@0 1141 vb->Unlock();
nuclear@0 1142 }
nuclear@0 1143
nuclear@0 1144 void Unlock(IndexBuffer *ib) {
nuclear@0 1145 ib->Unlock();
nuclear@0 1146 }
nuclear@0 1147
nuclear@0 1148
nuclear@0 1149 void CreateProjectionMatrix(Matrix4x4 *mat, float yFOV, float Aspect, float NearClip, float FarClip) {
nuclear@0 1150
nuclear@0 1151 float h, w, Q;
nuclear@0 1152 float xFOV = yFOV * Aspect;
nuclear@0 1153
nuclear@0 1154 w = (float)(1.0f/tan(xFOV*0.5f)); // 1/tan(x) == cot(x)
nuclear@0 1155 h = (float)(1.0f/tan(yFOV*0.5f)); // 1/tan(x) == cot(x)
nuclear@0 1156 Q = FarClip / (FarClip - NearClip);
nuclear@0 1157
nuclear@0 1158 /* Projection Matrix
nuclear@0 1159 [ w 0.0f 0.0f 0.0f]
nuclear@0 1160 |0.0f h 0.0f 0.0f|
nuclear@0 1161 |0.0f 0.0f Q 1.0f|
nuclear@0 1162 [0.0f 0.0f -Q*NearClip 0.0f]
nuclear@0 1163 */
nuclear@0 1164
nuclear@0 1165 mat->ResetIdentity();
nuclear@0 1166 mat->m[0][0] = w;
nuclear@0 1167 mat->m[1][1] = h;
nuclear@0 1168 mat->m[2][2] = Q;
nuclear@0 1169 mat->m[3][2] = -Q*NearClip;
nuclear@0 1170 mat->m[2][3] = 1.0f;
nuclear@0 1171 }
nuclear@0 1172
nuclear@0 1173 dword PackVector(const Vector3 &vec, float Height) {
nuclear@0 1174 dword r = (dword)(127.0f * vec.x + 128.0f);
nuclear@0 1175 dword g = (dword)(127.0f * vec.y + 128.0f);
nuclear@0 1176 dword b = (dword)(127.0f * vec.z + 128.0f);
nuclear@0 1177 dword a = (dword)(255.0f * Height);
nuclear@0 1178
nuclear@0 1179 return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) );
nuclear@0 1180 }
nuclear@0 1181
nuclear@0 1182 void NormalMapFromHeightField(Texture *tex) {
nuclear@0 1183
nuclear@0 1184 // Lock the texture
nuclear@0 1185 D3DLOCKED_RECT d3dlr;
nuclear@0 1186 D3DSURFACE_DESC d3dsd;
nuclear@0 1187
nuclear@0 1188 int LevelCount = tex->GetLevelCount();
nuclear@0 1189 for(int i=0; i<LevelCount; i++) {
nuclear@0 1190
nuclear@0 1191 tex->GetLevelDesc(i, &d3dsd);
nuclear@0 1192 tex->LockRect(i, &d3dlr, 0, 0);
nuclear@0 1193 DWORD* pPixel = (DWORD*)d3dlr.pBits;
nuclear@0 1194
nuclear@0 1195 // For each pixel, generate a vector normal that represents the change
nuclear@0 1196 // in thea height field at that pixel
nuclear@0 1197 for( DWORD j=0; j<d3dsd.Height; j++ ) {
nuclear@0 1198 for( DWORD i=0; i<d3dsd.Width; i++ ) {
nuclear@0 1199 DWORD color00 = pPixel[0];
nuclear@0 1200 DWORD color10 = pPixel[1];
nuclear@0 1201 DWORD color01 = pPixel[d3dlr.Pitch/sizeof(DWORD)];
nuclear@0 1202
nuclear@0 1203 float fHeight00 = (float)((color00 & 0x00ff0000) >> 16) / 255.0f;
nuclear@0 1204 float fHeight10 = (float)((color10 & 0x00ff0000) >> 16) / 255.0f;
nuclear@0 1205 float fHeight01 = (float)((color01 & 0x00ff0000) >> 16) / 255.0f;
nuclear@0 1206
nuclear@0 1207 Vector3 vPoint00(i+0.0f, j+0.0f, fHeight00);
nuclear@0 1208 Vector3 vPoint10(i+1.0f, j+0.0f, fHeight10);
nuclear@0 1209 Vector3 vPoint01(i+0.0f, j+1.0f, fHeight01);
nuclear@0 1210 Vector3 v10 = vPoint10 - vPoint00;
nuclear@0 1211 Vector3 v01 = vPoint01 - vPoint00;
nuclear@0 1212
nuclear@0 1213 Vector3 Normal = v10.CrossProduct(v01);
nuclear@0 1214 Normal.Normalize();
nuclear@0 1215
nuclear@0 1216 // Store the normal as an RGBA value in the normal map
nuclear@0 1217 *pPixel++ = PackVector(Normal, fHeight00);
nuclear@0 1218 }
nuclear@0 1219 }
nuclear@0 1220 tex->UnlockRect(i);
nuclear@0 1221 }
nuclear@0 1222 }
nuclear@0 1223
nuclear@0 1224 void UpdateMipmapChain(Texture *tex) {
nuclear@0 1225 D3DXFilterTexture(tex, 0, 0, D3DX_FILTER_BOX);
nuclear@0 1226 }
nuclear@0 1227
nuclear@0 1228 dword AddEdge(Edge *edges, dword EdgeCount, const Edge &newedge) {
nuclear@0 1229 // remove internal edges
nuclear@0 1230 for(dword i=0; i<EdgeCount; i++) {
nuclear@0 1231 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])) {
nuclear@0 1232 edges[i] = edges[--EdgeCount];
nuclear@0 1233 return EdgeCount;
nuclear@0 1234 }
nuclear@0 1235 }
nuclear@0 1236
nuclear@0 1237 edges[EdgeCount++] = newedge;
nuclear@0 1238 return EdgeCount;
nuclear@0 1239 }
nuclear@0 1240
nuclear@0 1241 //#define LIGHTDIR(l, p) (l->GetType() == LTDir ? l->GetDirection() : p - l->GetPosition())
nuclear@0 1242 inline Vector3 GetLightDir(const Light *light, const Vector3 &pos, const Matrix4x4 &mat) {
nuclear@0 1243 if(light->GetType() == LTDir) {
nuclear@0 1244 return light->GetDirection();
nuclear@0 1245 } else {
nuclear@0 1246 Vector3 lpos = light->GetPosition();
nuclear@0 1247 lpos.Transform(mat);
nuclear@0 1248 return pos - lpos;
nuclear@0 1249 }
nuclear@0 1250 return Vector3();
nuclear@0 1251 }
nuclear@0 1252
nuclear@0 1253
nuclear@0 1254 //////////////////////////////////////////
nuclear@0 1255 // ----==( CreateShadowVolume )==----
nuclear@0 1256 // (Helper Function)
nuclear@0 1257 // Creates a graphics context with the specified parameters
nuclear@0 1258 // Light version, basic info passed, fills in the rest
nuclear@0 1259 //////////////////////////////////////////
nuclear@0 1260
nuclear@0 1261 TriMesh *CreateShadowVolume(const TriMesh &mesh, const Light *light, const Matrix4x4 &MeshXForm, bool WorldCoords) {
nuclear@0 1262
nuclear@0 1263 // transform light into object's local coordinate system
nuclear@0 1264 //const_cast<Light*>(light)->Transform(MeshXForm.Inverse());
nuclear@0 1265 Matrix4x4 InvXForm = MeshXForm.Inverse();
nuclear@0 1266
nuclear@0 1267 const Vertex *varray = mesh.GetVertexArray();
nuclear@0 1268 const Triangle *triarray = mesh.GetTriangleArray();
nuclear@0 1269
nuclear@0 1270 dword VertexCount = mesh.GetVertexCount();
nuclear@0 1271 dword TriangleCount = mesh.GetTriangleCount();
nuclear@0 1272
nuclear@0 1273 Edge *edges = new Edge[TriangleCount];
nuclear@0 1274 dword EdgeCount = 0;
nuclear@0 1275
nuclear@0 1276 // first find the contour edges
nuclear@0 1277
nuclear@0 1278 for(dword i=0; i<TriangleCount; i++) {
nuclear@0 1279
nuclear@0 1280 // find the light vector incident at this triangle
nuclear@0 1281 Vertex TriVerts[3];
nuclear@0 1282 TriVerts[0] = varray[triarray[i].vertices[0]];
nuclear@0 1283 TriVerts[1] = varray[triarray[i].vertices[1]];
nuclear@0 1284 TriVerts[2] = varray[triarray[i].vertices[2]];
nuclear@0 1285
nuclear@0 1286 Vector3 pos = (TriVerts[0].pos + TriVerts[1].pos + TriVerts[2].pos) / 3.0f;
nuclear@0 1287 //Vector3 LightDir = LIGHTDIR(light, pos);
nuclear@0 1288 Vector3 LightDir = GetLightDir(light, pos, InvXForm);
nuclear@0 1289
nuclear@0 1290 // if it looks away from the light...
nuclear@0 1291 if(DotProduct(triarray[i].normal, LightDir) >= 0.0f) {
nuclear@0 1292 EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[0], triarray[i].vertices[1]));
nuclear@0 1293 EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[1], triarray[i].vertices[2]));
nuclear@0 1294 EdgeCount = AddEdge(edges, EdgeCount, Edge(triarray[i].vertices[2], triarray[i].vertices[0]));
nuclear@0 1295 }
nuclear@0 1296 }
nuclear@0 1297
nuclear@0 1298 // now extract the contour edges to build the shadow volume boundrary
nuclear@0 1299 const float ExtrudeMagnitude = 100000.0f;
nuclear@0 1300 Vertex *ShadowVertices = new Vertex[EdgeCount * 6];
nuclear@0 1301
nuclear@0 1302 for(dword i=0; i<EdgeCount; i++) {
nuclear@0 1303 Vertex QuadVert[4];
nuclear@0 1304 QuadVert[0] = varray[edges[i].vertices[0]];
nuclear@0 1305 QuadVert[1] = varray[edges[i].vertices[1]];
nuclear@0 1306 //QuadVert[2] = QuadVert[1].pos + (Vector3)LIGHTDIR(light, QuadVert[1].pos) * ExtrudeMagnitude;
nuclear@0 1307 //QuadVert[3] = QuadVert[0].pos + (Vector3)LIGHTDIR(light, QuadVert[0].pos) * ExtrudeMagnitude;
nuclear@0 1308 QuadVert[2] = QuadVert[1].pos + GetLightDir(light, QuadVert[1].pos, InvXForm) * ExtrudeMagnitude;
nuclear@0 1309 QuadVert[3] = QuadVert[0].pos + GetLightDir(light, QuadVert[0].pos, InvXForm) * ExtrudeMagnitude;
nuclear@0 1310
nuclear@0 1311 ShadowVertices[i*6] = QuadVert[0];
nuclear@0 1312 ShadowVertices[i*6+1] = QuadVert[1];
nuclear@0 1313 ShadowVertices[i*6+2] = QuadVert[2];
nuclear@0 1314
nuclear@0 1315 ShadowVertices[i*6+3] = QuadVert[0];
nuclear@0 1316 ShadowVertices[i*6+4] = QuadVert[2];
nuclear@0 1317 ShadowVertices[i*6+5] = QuadVert[3];
nuclear@0 1318
nuclear@0 1319 if(WorldCoords) {
nuclear@0 1320 for(int j=0; j<6; j++) {
nuclear@0 1321 ShadowVertices[i*6+j].pos.Transform(MeshXForm);
nuclear@0 1322 }
nuclear@0 1323 }
nuclear@0 1324 }
nuclear@0 1325
nuclear@0 1326 TriMesh *ShadowMesh = new TriMesh(1);
nuclear@0 1327 ShadowMesh->SetData(ShadowVertices, 0, EdgeCount * 6, 0);
nuclear@0 1328
nuclear@0 1329 delete [] ShadowVertices;
nuclear@0 1330 delete [] edges;
nuclear@0 1331
nuclear@0 1332 //const_cast<Light*>(light)->Transform(MeshXForm); // return light to world coordinate system
nuclear@0 1333
nuclear@0 1334 return ShadowMesh;
nuclear@0 1335 }
nuclear@0 1336
nuclear@0 1337
nuclear@0 1338 ///////////// local //////////////
nuclear@0 1339
nuclear@0 1340 ColorDepth GetColorDepthFromPixelFormat(D3DFORMAT fmt) {
nuclear@0 1341 switch(fmt) {
nuclear@0 1342 case D3DFMT_R8G8B8: return ColorDepth(24, 24, 0);
nuclear@0 1343 case D3DFMT_A8R8G8B8: return ColorDepth(32, 24, 8);
nuclear@0 1344 case D3DFMT_X8R8G8B8: return ColorDepth(32, 24, 0);
nuclear@0 1345 case D3DFMT_R5G6B5: return ColorDepth(16, 16, 0);
nuclear@0 1346 case D3DFMT_X1R5G5B5: return ColorDepth(16, 15, 0);
nuclear@0 1347 case D3DFMT_A1R5G5B5: return ColorDepth(16, 15, 1);
nuclear@0 1348 case D3DFMT_P8: return ColorDepth(8, 8, 0);
nuclear@0 1349 default: return ColorDepth(0, 0, 0);
nuclear@0 1350 }
nuclear@0 1351 }
nuclear@0 1352
nuclear@0 1353 bool operator ==(const ColorDepth &lhs, const ColorDepth &rhs) {
nuclear@0 1354 return (lhs.bpp == rhs.bpp && lhs.colorbits == rhs.colorbits && lhs.alpha == rhs.alpha);
nuclear@0 1355 }
nuclear@0 1356
nuclear@0 1357 D3DFORMAT GetPixelFormatFromColorDepth(ColorDepth cd, bool noalpha) {
nuclear@0 1358 if(cd == ColorDepth(24, 24, 0)) return D3DFMT_R8G8B8;
nuclear@0 1359 if(cd == ColorDepth(32, 24, 8)) return noalpha ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
nuclear@0 1360 if(cd == ColorDepth(32, 24, 0)) return D3DFMT_X8R8G8B8;
nuclear@0 1361 if(cd == ColorDepth(16, 16, 0)) return D3DFMT_R5G6B5;
nuclear@0 1362 if(cd == ColorDepth(16, 15, 0)) return D3DFMT_X1R5G5B5;
nuclear@0 1363 if(cd == ColorDepth(16, 15, 1)) return noalpha ? D3DFMT_X1R5G5B5 : D3DFMT_A1R5G5B5;
nuclear@0 1364 if(cd == ColorDepth(8, 8, 0)) return D3DFMT_P8;
nuclear@0 1365 return (D3DFORMAT)0;
nuclear@0 1366 }
nuclear@0 1367
nuclear@0 1368
nuclear@0 1369 D3DFORMAT GetDepthStencilFormat(int depthbits, bool stencil) {
nuclear@0 1370 switch(depthbits) {
nuclear@0 1371 case 32:
nuclear@0 1372 return (stencil) ? D3DFMT_D24S8 : D3DFMT_D32;
nuclear@0 1373 break;
nuclear@0 1374
nuclear@0 1375 case 24:
nuclear@0 1376 return (stencil) ? D3DFMT_D24S8 : D3DFMT_D24X8;
nuclear@0 1377 break;
nuclear@0 1378
nuclear@0 1379 case 16:
nuclear@0 1380 return (stencil) ? D3DFMT_D15S1 : D3DFMT_D16;
nuclear@0 1381 break;
nuclear@0 1382
nuclear@0 1383 default:
nuclear@0 1384 break;
nuclear@0 1385 }
nuclear@0 1386
nuclear@0 1387 return (D3DFORMAT)0;
nuclear@0 1388 }