absence_thelab

diff src/3deng/3dengine.cpp @ 0:1cffe3409164

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