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