summaryrefslogtreecommitdiffstats
path: root/src/graphics/d3d
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/d3d')
-rw-r--r--src/graphics/d3d/d3dengine.cpp5727
-rw-r--r--src/graphics/d3d/d3dengine.h686
-rw-r--r--src/graphics/d3d/d3denum.cpp621
-rw-r--r--src/graphics/d3d/d3denum.h136
-rw-r--r--src/graphics/d3d/d3dframe.cpp623
-rw-r--r--src/graphics/d3d/d3dframe.h142
-rw-r--r--src/graphics/d3d/d3dtextr.cpp1080
-rw-r--r--src/graphics/d3d/d3dtextr.h80
-rw-r--r--src/graphics/d3d/d3dutil.cpp327
-rw-r--r--src/graphics/d3d/d3dutil.h114
10 files changed, 9536 insertions, 0 deletions
diff --git a/src/graphics/d3d/d3dengine.cpp b/src/graphics/d3d/d3dengine.cpp
new file mode 100644
index 0000000..bbfb89e
--- /dev/null
+++ b/src/graphics/d3d/d3dengine.cpp
@@ -0,0 +1,5727 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// D3DEngine.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <stdio.h>
+#include <math.h>
+
+#include "struct.h"
+#include "d3dapp.h"
+#include "d3dtextr.h"
+#include "d3dutil.h"
+#include "d3dmath.h"
+#include "d3dengine.h"
+#include "language.h"
+#include "iman.h"
+#include "event.h"
+#include "profile.h"
+#include "math3d.h"
+#include "object.h"
+#include "interface.h"
+#include "light.h"
+#include "text.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "cloud.h"
+#include "blitz.h"
+#include "planet.h"
+#include "sound.h"
+
+
+
+#define SIZEBLOC_TEXTURE 50
+#define SIZEBLOC_TRANSFORM 100
+#define SIZEBLOC_MINMAX 5
+#define SIZEBLOC_LIGHT 10
+#define SIZEBLOC_MATERIAL 100
+#define SIZEBLOC_TRIANGLE 200
+
+
+
+#if 0
+static int debug_blend1 = 1;
+static int debug_blend2 = 3;
+static int debug_blend3 = 8;
+static int debug_blend4 = 0;
+
+static int table_blend[13] =
+{
+ D3DBLEND_ZERO, // 0
+ D3DBLEND_ONE, // 1
+ D3DBLEND_SRCCOLOR, // 2
+ D3DBLEND_INVSRCCOLOR, // 3
+ D3DBLEND_SRCALPHA, // 4
+ D3DBLEND_INVSRCALPHA, // 5
+ D3DBLEND_DESTALPHA, // 6
+ D3DBLEND_INVDESTALPHA, // 7
+ D3DBLEND_DESTCOLOR, // 8
+ D3DBLEND_INVDESTCOLOR, // 9
+ D3DBLEND_SRCALPHASAT, // 10
+ D3DBLEND_BOTHSRCALPHA, // 11
+ D3DBLEND_BOTHINVSRCALPHA, // 12
+};
+#endif
+
+static int s_resol = 0;
+
+
+
+// Converts a FLOAT to a DWORD for use in SetRenderState() calls.
+
+inline DWORD F2DW( FLOAT f )
+{
+ return *((DWORD*)&f);
+}
+
+
+
+
+// Application constructor. Sets attributes for the app.
+
+CD3DEngine::CD3DEngine(CInstanceManager *iMan, CD3DApplication *app)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_ENGINE, this);
+ m_app = app;
+
+ m_light = new CLight(m_iMan, this);
+ m_text = new CText(m_iMan, this);
+ m_particule = new CParticule(m_iMan, this);
+ m_water = new CWater(m_iMan, this);
+ m_cloud = new CCloud(m_iMan, this);
+ m_blitz = new CBlitz(m_iMan, this);
+ m_planet = new CPlanet(m_iMan, this);
+ m_pD3DDevice = 0;
+ m_sound = 0;
+ m_terrain = 0;
+
+ m_dim.x = 640;
+ m_dim.y = 480;
+ m_lastDim = m_dim;
+ m_focus = 0.75f;
+ m_baseTime = 0;
+ m_lastTime = 0;
+ m_absTime = 0.0f;
+ m_rankView = 0;
+ m_ambiantColor[0] = 0x80808080;
+ m_ambiantColor[1] = 0x80808080;
+ m_fogColor[0] = 0xffffffff; // white
+ m_fogColor[1] = 0xffffffff; // white
+ m_deepView[0] = 1000.0f;
+ m_deepView[1] = 1000.0f;
+ m_fogStart[0] = 0.75f;
+ m_fogStart[1] = 0.75f;
+ m_waterAddColor.r = 0.0f;
+ m_waterAddColor.g = 0.0f;
+ m_waterAddColor.b = 0.0f;
+ m_waterAddColor.a = 0.0f;
+ m_bPause = FALSE;
+ m_bRender = TRUE;
+ m_bMovieLock = FALSE;
+ m_bShadow = TRUE;
+ m_bGroundSpot = TRUE;
+ m_bDirty = TRUE;
+ m_bFog = TRUE;
+ m_speed = 1.0f;
+ m_secondTexNum = 0;
+ m_eyeDirH = 0.0f;
+ m_eyeDirV = 0.0f;
+ m_backgroundName[0] = 0; // no background image
+ m_backgroundColorUp = 0;
+ m_backgroundColorDown = 0;
+ m_backgroundCloudUp = 0;
+ m_backgroundCloudDown = 0;
+ m_bBackgroundFull = FALSE;
+ m_bBackgroundQuarter = FALSE;
+ m_bOverFront = TRUE;
+ m_overColor = 0;
+ m_overMode = D3DSTATETCb;
+ m_frontsizeName[0] = 0; // no front image
+ m_hiliteRank[0] = -1; // empty list
+ m_mousePos = FPOINT(0.5f, 0.5f);
+ m_mouseType = D3DMOUSENORM;
+ m_bMouseHide = FALSE;
+ m_imageSurface = 0;
+ m_imageCopy = 0;
+ m_eyePt = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_lookatPt = D3DVECTOR(0.0f, 0.0f, 1.0f);
+ m_bDrawWorld = TRUE;
+ m_bDrawFront = FALSE;
+ m_limitLOD[0] = 100.0f;
+ m_limitLOD[1] = 200.0f;
+ m_particuleDensity = 1.0f;
+ m_clippingDistance = 1.0f;
+ m_lastClippingDistance = m_clippingDistance;
+ m_objectDetail = 1.0f;
+ m_lastObjectDetail = m_objectDetail;
+ m_terrainVision = 1000.0f;
+ m_gadgetQuantity = 1.0f;
+ m_textureQuality = 1;
+ m_bTotoMode = TRUE;
+ m_bLensMode = TRUE;
+ m_bWaterMode = TRUE;
+ m_bSkyMode = TRUE;
+ m_bBackForce = TRUE;
+ m_bPlanetMode = TRUE;
+ m_bLightMode = TRUE;
+ m_bEditIndentMode = TRUE;
+ m_editIndentValue = 4;
+ m_tracePrecision = 1.0f;
+
+ m_alphaMode = 1;
+ if ( GetProfileInt("Engine", "AlphaMode", i) )
+ {
+ m_alphaMode = i;
+ }
+
+ if ( GetProfileInt("Engine", "StateColor", i) && i != -1 )
+ {
+ m_bForceStateColor = TRUE;
+ m_bStateColor = i;
+ }
+ else
+ {
+ m_bForceStateColor = FALSE;
+ m_bStateColor = FALSE;
+ }
+
+ m_blackSrcBlend[0] = 0;
+ m_blackDestBlend[0] = 0;
+ m_whiteSrcBlend[0] = 0;
+ m_whiteDestBlend[0] = 0;
+ m_diffuseSrcBlend[0] = 0;
+ m_diffuseDestBlend[0] = 0;
+ m_alphaSrcBlend[0] = 0;
+ m_alphaDestBlend[0] = 0;
+
+ if ( GetProfileInt("Engine", "BlackSrcBlend", i) ) m_blackSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "BlackDestBlend", i) ) m_blackDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "WhiteSrcBlend", i) ) m_whiteSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "WhiteDestBlend", i) ) m_whiteDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "DiffuseSrcBlend", i) ) m_diffuseSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "DiffuseDestBlend", i) ) m_diffuseDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "AlphaSrcBlend", i) ) m_alphaSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "AlphaDestBlend", i) ) m_alphaDestBlend[0] = i;
+
+ m_bUpdateGeometry = FALSE;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ m_infoText[i][0] = 0;
+ }
+
+ m_objectPointer = 0;
+ MemSpace1(m_objectPointer, 0);
+
+ m_objectParam = (D3DObject*)malloc(sizeof(D3DObject)*D3DMAXOBJECT);
+ ZeroMemory(m_objectParam, sizeof(D3DObject)*D3DMAXOBJECT);
+ m_objectParamTotal = 0;
+
+ m_shadow = (D3DShadow*)malloc(sizeof(D3DShadow)*D3DMAXSHADOW);
+ ZeroMemory(m_shadow, sizeof(D3DShadow)*D3DMAXSHADOW);
+ m_shadowTotal = 0;
+
+ m_groundSpot = (D3DGroundSpot*)malloc(sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+ ZeroMemory(m_groundSpot, sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+
+ D3DTextr_SetTexturePath("textures\\");
+}
+
+// Application destructor. Free memory.
+
+CD3DEngine::~CD3DEngine()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ }
+ free(p2);
+ }
+ free(p1);
+
+ delete m_light;
+ delete m_particule;
+ delete m_water;
+ delete m_cloud;
+ delete m_blitz;
+ delete m_planet;
+}
+
+
+
+void CD3DEngine::SetD3DDevice(LPDIRECT3DDEVICE7 device)
+{
+ D3DDEVICEDESC7 ddDesc;
+
+ m_pD3DDevice = device;
+ m_light->SetD3DDevice(device);
+ m_text->SetD3DDevice(device);
+ m_particule->SetD3DDevice(device);
+
+ if ( !m_bForceStateColor )
+ {
+ m_pD3DDevice->GetCaps(&ddDesc);
+ if( ddDesc.dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_ADD )
+ {
+ m_bStateColor = TRUE;
+ }
+ else
+ {
+ m_bStateColor = FALSE;
+ }
+ }
+
+ m_blackSrcBlend[1] = D3DBLEND_ONE; // = 2
+ m_blackDestBlend[1] = D3DBLEND_INVSRCCOLOR; // = 4
+ m_whiteSrcBlend[1] = D3DBLEND_DESTCOLOR; // = 9
+ m_whiteDestBlend[1] = D3DBLEND_ZERO; // = 1
+ m_diffuseSrcBlend[1] = D3DBLEND_SRCALPHA; // = 5
+ m_diffuseDestBlend[1] = D3DBLEND_DESTALPHA; // = 7
+ m_alphaSrcBlend[1] = D3DBLEND_ONE; // = 2
+ m_alphaDestBlend[1] = D3DBLEND_INVSRCCOLOR; // = 4
+
+//? if ( !m_bStateColor ) m_whiteDestBlend[1] = D3DBLEND_INVSRCALPHA; // = 6
+
+// Fix for the graphics bug:
+ //if ( m_blackSrcBlend[0] ) m_blackSrcBlend[1] = m_blackSrcBlend[0];
+ //if ( m_blackDestBlend[0] ) m_blackDestBlend[1] = m_blackDestBlend[0];
+ //if ( m_whiteSrcBlend[0] ) m_whiteSrcBlend[1] = m_whiteSrcBlend[0];
+ //if ( m_whiteDestBlend[0] ) m_whiteDestBlend[1] = m_whiteDestBlend[0];
+
+ if ( m_diffuseSrcBlend[0] ) m_diffuseSrcBlend[1] = m_diffuseSrcBlend[0];
+ if ( m_diffuseDestBlend[0] ) m_diffuseDestBlend[1] = m_diffuseDestBlend[0];
+ if ( m_alphaSrcBlend[0] ) m_alphaSrcBlend[1] = m_alphaSrcBlend[0];
+ if ( m_alphaDestBlend[0] ) m_alphaDestBlend[1] = m_alphaDestBlend[0];
+
+#if 0
+ DWORD pass;
+ m_pD3DDevice->ValidateDevice(&pass);
+ char s[100];
+ sprintf(s, "NbPass=%d", pass);
+ SetInfoText(3, s);
+#endif
+}
+
+LPDIRECT3DDEVICE7 CD3DEngine::RetD3DDevice()
+{
+ return m_pD3DDevice;
+}
+
+
+// Gives the pointer to the existing terrain.
+
+void CD3DEngine::SetTerrain(CTerrain* terrain)
+{
+ m_terrain = terrain;
+}
+
+
+// Saving the state of the graphics engine in COLOBOT.INI.
+
+BOOL CD3DEngine::WriteProfile()
+{
+ SetProfileInt("Engine", "AlphaMode", m_alphaMode);
+
+ if ( m_bForceStateColor )
+ {
+ SetProfileInt("Engine", "StateColor", m_bStateColor);
+ }
+ else
+ {
+ SetProfileInt("Engine", "StateColor", -1);
+ }
+
+ SetProfileInt("Engine", "BlackSrcBlend", m_blackSrcBlend[0]);
+ SetProfileInt("Engine", "BlackDestBlend", m_blackDestBlend[0]);
+ SetProfileInt("Engine", "WhiteSrcBlend", m_whiteSrcBlend[0]);
+ SetProfileInt("Engine", "WhiteDestBlend", m_whiteDestBlend[0]);
+ SetProfileInt("Engine", "DiffuseSrcBlend", m_diffuseSrcBlend[0]);
+ SetProfileInt("Engine", "DiffuseDestBlend", m_diffuseDestBlend[0]);
+ SetProfileInt("Engine", "AlphaSrcBlend", m_alphaSrcBlend[0]);
+ SetProfileInt("Engine", "AlphaDestBlend", m_alphaDestBlend[0]);
+
+ return TRUE;
+}
+
+
+// Setup the app so it can support single-stepping.
+
+void CD3DEngine::TimeInit()
+{
+ m_baseTime = timeGetTime();
+ m_lastTime = 0;
+ m_absTime = 0.0f;
+}
+
+void CD3DEngine::TimeEnterGel()
+{
+ m_stopTime = timeGetTime();
+}
+
+void CD3DEngine::TimeExitGel()
+{
+ m_baseTime += timeGetTime() - m_stopTime;
+}
+
+float CD3DEngine::TimeGet()
+{
+ float aTime, rTime;
+
+ aTime = (timeGetTime()-m_baseTime)*0.001f; // in ms
+ rTime = (aTime - m_lastTime)*m_speed;
+ m_absTime += rTime;
+ m_lastTime = aTime;
+
+ return rTime;
+}
+
+
+void CD3DEngine::SetPause(BOOL bPause)
+{
+ m_bPause = bPause;
+}
+
+BOOL CD3DEngine::RetPause()
+{
+ return m_bPause;
+}
+
+
+void CD3DEngine::SetMovieLock(BOOL bLock)
+{
+ m_bMovieLock = bLock;
+}
+
+BOOL CD3DEngine::RetMovieLock()
+{
+ return m_bMovieLock;
+}
+
+
+void CD3DEngine::SetShowStat(BOOL bShow)
+{
+ m_app->SetShowStat(bShow);
+}
+
+BOOL CD3DEngine::RetShowStat()
+{
+ return m_app->RetShowStat();
+}
+
+
+void CD3DEngine::SetRenderEnable(BOOL bEnable)
+{
+ m_bRender = bEnable;
+}
+
+
+// Prepare a structure to add D3DObjLevel6
+// qq D3DVERTEX2 elements.
+
+void CD3DEngine::MemSpace6(D3DObjLevel6 *&p, int nb)
+{
+ D3DObjLevel6* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TRIANGLE+nb;
+ size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1);
+ p = (D3DObjLevel6*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TRIANGLE+nb;
+ size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1);
+ pp = (D3DObjLevel6*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prepare a structure to add D3DObjLevel5
+// qq elements D3DObjLevel6.
+
+void CD3DEngine::MemSpace5(D3DObjLevel5 *&p, int nb)
+{
+ D3DObjLevel5* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_MATERIAL+nb;
+ size = sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(total-1);
+ p = (D3DObjLevel5*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_MATERIAL+nb;
+ size = sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(total-1);
+ pp = (D3DObjLevel5*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prepare a structure to add D3DObjLevel4
+// qq D3DObjLevel5 elements.
+
+void CD3DEngine::MemSpace4(D3DObjLevel4 *&p, int nb)
+{
+ D3DObjLevel4* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_LIGHT+nb;
+ size = sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(total-1);
+ p = (D3DObjLevel4*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_LIGHT+nb;
+ size = sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(total-1);
+ pp = (D3DObjLevel4*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prepare a structure to add D3DObjLevel3
+// qq D3DObjLevel4 elements.
+
+void CD3DEngine::MemSpace3(D3DObjLevel3 *&p, int nb)
+{
+ D3DObjLevel3* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_MINMAX+nb;
+ size = sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(total-1);
+ p = (D3DObjLevel3*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_MINMAX+nb;
+ size = sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(total-1);
+ pp = (D3DObjLevel3*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prepare a structure to add D3DObjLevel2
+// qq D3DObjLevel3 elements.
+
+void CD3DEngine::MemSpace2(D3DObjLevel2 *&p, int nb)
+{
+ D3DObjLevel2* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TRANSFORM+nb;
+ size = sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(total-1);
+ p = (D3DObjLevel2*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TRANSFORM+nb;
+ size = sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(total-1);
+ pp = (D3DObjLevel2*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prepare a structure to add D3DObjLevel1
+// qq D3DObjLevel2 elements.
+
+void CD3DEngine::MemSpace1(D3DObjLevel1 *&p, int nb)
+{
+ D3DObjLevel1* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TEXTURE+nb;
+ size = sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(total-1);
+ p = (D3DObjLevel1*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TEXTURE+nb;
+ size = sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(total-1);
+ pp = (D3DObjLevel1*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+
+// Returns the number of objects that can still be created.
+
+int CD3DEngine::RetRestCreate()
+{
+ return D3DMAXOBJECT-m_objectParamTotal-2;
+}
+
+// Creates a new object. Returns its rank or -1 on error.
+
+int CD3DEngine::CreateObject()
+{
+ D3DMATRIX mat;
+ int i;
+
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE )
+ {
+ ZeroMemory(&m_objectParam[i], sizeof(D3DObject));
+ m_objectParam[i].bUsed = TRUE;
+
+ D3DUtil_SetIdentityMatrix(mat);
+ SetObjectTransform(i, mat);
+
+ m_objectParam[i].bDrawWorld = TRUE;
+ m_objectParam[i].distance = 0.0f;
+ m_objectParam[i].bboxMin = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_objectParam[i].bboxMax = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_objectParam[i].shadowRank = -1;
+
+ if ( i >= m_objectParamTotal )
+ {
+ m_objectParamTotal = i+1;
+ }
+ return i;
+ }
+ }
+ OutputDebugString("CD3DEngine::CreateObject() -> Too many object\n");
+ return -1;
+}
+
+
+// Removes all objects.
+
+void CD3DEngine::FlushObject()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, i;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ }
+ free(p2);
+ p1->table[l1] = 0;
+ }
+ p1->totalUsed = 0;
+
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ m_objectParam[i].bUsed = FALSE;
+ }
+ m_objectParamTotal = 0;
+
+ ZeroMemory(m_shadow, sizeof(D3DShadow)*D3DMAXSHADOW);
+ m_shadowTotal = 0;
+
+ GroundSpotFlush();
+}
+
+// Destroys an existing object.
+
+BOOL CD3DEngine::DeleteObject(int objRank)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, i;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ p2->table[l2] = 0;
+ }
+ }
+
+ ShadowDelete(objRank); // removes the shadow
+
+ m_objectParam[objRank].bUsed = FALSE;
+
+ m_objectParamTotal = 0;
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ if ( m_objectParam[i].bUsed )
+ {
+ m_objectParamTotal = i+1;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Indicates whether an object should be drawn underneath the interface.
+
+BOOL CD3DEngine::SetDrawWorld(int objRank, BOOL bDraw)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].bDrawWorld = bDraw;
+ return TRUE;
+}
+
+// Indicates whether an object should be drawn over the interface.
+
+BOOL CD3DEngine::SetDrawFront(int objRank, BOOL bDraw)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].bDrawFront = bDraw;
+ return TRUE;
+}
+
+
+// Prepare Level 1 to add a triangle.
+
+D3DObjLevel2* CD3DEngine::AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2)
+{
+ D3DObjLevel2* p2;
+ int l1;
+
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ if ( strcmp(p2->texName1, texName1) == 0 &&
+ strcmp(p2->texName2, texName2) == 0 )
+ {
+ MemSpace2(p1->table[l1], 1);
+ return p1->table[l1];
+ }
+ }
+
+ MemSpace1(p1, 1);
+ l1 = p1->totalUsed++;
+ p1->table[l1] = 0;
+
+ MemSpace2(p1->table[l1], 1);
+ strcpy(p1->table[l1]->texName1, texName1);
+ strcpy(p1->table[l1]->texName2, texName2);
+ return p1->table[l1];
+}
+
+// Prepare Level 2 to add a triangle.
+
+D3DObjLevel3* CD3DEngine::AddLevel2(D3DObjLevel2 *&p2, int objRank)
+{
+ D3DObjLevel3* p3;
+ int l2;
+
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank == objRank )
+ {
+ MemSpace3(p2->table[l2], 1);
+ return p2->table[l2];
+ }
+ }
+
+ MemSpace2(p2, 1);
+ l2 = p2->totalUsed++;
+ p2->table[l2] = 0;
+
+ MemSpace3(p2->table[l2], 1);
+ p2->table[l2]->objRank = objRank;
+ return p2->table[l2];
+}
+
+// Prepare Level 3 to add a triangle.
+
+D3DObjLevel4* CD3DEngine::AddLevel3(D3DObjLevel3 *&p3, float min, float max)
+{
+ D3DObjLevel4* p4;
+ int l3;
+
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min == min && p4->max == max )
+ {
+ MemSpace4(p3->table[l3], 1);
+ return p3->table[l3];
+ }
+ }
+
+ MemSpace3(p3, 1);
+ l3 = p3->totalUsed++;
+ p3->table[l3] = 0;
+
+ MemSpace4(p3->table[l3], 1);
+ p3->table[l3]->min = min;
+ p3->table[l3]->max = max;
+ return p3->table[l3];
+}
+
+// Prepare Level 4 to add a triangle.
+
+D3DObjLevel5* CD3DEngine::AddLevel4(D3DObjLevel4 *&p4, int reserve)
+{
+ D3DObjLevel5* p5;
+ int l4;
+
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ if ( p5->reserve == reserve )
+ {
+ MemSpace5(p4->table[l4], 1);
+ return p4->table[l4];
+ }
+ }
+
+ MemSpace4(p4, 1);
+ l4 = p4->totalUsed++;
+ p4->table[l4] = 0;
+
+ MemSpace5(p4->table[l4], 1);
+ p4->table[l4]->reserve = reserve;
+ return p4->table[l4];
+}
+
+// Prepares Level 5 to add vertices.
+
+D3DObjLevel6* CD3DEngine::AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type,
+ const D3DMATERIAL7 &mat, int state,
+ int nb)
+{
+ D3DObjLevel6* p6;
+ int l5;
+
+ if ( type == D3DTYPE6T )
+ {
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ if ( p6->type == type &&
+ memcmp(&p6->material, &mat, sizeof(D3DMATERIAL7)) == 0 &&
+ p6->state == state )
+ {
+ MemSpace6(p5->table[l5], nb);
+ return p5->table[l5];
+ }
+ }
+ }
+
+ MemSpace5(p5, 1);
+ l5 = p5->totalUsed++;
+ p5->table[l5] = 0;
+
+ MemSpace6(p5->table[l5], nb);
+ p5->table[l5]->type = type;
+ p5->table[l5]->material = mat;
+ p5->table[l5]->state = state;
+ return p5->table[l5];
+}
+
+// Adds one or more triangles to an existing object.
+// The number must be divisible by 3.
+
+BOOL CD3DEngine::AddTriangle(int objRank, D3DVERTEX2* vertex, int nb,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int i;
+
+ m_lastDim = m_dim;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+ p6 = AddLevel5(p5, D3DTYPE6T, mat, state, nb); // place for number of vertex
+
+ CopyMemory(&p6->vertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb);
+ p6->totalUsed += nb;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<nb ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += nb/3;
+
+ return TRUE;
+}
+
+// Adds a surface consisting of triangles joined.
+
+BOOL CD3DEngine::AddSurface(int objRank, D3DVERTEX2* vertex, int nb,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int i;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+ p6 = AddLevel5(p5, D3DTYPE6S, mat, state, nb); // place for number of vertex
+
+ CopyMemory(&p6->vertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb);
+ p6->totalUsed += nb;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<nb ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += nb-2;
+
+ return TRUE;
+}
+
+// Adds a surface consisting of triangles joined.
+// The buffer is not copied.
+
+BOOL CD3DEngine::AddQuick(int objRank, D3DObjLevel6* buffer,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ int l5, i;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+
+ MemSpace5(p5, 1);
+ l5 = p5->totalUsed++;
+ p5->table[l5] = buffer;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<buffer->totalUsed ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(buffer->vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(buffer->vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(buffer->vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(buffer->vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(buffer->vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(buffer->vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += buffer->totalUsed-2;
+
+ return TRUE;
+}
+
+
+// Looking for a list of triangles.
+
+void CD3DEngine::ChangeLOD()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ int l1, l2, l3;
+ float oldLimit[2], newLimit[2];
+ float oldTerrain, newTerrain;
+
+ oldLimit[0] = RetLimitLOD(0, TRUE);
+ oldLimit[1] = RetLimitLOD(1, TRUE);
+
+ newLimit[0] = RetLimitLOD(0, FALSE);
+ newLimit[1] = RetLimitLOD(1, FALSE);
+
+ oldTerrain = m_terrainVision*m_lastClippingDistance;
+ newTerrain = m_terrainVision*m_clippingDistance;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+
+ if ( IsEqual(p4->min, 0.0f ) &&
+ IsEqual(p4->max, oldLimit[0]) )
+ {
+ p4->max = newLimit[0];
+ }
+ else if ( IsEqual(p4->min, oldLimit[0]) &&
+ IsEqual(p4->max, oldLimit[1]) )
+ {
+ p4->min = newLimit[0];
+ p4->max = newLimit[1];
+ }
+ else if ( IsEqual(p4->min, oldLimit[1]) &&
+ IsEqual(p4->max, 1000000.0f ) )
+ {
+ p4->min = newLimit[1];
+ }
+ else if ( IsEqual(p4->min, 0.0f ) &&
+ IsEqual(p4->max, oldTerrain) )
+ {
+ p4->max = newTerrain;
+ }
+ }
+ }
+ }
+
+ m_lastDim = m_dim;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+}
+
+// Looking for a list of triangles.
+
+D3DObjLevel6* CD3DEngine::SearchTriangle(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+//? if ( strcmp(p2->texName1, texName1) != 0 ||
+//? strcmp(p2->texName2, texName2) != 0 ) continue;
+ if ( strcmp(p2->texName1, texName1) != 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != min ||
+ p4->max != max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+//? if ( p6->state != state ||
+ if ( (p6->state&(~(D3DSTATEDUALb|D3DSTATEDUALw))) != state ||
+ memcmp(&p6->material, &mat, sizeof(D3DMATERIAL7)) != 0 ) continue;
+ return p6;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// Secondary changes the texture of an object.
+
+BOOL CD3DEngine::ChangeSecondTexture(int objRank, char* texName2)
+{
+ D3DObjLevel2* newp2;
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ int l1, l2;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ if ( strcmp(p2->texName2, texName2) == 0 ) continue; // already new
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+
+ newp2 = AddLevel1(m_objectPointer, p2->texName1, texName2);
+
+ if ( newp2->totalUsed >= newp2->totalPossible ) continue; // to do better!!!
+ newp2->table[newp2->totalUsed++] = p3;
+
+ p2->table[l2] = 0;
+ }
+ }
+ return TRUE;
+}
+
+
+// Returns the number of triangles of the object.
+
+int CD3DEngine::RetTotalTriangles(int objRank)
+{
+ return m_objectParam[objRank].totalTriangle;
+}
+
+// Return qq triangles of an object.
+// qq triangles used to extract an object that explodes.
+// "Percent" is between 0 and 1.
+
+int CD3DEngine::GetTriangles(int objRank, float min, float max,
+ D3DTriangle* buffer, int size, float percent)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, l6, i, rank;
+
+ rank = 0;
+ i = 0;
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+//? if ( p2->texName[0] == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != min ||
+ p4->max != max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ for ( l6=0 ; l6<p6->totalUsed/3 ; l6++ )
+ {
+ if ( (float)i/rank <= percent )
+ {
+ if ( i >= size ) break;
+ buffer[i].triangle[0] = pv[0];
+ buffer[i].triangle[1] = pv[1];
+ buffer[i].triangle[2] = pv[2];
+ buffer[i].material = p6->material;
+ buffer[i].state = p6->state;
+ strcpy(buffer[i].texName1, p2->texName1);
+ strcpy(buffer[i].texName2, p2->texName2);
+ i ++;
+ }
+ rank ++;
+ pv += 3;
+ }
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ for ( l6=0 ; l6<p6->totalUsed-2 ; l6++ )
+ {
+ if ( (float)i/rank <= percent )
+ {
+ if ( i >= size ) break;
+ buffer[i].triangle[0] = pv[0];
+ buffer[i].triangle[1] = pv[1];
+ buffer[i].triangle[2] = pv[2];
+ buffer[i].material = p6->material;
+ buffer[i].state = p6->state;
+ strcpy(buffer[i].texName1, p2->texName1);
+ strcpy(buffer[i].texName2, p2->texName2);
+ i ++;
+ }
+ rank ++;
+ pv += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return i;
+}
+
+// Give the box of an object.
+
+BOOL CD3DEngine::GetBBox(int objRank, D3DVECTOR &min, D3DVECTOR &max)
+{
+ min = m_objectParam[objRank].bboxMin;
+ max = m_objectParam[objRank].bboxMax;
+ return TRUE;
+}
+
+
+// Change the texture mapping for a list of triangles.
+
+BOOL CD3DEngine::ChangeTextureMapping(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max,
+ D3DMaping mode,
+ float au, float bu,
+ float av, float bv)
+{
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l6, nb;
+
+ p6 = SearchTriangle(objRank, mat, state, texName1, texName2, min, max);
+ if ( p6 == 0 ) return FALSE;
+
+ pv = &p6->vertex[0];
+ nb = p6->totalUsed;
+
+ if ( mode == D3DMAPPINGX )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->z*au+bu;
+ pv->tv = pv->y*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPINGY )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv->tv = pv->z*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPINGZ )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv->tv = pv->y*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1X )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1Y )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tv = pv->y*au+bu;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1Z )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->z*au+bu;
+ pv ++;
+ }
+ }
+
+ return TRUE;
+}
+
+// Change the texture mapping for a list of triangles
+// to simulate a caterpillar that turns.
+// Only the mapping as "u" is changed.
+//
+// pos: position on the periphery [p]
+// tl: length repetitive element of the texture [t]
+// ts: beginning of the texture[t]
+// tt: total width of the texture [t]
+//
+// [p] = distance in the 3D world
+// [t] = position in the texture (pixels)
+
+// ^ y 5
+// | 6 o---------o 4
+// | / \
+// | o o
+// | 7 | | 3
+// | o current o
+// | \ | /
+// | 0 o---------o 2
+// | 1
+// -o-----------------------> x
+// |
+//
+// Quand l6=1 :
+// 0 1 2 3 4 ... 7
+// o--o---------o--o--o--o-//-o--o development track
+// |ps| |
+// <--> pe |
+// <------------>
+//
+// Texture :
+// o---------------o
+// | |
+// | o-o-o-o-o |
+// | | | | | |<--- texture of the track
+// | o-o-o-o-o |
+// | | | tl |
+// | ->|-|<--- |
+// | | |
+// o-----|---------o--> u
+// | ts | |
+// <-----> tt |
+// <--------------->
+
+BOOL CD3DEngine::TrackTextureMapping(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max,
+ D3DMaping mode, float pos, float factor,
+ float tl, float ts, float tt)
+{
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ D3DVECTOR current;
+ float ps, pe, pps, ppe, offset;
+ int l6, nb, i, j, s, e;
+ int is[6], ie[6];
+
+ p6 = SearchTriangle(objRank, mat, state, texName1, texName2, min, max);
+ if ( p6 == 0 ) return FALSE;
+
+ pv = &p6->vertex[0];
+ nb = p6->totalUsed;
+
+ if ( nb < 12 || nb%6 != 0 ) return FALSE;
+
+ while ( pos < 0.0f )
+ {
+ pos += 1000000.0f; // never negative!
+ }
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ for ( j=0 ; j<6 ; j++ )
+ {
+ if ( pv[i].x == pv[j+6].x &&
+ pv[i].y == pv[j+6].y )
+ {
+ current.x = pv[i].x; // position end link
+ current.y = pv[i].y;
+ break;
+ }
+ }
+ }
+
+ ps = 0.0f; // start position on the periphery
+ for ( l6=0 ; l6<nb/6 ; l6++ )
+ {
+ s = e = 0;
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( Abs(pv[i].x-current.x) < 0.0001f &&
+ Abs(pv[i].y-current.y) < 0.0001f )
+ {
+ ie[e++] = i;
+ }
+ else
+ {
+ is[s++] = i;
+ }
+ }
+ if ( s == 3 && e == 3 )
+ {
+ pe = ps+Length(pv[is[0]].x-pv[ie[0]].x,
+ pv[is[0]].y-pv[ie[0]].y)/factor; // end position on the periphery
+
+ pps = ps+pos;
+ ppe = pe+pos;
+ offset = (float)((int)pps);
+ pps -= offset;
+ ppe -= offset;
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ pv[is[i]].tu = ((pps*tl)+ts)/tt;
+ pv[ie[i]].tu = ((ppe*tl)+ts)/tt;
+ }
+ }
+
+ if ( l6 >= (nb/6)-1 ) break;
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( Abs(pv[i+6].x-current.x) > 0.0001f ||
+ Abs(pv[i+6].y-current.y) > 0.0001f )
+ {
+ current.x = pv[i+6].x; // end next link
+ current.y = pv[i+6].y;
+ break;
+ }
+ }
+ ps = pe; // following start position on the periphery
+ pv += 6;
+ }
+
+ return TRUE;
+}
+
+
+// Updates all the geometric parameters of objects.
+
+void CD3DEngine::UpdateGeometry()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, objRank, i;
+
+ if ( !m_bUpdateGeometry ) return;
+
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ m_objectParam[i].bboxMin.x = 0;
+ m_objectParam[i].bboxMin.y = 0;
+ m_objectParam[i].bboxMin.z = 0;
+ m_objectParam[i].bboxMax.x = 0;
+ m_objectParam[i].bboxMax.y = 0;
+ m_objectParam[i].bboxMax.z = 0;
+ m_objectParam[i].radius = 0;
+ }
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+
+ for ( i=0 ; i<p6->totalUsed ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(p6->vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(p6->vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(p6->vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(p6->vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(p6->vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(p6->vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ }
+ }
+ }
+ }
+
+ m_bUpdateGeometry = FALSE;
+}
+
+
+// Determines whether an object is visible, even partially.
+// Transformation of "world" must be done​​!
+
+BOOL CD3DEngine::IsVisible(int objRank)
+{
+ D3DVECTOR center;
+ DWORD flags;
+ float radius;
+
+ radius = m_objectParam[objRank].radius;
+ center = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_pD3DDevice->ComputeSphereVisibility(&center, &radius, 1, 0, &flags);
+
+ if ( flags & D3DSTATUS_CLIPINTERSECTIONALL )
+ {
+ m_objectParam[objRank].bVisible = FALSE;
+ return FALSE;
+ }
+ m_objectParam[objRank].bVisible = TRUE;
+ return TRUE;
+}
+
+
+// Detects the target object with the mouse.
+// Returns the rank of the object or -1.
+
+int CD3DEngine::DetectObject(FPOINT mouse)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, i, objRank, nearest;
+ float dist, min;
+
+ min = 1000000.0f;
+ nearest = -1;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !DetectBBox(objRank, mouse) ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != 0.0f ) continue; // LOD B or C?
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ for ( i=0 ; i<p6->totalUsed/3 ; i++ )
+ {
+ if ( DetectTriangle(mouse, pv, objRank, dist) &&
+ dist < min )
+ {
+ min = dist;
+ nearest = objRank;
+ }
+ pv += 3;
+ }
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ for ( i=0 ; i<p6->totalUsed-2 ; i++ )
+ {
+ if ( DetectTriangle(mouse, pv, objRank, dist) &&
+ dist < min )
+ {
+ min = dist;
+ nearest = objRank;
+ }
+ pv += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nearest;
+}
+
+// Detects whether the mouse is in a triangle.
+
+BOOL CD3DEngine::DetectTriangle(FPOINT mouse, D3DVERTEX2 *triangle,
+ int objRank, float &dist)
+{
+ D3DVECTOR p2D[3], p3D;
+ FPOINT a, b, c;
+ int i;
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ p3D.x = triangle[i].x;
+ p3D.y = triangle[i].y;
+ p3D.z = triangle[i].z;
+ if ( !TransformPoint(p2D[i], objRank, p3D) ) return FALSE;
+ }
+
+ if ( mouse.x < p2D[0].x &&
+ mouse.x < p2D[1].x &&
+ mouse.x < p2D[2].x ) return FALSE;
+ if ( mouse.x > p2D[0].x &&
+ mouse.x > p2D[1].x &&
+ mouse.x > p2D[2].x ) return FALSE;
+ if ( mouse.y < p2D[0].y &&
+ mouse.y < p2D[1].y &&
+ mouse.y < p2D[2].y ) return FALSE;
+ if ( mouse.y > p2D[0].y &&
+ mouse.y > p2D[1].y &&
+ mouse.y > p2D[2].y ) return FALSE;
+
+ a.x = p2D[0].x;
+ a.y = p2D[0].y;
+ b.x = p2D[1].x;
+ b.y = p2D[1].y;
+ c.x = p2D[2].x;
+ c.y = p2D[2].y;
+ if ( !IsInsideTriangle(a, b, c, mouse) ) return FALSE;
+
+ dist = (p2D[0].z+p2D[1].z+p2D[2].z)/3.0f;
+ return TRUE;
+}
+
+// Detects whether an object is affected by the mouse.
+
+BOOL CD3DEngine::DetectBBox(int objRank, FPOINT mouse)
+{
+ D3DVECTOR p, pp;
+ FPOINT min, max;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ if ( i & (1<<0) ) p.x = m_objectParam[objRank].bboxMin.x;
+ else p.x = m_objectParam[objRank].bboxMax.x;
+ if ( i & (1<<1) ) p.y = m_objectParam[objRank].bboxMin.y;
+ else p.y = m_objectParam[objRank].bboxMax.y;
+ if ( i & (1<<2) ) p.z = m_objectParam[objRank].bboxMin.z;
+ else p.z = m_objectParam[objRank].bboxMax.z;
+ if ( TransformPoint(pp, objRank, p) )
+ {
+ if ( pp.x < min.x ) min.x = pp.x;
+ if ( pp.x > max.x ) max.x = pp.x;
+ if ( pp.y < min.y ) min.y = pp.y;
+ if ( pp.y > max.y ) max.y = pp.y;
+ }
+ }
+
+ return ( mouse.x >= min.x &&
+ mouse.x <= max.x &&
+ mouse.y >= min.y &&
+ mouse.y <= max.y );
+}
+
+// Transforms a 3D point (x, y, z) in 2D space (x, y, -) of the window.
+// The coordinated p2D.z gives the distance.
+
+BOOL CD3DEngine::TransformPoint(D3DVECTOR &p2D, int objRank, D3DVECTOR p3D)
+{
+ p3D = Transform(m_objectParam[objRank].transform, p3D);
+ p3D = Transform(m_matView, p3D);
+
+ if ( p3D.z < 2.0f ) return FALSE; // behind?
+
+ p2D.x = (p3D.x/p3D.z)*m_matProj._11;
+ p2D.y = (p3D.y/p3D.z)*m_matProj._22;
+ p2D.z = p3D.z;
+
+ p2D.x = (p2D.x+1.0f)/2.0f; // [-1..1] -> [0..1]
+ p2D.y = (p2D.y+1.0f)/2.0f;
+
+ return TRUE;
+}
+
+
+// Calculating the distances between the viewpoint and the origin
+// of different objects.
+
+void CD3DEngine::ComputeDistance()
+{
+ D3DVECTOR v;
+ int i;
+ float distance;
+
+ if ( s_resol == 0 )
+ {
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE ) continue;
+
+ v.x = m_eyePt.x - m_objectParam[i].transform._41;
+ v.y = m_eyePt.y - m_objectParam[i].transform._42;
+ v.z = m_eyePt.z - m_objectParam[i].transform._43;
+ m_objectParam[i].distance = Length(v);
+ }
+ }
+ else
+ {
+ if ( s_resol == 1 )
+ {
+ distance = 100000.0f;
+ }
+ if ( s_resol == 2 )
+ {
+ distance = (RetLimitLOD(0)+RetLimitLOD(1))/2.0f;
+ }
+ if ( s_resol == 3 )
+ {
+ distance = 0.0f;
+ }
+
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE ) continue;
+
+ if ( m_objectParam[i].type == TYPETERRAIN )
+ {
+ v.x = m_eyePt.x - m_objectParam[i].transform._41;
+ v.y = m_eyePt.y - m_objectParam[i].transform._42;
+ v.z = m_eyePt.z - m_objectParam[i].transform._43;
+ m_objectParam[i].distance = Length(v);
+ }
+ else
+ {
+ m_objectParam[i].distance = distance;
+ }
+ }
+ }
+}
+
+
+// Adjusts settings when first run.
+
+void CD3DEngine::FirstExecuteAdapt(BOOL bFirst)
+{
+ if ( m_app->IsVideo8MB() )
+ {
+ SetGroundSpot(FALSE);
+ SetSkyMode(FALSE);
+ }
+
+ if ( m_app->IsVideo32MB() && bFirst )
+ {
+ SetObjectDetail(2.0f);
+ }
+}
+
+// Returns the total amount of video memory for textures.
+
+int CD3DEngine::GetVidMemTotal()
+{
+ return m_app->GetVidMemTotal();
+}
+
+BOOL CD3DEngine::IsVideo8MB()
+{
+ return m_app->IsVideo8MB();
+}
+
+BOOL CD3DEngine::IsVideo32MB()
+{
+ return m_app->IsVideo32MB();
+}
+
+
+// Perform the list of all graphics devices available.
+
+BOOL CD3DEngine::EnumDevices(char *bufDevices, int lenDevices,
+ char *bufModes, int lenModes,
+ int &totalDevices, int &selectDevices,
+ int &totalModes, int &selectModes)
+{
+ return m_app->EnumDevices(bufDevices, lenDevices,
+ bufModes, lenModes,
+ totalDevices, selectDevices,
+ totalModes, selectModes);
+}
+
+BOOL CD3DEngine::RetFullScreen()
+{
+ return m_app->RetFullScreen();
+}
+
+BOOL CD3DEngine::ChangeDevice(char *device, char *mode, BOOL bFull)
+{
+ return m_app->ChangeDevice(device, mode, bFull);
+}
+
+
+
+D3DMATRIX* CD3DEngine::RetMatView()
+{
+ return &m_matView;
+}
+
+D3DMATRIX* CD3DEngine::RetMatLeftView()
+{
+ return &m_matLeftView;
+}
+
+D3DMATRIX* CD3DEngine::RetMatRightView()
+{
+ return &m_matRightView;
+}
+
+
+// Specifies the location and direction of view.
+
+void CD3DEngine::SetViewParams(const D3DVECTOR &vEyePt,
+ const D3DVECTOR &vLookatPt,
+ const D3DVECTOR &vUpVec,
+ FLOAT fEyeDistance)
+{
+#if 0
+ m_eyePt = vEyePt;
+
+ // Adjust camera position for left or right eye along the axis
+ // perpendicular to the view direction vector and the up vector.
+ D3DVECTOR vView = (vLookatPt) - (vEyePt);
+ vView = CrossProduct( vView, (vUpVec) );
+ vView = Normalize( vView ) * fEyeDistance;
+
+ D3DVECTOR vLeftEyePt = (vEyePt) + vView;
+ D3DVECTOR vRightEyePt = (vEyePt) - vView;
+
+ // Set the view matrices
+ D3DUtil_SetViewMatrix( m_matLeftView, (D3DVECTOR)vLeftEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+ D3DUtil_SetViewMatrix( m_matRightView, (D3DVECTOR)vRightEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+ D3DUtil_SetViewMatrix( m_matView, (D3DVECTOR)vEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+#else
+ m_eyePt = vEyePt;
+ m_lookatPt = vLookatPt;
+ m_eyeDirH = RotateAngle(vEyePt.x-vLookatPt.x, vEyePt.z-vLookatPt.z);
+ m_eyeDirV = RotateAngle(Length2d(vEyePt, vLookatPt), vEyePt.y-vLookatPt.y);
+
+ D3DUtil_SetViewMatrix(m_matView, (D3DVECTOR&)vEyePt, (D3DVECTOR&)vLookatPt, (D3DVECTOR&)vUpVec);
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+ m_sound->SetListener(vEyePt, vLookatPt);
+#endif
+}
+
+
+// Specifies the transformation matrix of an object.
+
+BOOL CD3DEngine::SetObjectTransform(int objRank, const D3DMATRIX &transform)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].transform = transform;
+ return TRUE;
+}
+
+// Gives the transformation matrix of an object.
+
+BOOL CD3DEngine::GetObjectTransform(int objRank, D3DMATRIX &transform)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ transform = m_objectParam[objRank].transform;
+ return TRUE;
+}
+
+// Specifies the type of an object.
+
+BOOL CD3DEngine::SetObjectType(int objRank, D3DTypeObj type)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].type = type;
+ return TRUE;
+}
+
+// Returns the type of an object.
+
+D3DTypeObj CD3DEngine::RetObjectType(int objRank)
+{
+ return m_objectParam[objRank].type;
+}
+
+// Specifies the transparency of an object.
+
+BOOL CD3DEngine::SetObjectTransparency(int objRank, float value)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].transparency = value;
+ return TRUE;
+}
+
+
+// Allocates a table for shade, if necessary.
+
+BOOL CD3DEngine::ShadowCreate(int objRank)
+{
+ int i;
+
+ // Already allocated?
+ if ( m_objectParam[objRank].shadowRank != -1 ) return TRUE;
+
+ for ( i=0 ; i<D3DMAXSHADOW ; i++ )
+ {
+ if ( m_shadow[i].bUsed == FALSE ) // Free?
+ {
+ ZeroMemory(&m_shadow[i], sizeof(D3DShadow));
+
+ m_shadow[i].bUsed = TRUE;
+ m_shadow[i].objRank = objRank;
+ m_shadow[i].height = 0.0f;
+
+ m_objectParam[objRank].shadowRank = i;
+
+ if ( m_shadowTotal < i+1 )
+ {
+ m_shadowTotal = i+1;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE; // not found
+}
+
+// Removes the shadow associated with an object.
+
+void CD3DEngine::ShadowDelete(int objRank)
+{
+ int i;
+
+ if ( objRank == -1 ) return;
+
+ i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return;
+
+ m_shadow[i].bUsed = FALSE;
+ m_shadow[i].objRank = -1;
+ m_shadow[i].pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_shadow[i].type = D3DSHADOWNORM;
+
+ m_objectParam[objRank].shadowRank = -1;
+
+ m_shadowTotal = 0;
+ for ( i=0 ; i<D3DMAXSHADOW ; i++ )
+ {
+ if ( m_shadow[i].bUsed ) m_shadowTotal = i+1;
+ }
+}
+
+// Specifies if the shadow is visible.
+// For example, when an object is carried, he has no shadow.
+
+BOOL CD3DEngine::SetObjectShadowHide(int objRank, BOOL bHide)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].bHide = bHide;
+ return TRUE;
+}
+
+// Specifies the type of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowType(int objRank, D3DShadowType type)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].type = type;
+ return TRUE;
+}
+
+// Specifies the position of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowPos(int objRank, const D3DVECTOR &pos)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].pos = pos;
+ return TRUE;
+}
+
+// Specifies the normal shadow to the field of the object.
+
+BOOL CD3DEngine::SetObjectShadowNormal(int objRank, const D3DVECTOR &n)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].normal = n;
+ return TRUE;
+}
+
+// Specifies the angle of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowAngle(int objRank, float angle)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].angle = angle;
+ return TRUE;
+}
+
+// Specifies the radius of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowRadius(int objRank, float radius)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].radius = radius;
+ return TRUE;
+}
+
+// Returns the radius of the shadow of the object.
+
+float CD3DEngine::RetObjectShadowRadius(int objRank)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return 0.0f;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ return m_shadow[i].radius;
+}
+
+// Specifies the intensity of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowIntensity(int objRank, float intensity)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].intensity = intensity;
+ return TRUE;
+}
+
+// Specifies the height of the shadow of the object.
+
+BOOL CD3DEngine::SetObjectShadowHeight(int objRank, float h)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].height = h;
+ return TRUE;
+}
+
+
+// Clears all marks on the ground.
+
+void CD3DEngine::GroundSpotFlush()
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ WORD* pbSurf;
+ char texName[20];
+ int s, y;
+
+ ZeroMemory(m_groundSpot, sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+ m_bFirstGroundSpot = TRUE; // drawing power first
+
+ for ( s=0 ; s<16 ; s++ )
+ {
+ sprintf(texName, "shadow%.2d.tga", s);
+ surface = D3DTextr_GetSurface(texName);
+ if ( surface == 0 ) continue;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) continue;
+
+ if ( ddsd.ddpfPixelFormat.dwRGBBitCount != 16 ) continue;
+
+ for ( y=0 ; y<(int)ddsd.dwHeight ; y++ )
+ {
+ pbSurf = (WORD*)ddsd.lpSurface;
+ pbSurf += ddsd.lPitch*y/2;
+ memset(pbSurf, -1, ddsd.lPitch); // all blank
+ }
+
+ surface->Unlock(NULL);
+ }
+}
+
+// Allocates a table for a mark on the ground, if necessary.
+
+int CD3DEngine::GroundSpotCreate()
+{
+ int i;
+
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ) // free?
+ {
+ ZeroMemory(&m_groundSpot[i], sizeof(D3DGroundSpot));
+ m_groundSpot[i].bUsed = TRUE;
+ m_groundSpot[i].smooth = 1.0f;
+ return i;
+ }
+ }
+ return -1; // not found
+}
+
+// Removes a mark on the ground.
+
+void CD3DEngine::GroundSpotDelete(int rank)
+{
+ m_groundSpot[rank].bUsed = FALSE;
+ m_groundSpot[rank].pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+// Specifies the position of surface marking of the object.
+
+BOOL CD3DEngine::SetObjectGroundSpotPos(int rank, const D3DVECTOR &pos)
+{
+ m_groundSpot[rank].pos = pos;
+ return TRUE;
+}
+
+// Specifies the radius of surface marking of the object.
+
+BOOL CD3DEngine::SetObjectGroundSpotRadius(int rank, float radius)
+{
+ m_groundSpot[rank].radius = radius;
+ return TRUE;
+}
+
+// Specifies the color of a mark on the ground.
+
+BOOL CD3DEngine::SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color)
+{
+ m_groundSpot[rank].color = color;
+ return TRUE;
+}
+
+// Specifies the height min / max.
+
+BOOL CD3DEngine::SetObjectGroundSpotMinMax(int rank, float min, float max)
+{
+ m_groundSpot[rank].min = min;
+ m_groundSpot[rank].max = max;
+ return TRUE;
+}
+
+// Specifies the transition factor.
+
+BOOL CD3DEngine::SetObjectGroundSpotSmooth(int rank, float smooth)
+{
+ m_groundSpot[rank].smooth = smooth;
+ return TRUE;
+}
+
+
+// Creates ground marks.
+
+int CD3DEngine::GroundMarkCreate(D3DVECTOR pos, float radius,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table)
+{
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+ m_groundMark.bUsed = TRUE;
+ m_groundMark.phase = 1;
+ m_groundMark.delay[0] = delay1;
+ m_groundMark.delay[1] = delay2;
+ m_groundMark.delay[2] = delay3;
+ m_groundMark.pos = pos;
+ m_groundMark.radius = radius;
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.dx = dx;
+ m_groundMark.dy = dy;
+ m_groundMark.table = table;
+ return 0;
+}
+
+// Clears the ground.
+
+BOOL CD3DEngine::GroundMarkDelete(int rank)
+{
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+ return TRUE;
+}
+
+
+// Border management (distance limits) depends of the resolution.
+// LOD = level-of-detail.
+
+void CD3DEngine::SetLimitLOD(int rank, float limit)
+{
+ m_limitLOD[rank] = limit;
+}
+
+float CD3DEngine::RetLimitLOD(int rank, BOOL bLast)
+{
+ float limit;
+
+ if ( bLast )
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_lastDim.x/640.0f; // limit further if large window!
+//? limit += m_limitLOD[0]*(m_lastObjectDetail*2.0f-1.0f);
+ limit += m_limitLOD[0]*(m_lastObjectDetail*2.0f);
+ }
+ else
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_dim.x/640.0f; // limit further if large window!
+//? limit += m_limitLOD[0]*(m_objectDetail*2.0f-1.0f);
+ limit += m_limitLOD[0]*(m_objectDetail*2.0f);
+ }
+ if ( limit < 0.0f ) limit = 0.0f;
+
+ return limit;
+}
+
+
+// Definition of the distance field of vision.
+
+void CD3DEngine::SetTerrainVision(float vision)
+{
+ m_terrainVision = vision;
+}
+
+
+// Management of the global mode of shading.
+
+void CD3DEngine::SetShadow(BOOL bMode)
+{
+ m_bShadow = bMode;
+}
+
+BOOL CD3DEngine::RetShadow()
+{
+ return m_bShadow;
+}
+
+
+// Management of the global mode of marking.
+
+void CD3DEngine::SetGroundSpot(BOOL bMode)
+{
+ m_bGroundSpot = bMode;
+}
+
+BOOL CD3DEngine::RetGroundSpot()
+{
+ return m_bGroundSpot;
+}
+
+
+// Management of the global mode of contamination.
+
+void CD3DEngine::SetDirty(BOOL bMode)
+{
+ m_bDirty = bMode;
+}
+
+BOOL CD3DEngine::RetDirty()
+{
+ return m_bDirty;
+}
+
+
+// Management of the global mode of horizontal fog patches.
+
+void CD3DEngine::SetFog(BOOL bMode)
+{
+ m_bFog = bMode;
+}
+
+BOOL CD3DEngine::RetFog()
+{
+ return m_bFog;
+}
+
+
+// ndicates whether it is possible to give a color SetState.
+
+BOOL CD3DEngine::RetStateColor()
+{
+ return m_bStateColor;
+}
+
+
+// Management of the global mode of secondary texturing.
+
+void CD3DEngine::SetSecondTexture(int texNum)
+{
+ m_secondTexNum = texNum;
+}
+
+int CD3DEngine::RetSecondTexture()
+{
+ return m_secondTexNum;
+}
+
+
+// Choice of the rank of the active view.
+
+void CD3DEngine::SetRankView(int rank)
+{
+ if ( rank < 0 ) rank = 0;
+ if ( rank > 1 ) rank = 1;
+
+ if ( m_rankView == 0 && rank == 1 ) // enters the water?
+ {
+ m_light->AdaptLightColor(m_waterAddColor, +1.0f);
+ }
+
+ if ( m_rankView == 1 && rank == 0 ) // out of the water?
+ {
+ m_light->AdaptLightColor(m_waterAddColor, -1.0f);
+ }
+
+ m_rankView = rank;
+}
+
+int CD3DEngine::RetRankView()
+{
+ return m_rankView;
+}
+
+// Whether to draw the world from the interface.
+
+void CD3DEngine::SetDrawWorld(BOOL bDraw)
+{
+ m_bDrawWorld = bDraw;
+}
+
+// Whether to draw the world on the interface.
+
+void CD3DEngine::SetDrawFront(BOOL bDraw)
+{
+ m_bDrawFront = bDraw;
+}
+
+// Color management ambient.
+// color = 0x00rrggbb
+// rr: red
+// gg: green
+// bb: blue
+
+void CD3DEngine::SetAmbiantColor(D3DCOLOR color, int rank)
+{
+ m_ambiantColor[rank] = color;
+}
+
+D3DCOLOR CD3DEngine::RetAmbiantColor(int rank)
+{
+ return m_ambiantColor[rank];
+}
+
+
+// Color management under water.
+
+void CD3DEngine::SetWaterAddColor(D3DCOLORVALUE color)
+{
+ m_waterAddColor = color;
+}
+
+D3DCOLORVALUE CD3DEngine::RetWaterAddColor()
+{
+ return m_waterAddColor;
+}
+
+
+// Management of the fog color.
+
+void CD3DEngine::SetFogColor(D3DCOLOR color, int rank)
+{
+ m_fogColor[rank] = color;
+}
+
+D3DCOLOR CD3DEngine::RetFogColor(int rank)
+{
+ return m_fogColor[rank];
+}
+
+
+// Management of the depth of field.
+// Beyond this distance, nothing is visible.
+// Shortly (according SetFogStart), one enters the fog.
+
+void CD3DEngine::SetDeepView(float length, int rank, BOOL bRef)
+{
+ if ( bRef )
+ {
+ length *= m_clippingDistance;
+ }
+
+ m_deepView[rank] = length;
+}
+
+float CD3DEngine::RetDeepView(int rank)
+{
+ return m_deepView[rank];
+}
+
+
+// Management the start of fog.
+// With 0.0, the fog from the point of view (fog max).
+// With 1.0, the fog from the depth of field (no fog).
+
+void CD3DEngine::SetFogStart(float start, int rank)
+{
+ m_fogStart[rank] = start;
+}
+
+float CD3DEngine::RetFogStart(int rank)
+{
+ return m_fogStart[rank];
+}
+
+
+// Gives the background image to use.
+
+void CD3DEngine::SetBackground(char *name, D3DCOLOR up, D3DCOLOR down,
+ D3DCOLOR cloudUp, D3DCOLOR cloudDown,
+ BOOL bFull, BOOL bQuarter)
+{
+ strcpy(m_backgroundName, name);
+ m_backgroundColorUp = up;
+ m_backgroundColorDown = down;
+ m_backgroundCloudUp = cloudUp;
+ m_backgroundCloudDown = cloudDown;
+ m_bBackgroundFull = bFull;
+ m_bBackgroundQuarter = bQuarter;
+}
+
+// Gives the background image used.
+
+void CD3DEngine::RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down,
+ D3DCOLOR &cloudUp, D3DCOLOR &cloudDown,
+ BOOL &bFull, BOOL &bQuarter)
+{
+ strcpy(name, m_backgroundName);
+ up = m_backgroundColorUp;
+ down = m_backgroundColorDown;
+ cloudUp = m_backgroundCloudUp;
+ cloudDown = m_backgroundCloudDown;
+ bFull = m_bBackgroundFull;
+ bQuarter = m_bBackgroundQuarter;
+}
+
+// Gives the foreground image to use.
+
+void CD3DEngine::SetFrontsizeName(char *name)
+{
+ if ( m_frontsizeName[0] != 0 )
+ {
+ FreeTexture(m_frontsizeName);
+ }
+
+ strcpy(m_frontsizeName, name);
+}
+
+// Specifies whether to draw the foreground.
+
+void CD3DEngine::SetOverFront(BOOL bFront)
+{
+ m_bOverFront = bFront;
+}
+
+// Gives color to the foreground.
+
+void CD3DEngine::SetOverColor(D3DCOLOR color, int mode)
+{
+ m_overColor = color;
+ m_overMode = mode;
+}
+
+
+
+// Management of the particle density.
+
+void CD3DEngine::SetParticuleDensity(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_particuleDensity = value;
+}
+
+float CD3DEngine::RetParticuleDensity()
+{
+ return m_particuleDensity;
+}
+
+float CD3DEngine::ParticuleAdapt(float factor)
+{
+ if ( m_particuleDensity == 0.0f )
+ {
+ return 1000000.0f;
+ }
+ return factor/m_particuleDensity;
+}
+
+// Management of the distance of clipping.
+
+void CD3DEngine::SetClippingDistance(float value)
+{
+ if ( value < 0.5f ) value = 0.5f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_clippingDistance = value;
+}
+
+float CD3DEngine::RetClippingDistance()
+{
+ return m_clippingDistance;
+}
+
+// Management of objects detals.
+
+void CD3DEngine::SetObjectDetail(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_objectDetail = value;
+}
+
+float CD3DEngine::RetObjectDetail()
+{
+ return m_objectDetail;
+}
+
+// The amount of management objects gadgets.
+
+void CD3DEngine::SetGadgetQuantity(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+
+ m_gadgetQuantity = value;
+}
+
+float CD3DEngine::RetGadgetQuantity()
+{
+ return m_gadgetQuantity;
+}
+
+// Managing the quality of textures.
+
+void CD3DEngine::SetTextureQuality(int value)
+{
+ if ( value < 0 ) value = 0;
+ if ( value > 2 ) value = 2;
+
+ if ( value != m_textureQuality )
+ {
+ m_textureQuality = value;
+ LoadAllTexture();
+ }
+}
+
+int CD3DEngine::RetTextureQuality()
+{
+ return m_textureQuality;
+}
+
+
+// Management mode of toto.
+
+void CD3DEngine::SetTotoMode(BOOL bPresent)
+{
+ m_bTotoMode = bPresent;
+}
+
+BOOL CD3DEngine::RetTotoMode()
+{
+ return m_bTotoMode;
+}
+
+
+// Managing the mode of foreground.
+
+void CD3DEngine::SetLensMode(BOOL bPresent)
+{
+ m_bLensMode = bPresent;
+}
+
+BOOL CD3DEngine::RetLensMode()
+{
+ return m_bLensMode;
+}
+
+
+// Managing the mode of water.
+
+void CD3DEngine::SetWaterMode(BOOL bPresent)
+{
+ m_bWaterMode = bPresent;
+}
+
+BOOL CD3DEngine::RetWaterMode()
+{
+ return m_bWaterMode;
+}
+
+
+// Managing the mode of sky.
+
+void CD3DEngine::SetSkyMode(BOOL bPresent)
+{
+ m_bSkyMode = bPresent;
+}
+
+BOOL CD3DEngine::RetSkyMode()
+{
+ return m_bSkyMode;
+}
+
+
+// Managing the mode of background.
+
+void CD3DEngine::SetBackForce(BOOL bPresent)
+{
+ m_bBackForce = bPresent;
+}
+
+BOOL CD3DEngine::RetBackForce()
+{
+ return m_bBackForce;
+}
+
+
+// Managing the mode of planets.
+
+void CD3DEngine::SetPlanetMode(BOOL bPresent)
+{
+ m_bPlanetMode = bPresent;
+}
+
+BOOL CD3DEngine::RetPlanetMode()
+{
+ return m_bPlanetMode;
+}
+
+
+// Managing the mode of dymanic lights.
+
+void CD3DEngine::SetLightMode(BOOL bPresent)
+{
+ m_bLightMode = bPresent;
+}
+
+BOOL CD3DEngine::RetLightMode()
+{
+ return m_bLightMode;
+}
+
+
+// Management of the indentation mode while editing (CEdit).
+
+void CD3DEngine::SetEditIndentMode(BOOL bAuto)
+{
+ m_bEditIndentMode = bAuto;
+}
+
+BOOL CD3DEngine::RetEditIndentMode()
+{
+ return m_bEditIndentMode;
+}
+
+
+// Management in advance of a tab when editing (CEdit).
+
+void CD3DEngine::SetEditIndentValue(int value)
+{
+ m_editIndentValue = value;
+}
+
+int CD3DEngine::RetEditIndentValue()
+{
+ return m_editIndentValue;
+}
+
+
+void CD3DEngine::SetSpeed(float speed)
+{
+ m_speed = speed;
+}
+
+float CD3DEngine::RetSpeed()
+{
+ return m_speed;
+}
+
+
+void CD3DEngine::SetTracePrecision(float factor)
+{
+ m_tracePrecision = factor;
+}
+
+float CD3DEngine::RetTracePrecision()
+{
+ return m_tracePrecision;
+}
+
+
+// Updates the scene after a change of parameters.
+
+void CD3DEngine::ApplyChange()
+{
+ m_deepView[0] /= m_lastClippingDistance;
+ m_deepView[1] /= m_lastClippingDistance;
+
+ SetFocus(m_focus);
+ ChangeLOD();
+
+ m_deepView[0] *= m_clippingDistance;
+ m_deepView[1] *= m_clippingDistance;
+}
+
+
+
+// Returns the point of view of the user.
+
+D3DVECTOR CD3DEngine::RetEyePt()
+{
+ return m_eyePt;
+}
+
+D3DVECTOR CD3DEngine::RetLookatPt()
+{
+ return m_lookatPt;
+}
+
+float CD3DEngine::RetEyeDirH()
+{
+ return m_eyeDirH;
+}
+
+float CD3DEngine::RetEyeDirV()
+{
+ return m_eyeDirV;
+}
+
+POINT CD3DEngine::RetDim()
+{
+ return m_dim;
+}
+
+
+// Generates an image name of the watch.
+
+void QuarterName(char *buffer, char *name, int quarter)
+{
+ while ( *name != 0 )
+ {
+ if ( *name == '.' )
+ {
+ *buffer++ = 'a'+quarter;
+ }
+ *buffer++ = *name++;
+ }
+ *buffer++ = 0;
+}
+
+// Frees texture.
+
+BOOL CD3DEngine::FreeTexture(char* name)
+{
+ if ( name[0] == 0 ) return TRUE;
+
+ if ( D3DTextr_DestroyTexture(name) != S_OK )
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// Load a texture.
+
+BOOL CD3DEngine::LoadTexture(char* name, int stage)
+{
+ DWORD mode;
+
+ if ( name[0] == 0 ) return TRUE;
+
+ if ( D3DTextr_GetSurface(name) == NULL )
+ {
+ if ( strstr(name, ".tga") == 0 )
+ {
+ mode = 0;
+ }
+ else
+ {
+ mode = D3DTEXTR_CREATEWITHALPHA;
+ }
+
+ if ( D3DTextr_CreateTextureFromFile(name, stage, mode) != S_OK )
+ {
+ return FALSE;
+ }
+
+ if ( D3DTextr_Restore(name, m_pD3DDevice) != S_OK )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// Load all the textures of the scene.
+
+BOOL CD3DEngine::LoadAllTexture()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ int l1, i;
+ char name[50];
+ BOOL bOK = TRUE;
+
+#if _POLISH
+ LoadTexture("textp.tga");
+#else
+ LoadTexture("text.tga");
+#endif
+ LoadTexture("mouse.tga");
+ LoadTexture("button1.tga");
+ LoadTexture("button2.tga");
+ LoadTexture("button3.tga");
+ LoadTexture("effect00.tga");
+ LoadTexture("effect01.tga");
+ LoadTexture("effect02.tga");
+ LoadTexture("map.tga");
+
+ if ( m_backgroundName[0] != 0 )
+ {
+ if ( m_bBackgroundQuarter ) // image into 4 pieces?
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ QuarterName(name, m_backgroundName, i);
+ LoadTexture(name);
+ }
+ }
+ else
+ {
+ LoadTexture(m_backgroundName);
+ }
+ }
+ if ( m_frontsizeName[0] != 0 )
+ {
+ LoadTexture(m_frontsizeName);
+ }
+
+ m_planet->LoadTexture();
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+
+ if ( p2 == 0 || p2->texName1[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName1, 0) ) bOK = FALSE;
+ }
+
+ if ( p2 == 0 || p2->texName2[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName2, 1) ) bOK = FALSE;
+ }
+ }
+ return bOK;
+}
+
+
+// Called during initial app startup, this function performs all the
+// permanent initialization.
+
+HRESULT CD3DEngine::OneTimeSceneInit()
+{
+ return S_OK;
+}
+
+
+// Updated after creating objects.
+
+void CD3DEngine::Update()
+{
+ ComputeDistance();
+ UpdateGeometry();
+}
+
+// Called once per frame, the call is the entry point for animating
+// the scene.
+
+HRESULT CD3DEngine::FrameMove(float rTime)
+{
+ m_light->FrameLight(rTime);
+ m_particule->FrameParticule(rTime);
+ ComputeDistance();
+ UpdateGeometry();
+
+ if ( m_groundMark.bUsed )
+ {
+ if ( m_groundMark.phase == 1 ) // growing?
+ {
+ m_groundMark.intensity += rTime*(1.0f/m_groundMark.delay[0]);
+ if ( m_groundMark.intensity >= 1.0f )
+ {
+ m_groundMark.intensity = 1.0f;
+ m_groundMark.fix = 0.0f;
+ m_groundMark.phase = 2;
+ }
+ }
+ else if ( m_groundMark.phase == 2 ) // fixed?
+ {
+ m_groundMark.fix += rTime*(1.0f/m_groundMark.delay[1]);
+ if ( m_groundMark.fix >= 1.0f )
+ {
+ m_groundMark.phase = 3;
+ }
+ }
+ else if ( m_groundMark.phase == 3 ) // decay?
+ {
+ m_groundMark.intensity -= rTime*(1.0f/m_groundMark.delay[2]);
+ if ( m_groundMark.intensity < 0.0f )
+ {
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.phase = 0;
+ m_groundMark.bUsed = FALSE;
+ }
+ }
+ }
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+ m_sound->FrameMove(rTime);
+
+ return S_OK;
+}
+
+// Evolved throughout the game
+
+void CD3DEngine::StepSimul(float rTime)
+{
+ m_app->StepSimul(rTime);
+}
+
+
+
+// Changes the state associated with a material.
+// (*) Does not work without this instruction, mystery!
+
+void CD3DEngine::SetState(int state, D3DCOLOR color)
+{
+ BOOL bSecond;
+
+ if ( state == m_lastState &&
+ color == m_lastColor ) return;
+ m_lastState = state;
+ m_lastColor = color;
+
+ if ( m_alphaMode != 1 && (state & D3DSTATEALPHA) )
+ {
+ state &= ~D3DSTATEALPHA;
+
+ if ( m_alphaMode == 2 )
+ {
+ state |= D3DSTATETTb;
+ }
+ }
+
+ if ( state & D3DSTATETTb ) // The transparent black texture?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_blackSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_blackDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend2]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); // (*)
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETTw ) // The transparent white texture?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_whiteSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_whiteDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend3]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend4]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, ~color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); // (*)
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETCb ) // The transparent black color?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_blackSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_blackDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend2]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETCw ) // The transparent white color?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_whiteSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_whiteDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend3]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend4]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, ~color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETD ) // diffuse color as transparent?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_diffuseSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_diffuseDestBlend[1]);
+
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATEALPHA ) // image with alpha channel?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)(128));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_alphaSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_alphaSrcBlend[1]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ }
+ else // normal ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+
+ if ( state & D3DSTATEFOG )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ }
+
+ bSecond = m_bGroundSpot|m_bDirty;
+ if ( !m_bGroundSpot && (state & D3DSTATESECOND) != 0 ) bSecond = FALSE;
+ if ( !m_bDirty && (state & D3DSTATESECOND) == 0 ) bSecond = FALSE;
+
+ if ( (state & D3DSTATEDUALb) && bSecond )
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
+ }
+ else if ( (state & D3DSTATEDUALw) && bSecond )
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
+ }
+ else
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+
+ if ( state & D3DSTATEWRAP )
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, D3DWRAP_U|D3DWRAP_V);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
+ }
+ else if ( state & D3DSTATECLAMP )
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, 0);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ }
+ else
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, 0);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ }
+
+ if ( state & D3DSTATE2FACE )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
+ }
+ else
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
+ }
+
+ if ( state & D3DSTATELIGHT )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ }
+ else
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, m_ambiantColor[m_rankView]);
+ }
+}
+
+// Specifies a texture to use.
+
+void CD3DEngine::SetTexture(char *name, int stage)
+{
+//? if ( stage == 1 && !m_bDirty ) return;
+//? if ( stage == 1 && !m_bShadow ) return;
+
+ if ( strcmp(name, m_lastTexture[stage]) == 0 ) return;
+ strcpy(m_lastTexture[stage], name);
+
+ m_pD3DDevice->SetTexture(stage, D3DTextr_GetSurface(name));
+}
+
+// Specifies the material to use.
+
+void CD3DEngine::SetMaterial(const D3DMATERIAL7 &mat)
+{
+ if ( memcmp(&mat, &m_lastMaterial, sizeof(D3DMATERIAL7)) == 0 ) return;
+ m_lastMaterial = mat;
+
+ m_pD3DDevice->SetMaterial(&m_lastMaterial);
+}
+
+
+// Deletes a point in a surface (draw in white).
+
+inline void ClearDot(DDSURFACEDESC2* ddsd, int x, int y)
+{
+ WORD* pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount != 16 ) return;
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = 0xffff; // white
+}
+
+// Deletes a point in a surface (draw in white)
+
+void AddDot(DDSURFACEDESC2* ddsd, int x, int y, D3DCOLORVALUE color)
+{
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount != 16 ) return;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ r = (int)(color.r*32.0f);
+ if ( r >= 32 ) r = 31; // 5 bits
+
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ g = (int)(color.g*32.0f);
+ if ( g >= 32 ) g = 31; // 5 bits
+
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+ b = (int)(color.b*32.0f);
+ if ( b >= 32 ) b = 31; // 5 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blank
+ }
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf &= w;
+}
+
+// Displays a point in a surface.
+
+void SetDot(DDSURFACEDESC2* ddsd, int x, int y, D3DCOLORVALUE color)
+{
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*32.0f);
+ g = (int)(color.g*32.0f);
+ b = (int)(color.b*32.0f);
+
+ if ( r >= 32 ) r = 31; // 5 bits
+ if ( g >= 32 ) g = 31; // 5 bits
+ if ( b >= 32 ) b = 31; // 5 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blank
+ }
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = w;
+ }
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 32 ) // image .tga ?
+ {
+ LONG* pbSurf;
+ LONG r,g,b, w;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*256.0f);
+ g = (int)(color.g*256.0f);
+ b = (int)(color.b*256.0f);
+
+ if ( r >= 256 ) r = 255; // 8 bits
+ if ( g >= 256 ) g = 255; // 8 bits
+ if ( b >= 256 ) b = 255; // 8 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xff0000 )
+ {
+ w = (r<<16)|(g<<8)|b;
+
+ pbSurf = (LONG*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/4;
+ pbSurf += x;
+
+ *pbSurf &= 0xff000000; // keeps alpha channel
+ *pbSurf |= w;
+ }
+ }
+}
+
+// Gives a point in a surface.
+
+D3DCOLORVALUE GetDot(DDSURFACEDESC2* ddsd, int x, int y)
+{
+ D3DCOLORVALUE color;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ w = *pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ r = (w>>10)&0x003e;
+ g = (w>> 5)&0x003f;
+ b = (w<< 1)&0x003e;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ r = (w>> 9)&0x003e;
+ g = (w>> 4)&0x003e;
+ b = (w<< 1)&0x003e;
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0; // black
+ }
+
+ color.r = (float)r/63.0f;
+ color.g = (float)g/63.0f;
+ color.b = (float)b/63.0f;
+ color.a = 0.0f;
+ return color;
+ }
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 32 ) // image .tga ?
+ {
+ LONG* pbSurf;
+ LONG r,g,b, w;
+
+ pbSurf = (LONG*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/4;
+ pbSurf += x;
+
+ w = *pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xff0000 )
+ {
+ r = (w>>16)&0x00ff;
+ g = (w>> 8)&0x00ff;
+ b = (w<< 0)&0x00ff;
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0; // black
+ }
+
+ color.r = (float)r/255.0f;
+ color.g = (float)g/255.0f;
+ color.b = (float)b/255.0f;
+ color.a = 0.0f;
+ return color;
+ }
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 0.0f; // black
+ return color;
+}
+
+// Draw all the shadows.
+
+// There is a pixel collection around each of the 16 surfaces:
+//
+// |<----------------------->|<----------------------->|<---- ...
+// 0 | 1 2 253 254|255 |
+// |---|---|---|-- ... --|---|---|---| |
+// 0 | 1 2 253 254|255
+// |---|---|---|-- ... --|---|---|---|
+//
+// So we draw in 254x254 pixels surfaces.
+// The pixel margin around it is drawn twice (in two adjacent surfaces),
+// so that the filter produces the same results!
+
+void CD3DEngine::RenderGroundSpot()
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ WORD* pbSurf;
+ D3DCOLORVALUE color;
+ D3DVECTOR pos;
+ FPOINT min, max;
+ int s, i, j, dot, ix, iy, y;
+ float tu, tv, cx, cy, px, py, ppx, ppy;
+ float intensity, level;
+ char texName[20];
+ BOOL bClear, bSet;
+
+ if ( !m_bFirstGroundSpot &&
+ m_groundMark.drawPos.x == m_groundMark.pos.x &&
+ m_groundMark.drawPos.z == m_groundMark.pos.z &&
+ m_groundMark.drawRadius == m_groundMark.radius &&
+ m_groundMark.drawIntensity == m_groundMark.intensity ) return;
+
+ for ( s=0 ; s<16 ; s++ )
+ {
+ min.x = (s%4)*254.0f-1.0f; // 1 pixel cover
+ min.y = (s/4)*254.0f-1.0f;
+ max.x = min.x+254.0f+2.0f;
+ max.y = min.y+254.0f+2.0f;
+
+ bClear = FALSE;
+ bSet = FALSE;
+
+ // Calculate the area to be erased.
+ dot = (int)(m_groundMark.drawRadius/2.0f);
+
+ tu = (m_groundMark.drawPos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.drawPos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple of 1
+
+ if ( m_bFirstGroundSpot ||
+ ( m_groundMark.drawRadius != 0.0f &&
+ px+dot >= min.x && py+dot >= min.y &&
+ px-dot <= max.x && py-dot <= max.y ) )
+ {
+ bClear = TRUE;
+ }
+
+ // Calculate the area to draw.
+ dot = (int)(m_groundMark.radius/2.0f);
+
+ tu = (m_groundMark.pos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple of 1
+
+ if ( m_groundMark.bUsed &&
+ px+dot >= min.x && py+dot >= min.y &&
+ px-dot <= max.x && py-dot <= max.y )
+ {
+ bSet = TRUE;
+ }
+
+ if ( bClear || bSet )
+ {
+ // Load the song.
+ sprintf(texName, "shadow%.2d.tga", s);
+ surface = D3DTextr_GetSurface(texName);
+ if ( surface == 0 ) continue;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) continue;
+
+ // Clears in blank whole piece.
+ if ( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ for ( y=0 ; y<(int)ddsd.dwHeight ; y++ )
+ {
+ pbSurf = (WORD*)ddsd.lpSurface;
+ pbSurf += ddsd.lPitch*y/2;
+ memset(pbSurf, -1, ddsd.lPitch); // all blank
+ }
+ }
+
+ // Draw the new shadows.
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ||
+ m_groundSpot[i].radius == 0.0f ) continue;
+
+ if ( m_groundSpot[i].min == 0.0f &&
+ m_groundSpot[i].max == 0.0f )
+ {
+ dot = (int)(m_groundSpot[i].radius/2.0f);
+
+ tu = (m_groundSpot[i].pos.x+1600.0f)/3200.0f;
+ tv = (m_groundSpot[i].pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple of 1
+
+ if ( px+dot < min.x || py+dot < min.y ||
+ px-dot > max.x || py-dot > max.y ) continue;
+
+ for ( iy=-dot ; iy<=dot ; iy++ )
+ {
+ for ( ix=-dot ; ix<=dot ; ix++ )
+ {
+ ppx = px+ix;
+ ppy = py+iy;
+
+ if ( ppx < min.x || ppy < min.y ||
+ ppx >= max.x || ppy >= max.y ) continue;
+
+ if ( dot == 0 )
+ {
+ intensity = 0.0f;
+ }
+ else
+ {
+ intensity = Length(ppx-cx, ppy-cy)/dot;
+ //? intensity = powf(intensity, m_groundSpot[i].smooth);
+ }
+
+ color.r = m_groundSpot[i].color.r+intensity;
+ color.g = m_groundSpot[i].color.g+intensity;
+ color.b = m_groundSpot[i].color.b+intensity;
+
+ ppx -= min.x; // on the texture
+ ppy -= min.y;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ }
+ }
+ else
+ {
+ for ( iy=0 ; iy<256 ; iy++ )
+ {
+ for ( ix=0 ; ix<256 ; ix++ )
+ {
+ pos.x = (256.0f*(s%4)+ix)*3200.0f/1024.0f - 1600.0f;
+ pos.z = (256.0f*(s/4)+iy)*3200.0f/1024.0f - 1600.0f;
+ pos.y = 0.0f;
+ level = m_terrain->RetFloorLevel(pos, TRUE);
+ if ( level < m_groundSpot[i].min ||
+ level > m_groundSpot[i].max ) continue;
+
+ if ( level > (m_groundSpot[i].max+m_groundSpot[i].min)/2.0f )
+ {
+ intensity = 1.0f-(m_groundSpot[i].max-level)/m_groundSpot[i].smooth;
+ }
+ else
+ {
+ intensity = 1.0f-(level-m_groundSpot[i].min)/m_groundSpot[i].smooth;
+ }
+ if ( intensity < 0.0f ) intensity = 0.0f;
+
+ color.r = m_groundSpot[i].color.r+intensity;
+ color.g = m_groundSpot[i].color.g+intensity;
+ color.b = m_groundSpot[i].color.b+intensity;
+
+ AddDot(&ddsd, ix, iy, color);
+ }
+ }
+ }
+ }
+
+ if ( bSet )
+ {
+ dot = (int)(m_groundMark.radius/2.0f);
+
+ tu = (m_groundMark.pos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple of 1
+
+ for ( iy=-dot ; iy<=dot ; iy++ )
+ {
+ for ( ix=-dot ; ix<=dot ; ix++ )
+ {
+ ppx = px+ix;
+ ppy = py+iy;
+
+ if ( ppx < min.x || ppy < min.y ||
+ ppx >= max.x || ppy >= max.y ) continue;
+
+ ppx -= min.x; // on the texture
+ ppy -= min.y;
+
+ intensity = 1.0f-Length((float)ix, (float)iy)/dot;
+ if ( intensity <= 0.0f ) continue;
+ intensity *= m_groundMark.intensity;
+
+ j = (ix+dot) + (iy+dot)*m_groundMark.dx;
+ if ( m_groundMark.table[j] == 1 ) // green ?
+ {
+ color.r = 1.0f-intensity;
+ color.g = 1.0f;
+ color.b = 1.0f-intensity;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ if ( m_groundMark.table[j] == 2 ) // red ?
+ {
+ color.r = 1.0f;
+ color.g = 1.0f-intensity;
+ color.b = 1.0f-intensity;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ }
+ }
+ }
+
+ surface->Unlock(NULL);
+ }
+ }
+
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ||
+ m_groundSpot[i].radius == 0.0f )
+ {
+ m_groundSpot[i].drawRadius = 0.0f;
+ }
+ else
+ {
+ m_groundSpot[i].drawPos = m_groundSpot[i].pos;
+ m_groundSpot[i].drawRadius = m_groundSpot[i].radius;
+ }
+ }
+
+ m_groundMark.drawPos = m_groundMark.pos;
+ m_groundMark.drawRadius = m_groundMark.radius;
+ m_groundMark.drawIntensity = m_groundMark.intensity;
+
+ m_bFirstGroundSpot = FALSE;
+}
+
+// Draw all the shadows.
+
+void CD3DEngine::DrawShadow()
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR corner[4], n, pos;
+ D3DMATERIAL7 material;
+ D3DMATRIX matrix;
+ FPOINT ts, ti, rot;
+ float startDeepView, endDeepView;
+ float intensity, lastIntensity, hFactor, radius, max, height;
+ float dp, h, d, D;
+ int i;
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse.r = 1.0f;
+ material.diffuse.g = 1.0f;
+ material.diffuse.b = 1.0f; // white
+ material.ambient.r = 0.5f;
+ material.ambient.g = 0.5f;
+ material.ambient.b = 0.5f;
+ SetMaterial(material);
+
+#if _POLISH
+ SetTexture("textp.tga");
+#else
+ SetTexture("text.tga");
+#endif
+
+ dp = 0.5f/256.0f;
+ ts.y = 192.0f/256.0f;
+ ti.y = 224.0f/256.0f;
+ ts.y += dp;
+ ti.y -= dp;
+
+ n = D3DVECTOR(0.0f, 1.0f, 0.0f);
+
+ startDeepView = m_deepView[m_rankView]*m_fogStart[m_rankView];
+ endDeepView = m_deepView[m_rankView];
+
+ lastIntensity = -1.0f;
+ for ( i=0 ; i<m_shadowTotal ; i++ )
+ {
+ if ( !m_shadow[i].bUsed ) continue;
+ if ( m_shadow[i].bHide ) continue;
+
+ pos = m_shadow[i].pos; // pos = center of the shadow on the ground
+
+ if ( m_eyePt.y == pos.y ) continue; // camera at the same level?
+
+ // h is the height above the ground to which the shadow
+ // will be drawn.
+ if ( m_eyePt.y > pos.y ) // camera on?
+ {
+ height = m_eyePt.y-pos.y;
+ h = m_shadow[i].radius;
+ max = height*0.5f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Length(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y += h;
+ }
+ else // camera underneath?
+ {
+ height = pos.y-m_eyePt.y;
+ h = m_shadow[i].radius;
+ max = height*0.1f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Length(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y -= h;
+ }
+
+ // The hFactor decreases the intensity and size increases more
+ // the object is high relative to the ground.
+ hFactor = m_shadow[i].height/20.0f;
+ if ( hFactor < 0.0f ) hFactor = 0.0f;
+ if ( hFactor > 1.0f ) hFactor = 1.0f;
+ hFactor = powf(1.0f-hFactor, 2.0f);
+ if ( hFactor < 0.2f ) hFactor = 0.2f;
+
+ radius = m_shadow[i].radius*1.5f;
+ radius *= 2.0f-hFactor; // greater if high
+ radius *= 1.0f-d/D; // smaller if close
+
+ if ( m_shadow[i].type == D3DSHADOWNORM )
+ {
+ corner[0].x = +radius;
+ corner[0].z = +radius;
+ corner[0].y = 0.0f;
+
+ corner[1].x = -radius;
+ corner[1].z = +radius;
+ corner[1].y = 0.0f;
+
+ corner[2].x = +radius;
+ corner[2].z = -radius;
+ corner[2].y = 0.0f;
+
+ corner[3].x = -radius;
+ corner[3].z = -radius;
+ corner[3].y = 0.0f;
+
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ else
+ {
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(radius, radius));
+ corner[0].x = rot.x;
+ corner[0].z = rot.y;
+ corner[0].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(-radius, radius));
+ corner[1].x = rot.x;
+ corner[1].z = rot.y;
+ corner[1].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(radius, -radius));
+ corner[2].x = rot.x;
+ corner[2].z = rot.y;
+ corner[2].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(-radius, -radius));
+ corner[3].x = rot.x;
+ corner[3].z = rot.y;
+ corner[3].y = 0.0f;
+
+ if ( m_shadow[i].type == D3DSHADOWWORM )
+ {
+ ts.x = 96.0f/256.0f;
+ ti.x = 128.0f/256.0f;
+ }
+ else
+ {
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ }
+
+ corner[0] = Cross(corner[0], m_shadow[i].normal);
+ corner[1] = Cross(corner[1], m_shadow[i].normal);
+ corner[2] = Cross(corner[2], m_shadow[i].normal);
+ corner[3] = Cross(corner[3], m_shadow[i].normal);
+
+ corner[0] += pos;
+ corner[1] += pos;
+ corner[2] += pos;
+ corner[3] += pos;
+
+ ts.x += dp;
+ ti.x -= dp;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, ts.x, ts.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, ti.x, ts.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, ts.x, ti.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, ti.x, ti.y);
+
+ intensity = (0.5f+m_shadow[i].intensity*0.5f)*hFactor;
+
+ // Decreases the intensity of the shade if you're in the area
+ // between the beginning and the end of the fog.
+ if ( D > startDeepView )
+ {
+ intensity *= 1.0f-(D-startDeepView)/(endDeepView-startDeepView);
+ }
+
+ // Decreases if the intensity is almost horizontal
+ // with shade (shade very platte).
+//? if ( height < 4.0f ) intensity *= height/4.0f;
+
+ if ( intensity == 0.0f ) continue;
+
+ if ( lastIntensity != intensity ) // intensity changed?
+ {
+ lastIntensity = intensity;
+ SetState(D3DSTATETTw, RetColor(intensity));
+ }
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+ }
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+}
+
+
+// Called ounces per frame, the call is the entry point for 3d rendering.
+// This function sets up render states, clears the
+// viewport, and renders the scene.
+
+HRESULT CD3DEngine::Render()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, objRank, tState;
+ CInterface* pInterface;
+ BOOL bTransparent;
+ D3DCOLOR color, tColor;
+
+ if ( !m_bRender ) return S_OK;
+
+ m_statisticTriangle = 0;
+ m_lastState = -1;
+ m_lastColor = 999;
+ m_lastTexture[0][0] = 0;
+ m_lastTexture[1][0] = 0;
+ ZeroMemory(&m_lastMaterial, sizeof(D3DMATERIAL7));
+
+ if ( m_bGroundSpot )
+ {
+ RenderGroundSpot();
+ }
+
+ // Clear the viewport
+ if ( m_bSkyMode && m_cloud->RetLevel() != 0.0f ) // clouds?
+ {
+ color = m_backgroundCloudDown;
+ }
+ else
+ {
+ color = m_backgroundColorDown;
+ }
+ m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
+ color, 1.0f, 0L );
+
+ m_light->LightUpdate();
+
+ // Begin the scene
+ if( FAILED( m_pD3DDevice->BeginScene() ) ) return S_OK;
+
+ if ( m_bDrawWorld )
+ {
+ DrawBackground(); // draws the background
+ if ( m_bPlanetMode ) DrawPlanet(); // draws the planets
+ if ( m_bSkyMode ) m_cloud->Draw(); // draws the clouds
+
+ // Display the objects
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, F2DW(16));
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, m_fogColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(m_deepView[m_rankView]*m_fogStart[m_rankView]));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(m_deepView[m_rankView]));
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matView);
+
+ if ( m_bWaterMode ) m_water->DrawBack(); // draws water
+
+ if ( m_bShadow )
+ {
+ // Draw the field.
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objectParam[objRank].type != TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DrawShadow(); // draws the shadows
+ }
+
+ // Draw objects.
+ bTransparent = FALSE;
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency != 0.0f ) // transparent ?
+ {
+ bTransparent = TRUE;
+ continue;
+ }
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bTransparent )
+ {
+ if ( m_bStateColor )
+ {
+ tState = D3DSTATETTb|D3DSTATE2FACE;
+ tColor = 0x44444444;
+ }
+ else
+ {
+ tState = D3DSTATETTb;
+ tColor = 0x88888888;
+ }
+
+ // Draw transparent objects.
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency == 0.0f ) continue;
+ SetState(tState, tColor);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_light->LightUpdate(TYPETERRAIN);
+ if ( m_bWaterMode ) m_water->DrawSurf(); // draws water
+//? m_cloud->Draw(); // draws the clouds
+
+ m_particule->DrawParticule(SH_WORLD); // draws the particles of the 3D world
+ m_blitz->Draw(); // draws lightning
+ if ( m_bLensMode ) DrawFrontsize(); // draws the foreground
+ if ( !m_bOverFront ) DrawOverColor(); // draws the foreground color
+ }
+
+ // Draw the user interface over the scene.
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ pInterface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ if ( pInterface != 0 )
+ {
+ pInterface->Draw(); // draws the entire interface
+ }
+ m_particule->DrawParticule(SH_INTERFACE); // draws the particles of the interface
+
+ if ( m_bDrawFront )
+ {
+ // Display the objects
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, F2DW(16));
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, m_ambiantColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, m_fogColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(m_deepView[m_rankView]*m_fogStart[m_rankView]));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(m_deepView[m_rankView]));
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matView);
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( !m_objectParam[objRank].bDrawFront ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_particule->DrawParticule(SH_FRONT); // draws the particles of the 3D world
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+ }
+
+ if ( m_bOverFront ) DrawOverColor(); // draws the foreground color
+
+ if ( m_mouseType != D3DMOUSEHIDE )
+ {
+ DrawMouse();
+ }
+
+ // End the scene.
+ m_pD3DDevice->EndScene();
+
+ DrawHilite();
+ return S_OK;
+}
+
+
+// Draw the gradient background.
+
+void CD3DEngine::DrawBackground()
+{
+ if ( m_bSkyMode && m_cloud->RetLevel() != 0.0f ) // clouds ?
+ {
+ if ( m_backgroundCloudUp != m_backgroundCloudDown ) // degraded?
+ {
+ DrawBackgroundGradient(m_backgroundCloudUp, m_backgroundCloudDown);
+ }
+ }
+ else
+ {
+ if ( m_backgroundColorUp != m_backgroundColorDown ) // degraded?
+ {
+ DrawBackgroundGradient(m_backgroundColorUp, m_backgroundColorDown);
+ }
+ }
+
+ if ( m_bBackForce || (m_bSkyMode && m_backgroundName[0] != 0) )
+ {
+ DrawBackgroundImage(); // image
+ }
+}
+
+// Draw the gradient background.
+
+void CD3DEngine::DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down)
+{
+ D3DLVERTEX vertex[4]; // 2 triangles
+ D3DCOLOR color[3];
+ FPOINT p1, p2;
+
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ color[0] = up;
+ color[1] = down;
+ color[2] = 0x00000000;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture("xxx.tga"); // no texture
+ SetState(D3DSTATENORMAL);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Draws a portion of the image background.
+
+void CD3DEngine::DrawBackgroundImageQuarter(FPOINT p1, FPOINT p2, char *name)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ float u1, u2, v1, v2, h, a;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normal
+
+ if ( m_bBackgroundFull )
+ {
+ u1 = 0.0f;
+ v1 = 0.0f;
+ u2 = 1.0f;
+ v2 = 1.0f;
+
+ if ( m_bBackgroundQuarter )
+ {
+ u1 += 0.5f/512.0f;
+ v1 += 0.5f/384.0f;
+ u2 -= 0.5f/512.0f;
+ v2 -= 0.5f/384.0f;
+ }
+ }
+ else
+ {
+ h = 0.5f; // visible area vertically (1=all)
+ a = m_eyeDirV-PI*0.15f;
+ if ( a > PI ) a -= PI*2.0f; // a = -PI..PI
+ if ( a > PI/4.0f ) a = PI/4.0f;
+ if ( a < -PI/4.0f ) a = -PI/4.0f;
+
+ u1 = -m_eyeDirH/PI;
+ u2 = u1+1.0f/PI;
+//? u1 = -m_eyeDirH/(PI*2.0f);
+//? u2 = u1+1.0f/(PI*2.0f);
+
+ v1 = (1.0f-h)*(0.5f+a/(2.0f*PI/4.0f))+0.1f;
+ v2 = v1+h;
+ }
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture(name);
+ SetState(D3DSTATEWRAP);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Draws the image background.
+
+void CD3DEngine::DrawBackgroundImage()
+{
+ FPOINT p1, p2;
+ char name[50];
+
+ if ( m_bBackgroundQuarter )
+ {
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 0.5f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 0);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 1);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 0.5f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 2);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 3);
+ DrawBackgroundImageQuarter(p1, p2, name);
+ }
+ else
+ {
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundName);
+ }
+}
+
+// Draws all the planets.
+
+void CD3DEngine::DrawPlanet()
+{
+ if ( !m_planet->PlanetExist() ) return;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ m_planet->Draw(); // draws the planets
+}
+
+// Draws the image foreground.
+
+void CD3DEngine::DrawFrontsize()
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ FPOINT p1, p2;
+ float u1, u2, v1, v2;
+
+ if ( m_frontsizeName[0] == 0 ) return;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normal
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ u1 = -m_eyeDirH/(PI*0.6f)+PI*0.5f;
+ u2 = u1+0.50f;
+
+ v1 = 0.2f;
+ v2 = 1.0f;
+
+#if 0
+ char s[100];
+ sprintf(s, "h=%.2f v=%.2f u=%.2f;%.2f v=%.2f;%.2f", m_eyeDirH, m_eyeDirV, u1, u2, v1, v2);
+ SetInfoText(3, s);
+#endif
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture(m_frontsizeName);
+ SetState(D3DSTATECLAMP|D3DSTATETTb);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Draws the foreground color.
+
+void CD3DEngine::DrawOverColor()
+{
+ D3DLVERTEX vertex[4]; // 2 triangles
+ D3DCOLOR color[3];
+ FPOINT p1, p2;
+
+ if ( !m_bStateColor ) return;
+ if ( (m_overColor == 0x00000000 && m_overMode == D3DSTATETCb) ||
+ (m_overColor == 0xffffffff && m_overMode == D3DSTATETCw) ) return;
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ color[0] = m_overColor;
+ color[1] = m_overColor;
+ color[2] = 0x00000000;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture("xxx.tga"); // no texture
+ SetState(m_overMode);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+
+// Lists the ranks of objects and subobjects selected.
+
+void CD3DEngine::SetHiliteRank(int *rankList)
+{
+ int i;
+
+ i = 0;
+ while ( *rankList != -1 )
+ {
+ m_hiliteRank[i++] = *rankList++;
+ }
+ m_hiliteRank[i] = -1; // terminator
+}
+
+// Give the box in the 2D screen of any object.
+
+BOOL CD3DEngine::GetBBox2D(int objRank, FPOINT &min, FPOINT &max)
+{
+ D3DVECTOR p, pp;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ if ( i & (1<<0) ) p.x = m_objectParam[objRank].bboxMin.x;
+ else p.x = m_objectParam[objRank].bboxMax.x;
+ if ( i & (1<<1) ) p.y = m_objectParam[objRank].bboxMin.y;
+ else p.y = m_objectParam[objRank].bboxMax.y;
+ if ( i & (1<<2) ) p.z = m_objectParam[objRank].bboxMin.z;
+ else p.z = m_objectParam[objRank].bboxMax.z;
+ if ( TransformPoint(pp, objRank, p) )
+ {
+ if ( pp.x < min.x ) min.x = pp.x;
+ if ( pp.x > max.x ) max.x = pp.x;
+ if ( pp.y < min.y ) min.y = pp.y;
+ if ( pp.y > max.y ) max.y = pp.y;
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f ) return FALSE;
+
+ return TRUE;
+}
+
+// Determines the rectangle of the object highlighted, which will be designed by CD3DApplication.
+
+void CD3DEngine::DrawHilite()
+{
+ FPOINT min, max, omin, omax;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ i = 0;
+ while ( m_hiliteRank[i] != -1 )
+ {
+ if ( GetBBox2D(m_hiliteRank[i++], omin, omax) )
+ {
+ min.x = Min(min.x, omin.x);
+ min.y = Min(min.y, omin.y);
+ max.x = Max(max.x, omax.x);
+ max.y = Max(max.y, omax.y);
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f )
+ {
+ m_bHilite = FALSE; // not highlighted
+ }
+ else
+ {
+ m_hiliteP1 = min;
+ m_hiliteP2 = max;
+ m_bHilite = TRUE;
+ }
+}
+
+// Give the rectangle highlighted by drawing CD3DApplication.
+
+BOOL CD3DEngine::GetHilite(FPOINT &p1, FPOINT &p2)
+{
+ p1 = m_hiliteP1;
+ p2 = m_hiliteP2;
+ return m_bHilite;
+}
+
+
+// Triangles adds qq records for statistics.
+
+void CD3DEngine::AddStatisticTriangle(int nb)
+{
+ m_statisticTriangle += nb;
+}
+
+// Returns the number of triangles rendered.
+
+int CD3DEngine::RetStatisticTriangle()
+{
+ return m_statisticTriangle;
+}
+
+BOOL CD3DEngine::GetSpriteCoord(int &x, int &y)
+{
+ D3DVIEWPORT7 vp;
+ D3DVECTOR v, vv;
+
+ return FALSE;
+ //?
+ vv = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ if ( !TransformPoint(v, 20*20+1, vv) ) return FALSE;
+
+ m_pD3DDevice->GetViewport(&vp);
+ v.x *= vp.dwWidth/2;
+ v.y *= vp.dwHeight/2;
+ v.x = v.x+vp.dwWidth/2;
+ v.y = vp.dwHeight-(v.y+vp.dwHeight/2);
+
+ x = (int)v.x;
+ y = (int)v.y;
+ return TRUE;
+}
+
+
+// Tests whether to exclude a point.
+
+BOOL IsExcludeColor(FPOINT *pExclu, int x, int y)
+{
+ int i;
+
+ i = 0;
+ while ( pExclu[i+0].x != 0.0f || pExclu[i+0].y != 0.0f ||
+ pExclu[i+1].y != 0.0f || pExclu[i+1].y != 0.0f )
+ {
+ if ( x >= (int)(pExclu[i+0].x*256.0f) &&
+ x < (int)(pExclu[i+1].x*256.0f) &&
+ y >= (int)(pExclu[i+0].y*256.0f) &&
+ y < (int)(pExclu[i+1].y*256.0f) ) return TRUE; // exclude
+
+ i += 2;
+ }
+
+ return FALSE; // point to include
+}
+
+// Change the color of a texture.
+
+BOOL CD3DEngine::ChangeColor(char *name,
+ D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1,
+ D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2,
+ float tolerance1, float tolerance2,
+ FPOINT ts, FPOINT ti,
+ FPOINT *pExclu, float shift, BOOL bHSV)
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ D3DCOLORVALUE color;
+ ColorHSV cr1, cn1, cr2, cn2, c;
+ int dx, dy, x, y, sx, sy, ex, ey;
+
+ D3DTextr_Invalidate(name);
+ LoadTexture(name); // reloads the initial texture
+
+ if ( colorRef1.r == colorNew1.r &&
+ colorRef1.g == colorNew1.g &&
+ colorRef1.b == colorNew1.b &&
+ colorRef2.r == colorNew2.r &&
+ colorRef2.g == colorNew2.g &&
+ colorRef2.b == colorNew2.b ) return TRUE;
+
+ surface = D3DTextr_GetSurface(name);
+ if ( surface == 0 ) return FALSE;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) return FALSE;
+
+ dx = ddsd.dwWidth;
+ dy = ddsd.dwHeight;
+
+ sx = (int)(ts.x*dx);
+ sy = (int)(ts.y*dy);
+ ex = (int)(ti.x*dx);
+ ey = (int)(ti.y*dy);
+
+ RGB2HSV(colorRef1, cr1);
+ RGB2HSV(colorNew1, cn1);
+ RGB2HSV(colorRef2, cr2);
+ RGB2HSV(colorNew2, cn2);
+
+ for ( y=sy ; y<ey ; y++ )
+ {
+ for ( x=sx ; x<ex ; x++ )
+ {
+ if ( pExclu != 0 && IsExcludeColor(pExclu, x,y) ) continue;
+
+ color = GetDot(&ddsd, x, y);
+
+ if ( bHSV )
+ {
+ RGB2HSV(color, c);
+ if ( c.s > 0.01f && Abs(c.h-cr1.h) < tolerance1 )
+ {
+ c.h += cn1.h-cr1.h;
+ c.s += cn1.s-cr1.s;
+ c.v += cn1.v-cr1.v;
+ if ( c.h < 0.0f ) c.h -= 1.0f;
+ if ( c.h > 1.0f ) c.h += 1.0f;
+ HSV2RGB(c, color);
+ color.r += shift;
+ color.g += shift;
+ color.b += shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ else
+ if ( tolerance2 != -1.0f &&
+ c.s > 0.01f && Abs(c.h-cr2.h) < tolerance2 )
+ {
+ c.h += cn2.h-cr2.h;
+ c.s += cn2.s-cr2.s;
+ c.v += cn2.v-cr2.v;
+ if ( c.h < 0.0f ) c.h -= 1.0f;
+ if ( c.h > 1.0f ) c.h += 1.0f;
+ HSV2RGB(c, color);
+ color.r += shift;
+ color.g += shift;
+ color.b += shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ }
+ else
+ {
+ if ( Abs(color.r-colorRef1.r)+
+ Abs(color.g-colorRef1.g)+
+ Abs(color.b-colorRef1.b) < tolerance1*3.0f )
+ {
+ color.r = colorNew1.r+color.r-colorRef1.r+shift;
+ color.g = colorNew1.g+color.g-colorRef1.g+shift;
+ color.b = colorNew1.b+color.b-colorRef1.b+shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ else
+ if ( tolerance2 != -1 &&
+ Abs(color.r-colorRef2.r)+
+ Abs(color.g-colorRef2.g)+
+ Abs(color.b-colorRef2.b) < tolerance2*3.0f )
+ {
+ color.r = colorNew2.r+color.r-colorRef2.r+shift;
+ color.g = colorNew2.g+color.g-colorRef2.g+shift;
+ color.b = colorNew2.b+color.b-colorRef2.b+shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ }
+ }
+ }
+
+ surface->Unlock(NULL);
+ return TRUE;
+}
+
+
+// Open an image to work directly in it.
+
+BOOL CD3DEngine::OpenImage(char *name)
+{
+//? D3DTextr_Invalidate(name);
+//? LoadTexture(name);
+
+ m_imageSurface = D3DTextr_GetSurface(name);
+ if ( m_imageSurface == 0 ) return FALSE;
+
+ ZeroMemory(&m_imageDDSD, sizeof(DDSURFACEDESC2));
+ m_imageDDSD.dwSize = sizeof(DDSURFACEDESC2);
+ if ( m_imageSurface->Lock(NULL, &m_imageDDSD, DDLOCK_WAIT, NULL) != DD_OK )
+ {
+ return FALSE;
+ }
+
+ if ( m_imageDDSD.ddpfPixelFormat.dwRGBBitCount != 16 )
+ {
+ m_imageSurface->Unlock(NULL);
+ return FALSE;
+ }
+
+ m_imageDX = m_imageDDSD.dwWidth;
+ m_imageDY = m_imageDDSD.dwHeight;
+
+ return TRUE;
+}
+
+// Copy the working image.
+
+BOOL CD3DEngine::CopyImage()
+{
+ WORD* pbSurf;
+ int y;
+
+ if ( m_imageCopy == 0 )
+ {
+ m_imageCopy = (WORD*)malloc(m_imageDX*m_imageDY*sizeof(WORD));
+ }
+
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ memcpy(m_imageCopy+y*m_imageDX, pbSurf, m_imageDX*sizeof(WORD));
+ }
+ return TRUE;
+}
+
+// Restores the image work.
+
+BOOL CD3DEngine::LoadImage()
+{
+ WORD* pbSurf;
+ int y;
+
+ if ( m_imageCopy == 0 ) return FALSE;
+
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ memcpy(pbSurf, m_imageCopy+y*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ return TRUE;
+}
+
+// Scroll the copy of the working image.
+
+BOOL CD3DEngine::ScrollImage(int dx, int dy)
+{
+ int x, y;
+
+ if ( dx > 0 )
+ {
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ for ( x=0 ; x<m_imageDX-dx ; x++ )
+ {
+ m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX];
+ }
+ }
+ }
+
+ if ( dx < 0 )
+ {
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ for ( x=m_imageDX-1 ; x>=-dx ; x-- )
+ {
+ m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX];
+ }
+ }
+ }
+
+ if ( dy > 0 )
+ {
+ for ( y=0 ; y<m_imageDY-dy ; y++ )
+ {
+ memcpy(m_imageCopy+y*m_imageDX, m_imageCopy+(y+dy)*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ }
+
+ if ( dy < 0 )
+ {
+ for ( y=m_imageDY-1 ; y>=-dy ; y-- )
+ {
+ memcpy(m_imageCopy+y*m_imageDX, m_imageCopy+(y+dy)*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ }
+
+ return TRUE;
+}
+
+// Draws a point in the image work.
+
+BOOL CD3DEngine::SetDot(int x, int y, D3DCOLORVALUE color)
+{
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( x < 0 || x >= m_imageDX ||
+ y < 0 || y >= m_imageDY ) return FALSE;
+
+#if 1
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*32.0f);
+ g = (int)(color.g*32.0f);
+ b = (int)(color.b*32.0f);
+
+ if ( r >= 32 ) r = 31; // 5 bits
+ if ( g >= 32 ) g = 31; // 5 bits
+ if ( b >= 32 ) b = 31; // 5 bits
+#else
+ r = (int)(color.r*31.0f);
+ g = (int)(color.g*31.0f);
+ b = (int)(color.b*31.0f);
+#endif
+
+ if ( m_imageDDSD.ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( m_imageDDSD.ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blank
+ }
+
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = w;
+ return TRUE;
+}
+
+// Closes the working image.
+
+BOOL CD3DEngine::CloseImage()
+{
+ m_imageSurface->Unlock(NULL);
+ return TRUE;
+}
+
+
+// Writes a .BMP screenshot.
+
+BOOL CD3DEngine::WriteScreenShot(char *filename, int width, int height)
+{
+ return m_app->WriteScreenShot(filename, width, height);
+}
+
+// Initializes an hDC on the rendering surface.
+
+BOOL CD3DEngine::GetRenderDC(HDC &hDC)
+{
+ return m_app->GetRenderDC(hDC);
+}
+
+// Frees the hDC of the rendering surface.
+
+BOOL CD3DEngine::ReleaseRenderDC(HDC &hDC)
+{
+ return m_app->ReleaseRenderDC(hDC);
+}
+
+PBITMAPINFO CD3DEngine::CreateBitmapInfoStruct(HBITMAP hBmp)
+{
+ return m_app->CreateBitmapInfoStruct(hBmp);
+}
+
+BOOL CD3DEngine::CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
+{
+ return m_app->CreateBMPFile(pszFile, pbi, hBMP, hDC);
+}
+
+// Returns the pointer to the class cText.
+
+CText* CD3DEngine::RetText()
+{
+ return m_text;
+}
+
+
+// Managing of information text displayed in the window.
+
+void CD3DEngine::SetInfoText(int line, char* text)
+{
+ strcpy(m_infoText[line], text);
+}
+
+char* CD3DEngine::RetInfoText(int line)
+{
+ return m_infoText[line];
+}
+
+
+
+// Specifies the length of the camera.
+// 0.75 = normal
+// 1.50 = wide-angle
+
+void CD3DEngine::SetFocus(float focus)
+{
+ D3DVIEWPORT7 vp;
+ float fAspect;
+
+ m_focus = focus;
+
+ if ( m_pD3DDevice != 0 )
+ {
+ m_pD3DDevice->GetViewport(&vp);
+ m_dim.x = vp.dwWidth;
+ m_dim.y = vp.dwHeight;
+ }
+
+ fAspect = ((float)m_dim.y) / m_dim.x;
+//? D3DUtil_SetProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[m_rankView]);
+ D3DUtil_SetProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[0]);
+}
+
+float CD3DEngine::RetFocus()
+{
+ return m_focus;
+}
+
+//
+
+void CD3DEngine::UpdateMatProj()
+{
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+}
+
+
+
+// Ignores key presses.
+
+void CD3DEngine::FlushPressKey()
+{
+ m_app->FlushPressKey();
+}
+
+// Resets the default keys.
+
+void CD3DEngine::ResetKey()
+{
+ m_app->ResetKey();
+}
+
+// Modifies a button.
+
+void CD3DEngine::SetKey(int keyRank, int option, int key)
+{
+ m_app->SetKey(keyRank, option, key);
+}
+
+// Gives a key.
+
+int CD3DEngine::RetKey(int keyRank, int option)
+{
+ return m_app->RetKey(keyRank, option);
+}
+
+
+// Use the joystick or keyboard.
+
+void CD3DEngine::SetJoystick(BOOL bEnable)
+{
+ m_app->SetJoystick(bEnable);
+}
+
+BOOL CD3DEngine::RetJoystick()
+{
+ return m_app->RetJoystick();
+}
+
+
+void CD3DEngine::SetDebugMode(BOOL bMode)
+{
+ m_app->SetDebugMode(bMode);
+}
+
+BOOL CD3DEngine::RetDebugMode()
+{
+ return m_app->RetDebugMode();
+}
+
+BOOL CD3DEngine::RetSetupMode()
+{
+ return m_app->RetSetupMode();
+}
+
+
+// Indicates whether a point is visible.
+
+BOOL CD3DEngine::IsVisiblePoint(const D3DVECTOR &pos)
+{
+ return ( Length(m_eyePt, pos) <= m_deepView[0] );
+}
+
+
+// Initialize scene objects.
+
+HRESULT CD3DEngine::InitDeviceObjects()
+{
+ // Set miscellaneous render states.
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
+
+ // Set up the textures.
+ D3DTextr_RestoreAllTextures(m_pD3DDevice);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
+
+ SetFocus(m_focus);
+
+ // Definitions of the matrices for the interface.
+ D3DUtil_SetIdentityMatrix(m_matWorldInterface);
+
+ D3DUtil_SetIdentityMatrix(m_matViewInterface);
+ m_matViewInterface._41 = -0.5f;
+ m_matViewInterface._42 = -0.5f;
+ m_matViewInterface._43 = 1.0f;
+
+ D3DUtil_SetIdentityMatrix(m_matProjInterface);
+ m_matProjInterface._11 = 2.0f;
+ m_matProjInterface._22 = 2.0f;
+ m_matProjInterface._34 = 1.0f;
+ m_matProjInterface._43 = -1.0f;
+ m_matProjInterface._44 = 0.0f;
+
+ return S_OK;
+}
+
+
+// Restore all surfaces.
+
+HRESULT CD3DEngine::RestoreSurfaces()
+{
+ return S_OK;
+}
+
+
+// Called when the app is exitting, or the device is being changed,
+// this function deletes any device dependant objects.
+
+HRESULT CD3DEngine::DeleteDeviceObjects()
+{
+ D3DTextr_InvalidateAllTextures();
+ return S_OK;
+}
+
+
+// Called before the app exits, this function gives the app the chance
+// to cleanup after itself.
+
+HRESULT CD3DEngine::FinalCleanup()
+{
+ return S_OK;
+}
+
+
+// Overrrides the main WndProc, so the sample can do custom message
+// handling (e.g. processing mouse, keyboard, or menu commands).
+
+LRESULT CD3DEngine::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+#if 0
+ if ( uMsg == WM_KEYDOWN ) // Alt+key ?
+ {
+ if ( wParam == 'Q' )
+ {
+ debug_blend1 ++;
+ if ( debug_blend1 > 13 ) debug_blend1 = 0;
+ }
+ if ( wParam == 'W' )
+ {
+ debug_blend2 ++;
+ if ( debug_blend2 > 13 ) debug_blend2 = 0;
+ }
+ if ( wParam == 'E' )
+ {
+ debug_blend3 ++;
+ if ( debug_blend3 > 13 ) debug_blend3 = 0;
+ }
+ if ( wParam == 'R' )
+ {
+ debug_blend4 ++;
+ if ( debug_blend4 > 13 ) debug_blend4 = 0;
+ }
+ char s[100];
+ sprintf(s, "src=%d, dest=%d, src=%d, dest=%d", debug_blend1, debug_blend2, debug_blend3, debug_blend4);
+ SetInfoText(4, s);
+ }
+#endif
+
+#if 1
+ if ( uMsg == WM_SYSKEYDOWN ) // Alt+key ?
+ {
+ if ( wParam == VK_F7 ) // Alt+F7 ?
+ {
+ s_resol = 0;
+ }
+ if ( wParam == VK_F8 ) // Alt+F8 ?
+ {
+ s_resol = 1;
+ }
+ if ( wParam == VK_F9 ) // Alt+F9 ?
+ {
+ s_resol = 2;
+ }
+ if ( wParam == VK_F10 ) // Alt+F10 ?
+ {
+ s_resol = 3;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+// Mouse control.
+
+void CD3DEngine::MoveMousePos(FPOINT pos)
+{
+ m_mousePos = pos;
+ m_app->SetMousePos(pos);
+}
+
+void CD3DEngine::SetMousePos(FPOINT pos)
+{
+ m_mousePos = pos;
+}
+
+FPOINT CD3DEngine::RetMousePos()
+{
+ return m_mousePos;
+}
+
+void CD3DEngine::SetMouseType(D3DMouse type)
+{
+ m_mouseType = type;
+}
+
+D3DMouse CD3DEngine::RetMouseType()
+{
+ return m_mouseType;
+}
+
+void CD3DEngine::SetMouseHide(BOOL bHide)
+{
+ if ( m_bMouseHide == bHide ) return;
+
+ if ( bHide ) // hide the mouse?
+ {
+ m_bNiceMouse = m_app->RetNiceMouse();
+ if ( !m_bNiceMouse )
+ {
+ m_app->SetNiceMouse(TRUE);
+ }
+ m_bMouseHide = TRUE;
+ }
+ else // shows the mouse?
+ {
+ if ( !m_bNiceMouse )
+ {
+ m_app->SetNiceMouse(FALSE);
+ }
+ m_bMouseHide = FALSE;
+ }
+}
+
+BOOL CD3DEngine::RetMouseHide()
+{
+ return m_bMouseHide;
+}
+
+void CD3DEngine::SetNiceMouse(BOOL bNice)
+{
+ m_app->SetNiceMouse(bNice);
+}
+
+BOOL CD3DEngine::RetNiceMouse()
+{
+ return m_app->RetNiceMouse();
+}
+
+BOOL CD3DEngine::RetNiceMouseCap()
+{
+ return m_app->RetNiceMouseCap();
+}
+
+// Draws the sprite of the mouse.
+
+void CD3DEngine::DrawMouse()
+{
+ D3DMATERIAL7 material;
+ FPOINT pos, ppos, dim;
+ int i;
+
+ typedef struct
+ {
+ D3DMouse type;
+ int icon1, icon2, iconShadow;
+ int mode1, mode2;
+ float hotx, hoty;
+ }
+ Mouse;
+
+ static Mouse table[] =
+ {
+ { D3DMOUSENORM, 0, 1,32, D3DSTATETTw, D3DSTATETTb, 1.0f, 1.0f},
+ { D3DMOUSEWAIT, 2, 3,33, D3DSTATETTw, D3DSTATETTb, 8.0f, 12.0f},
+ { D3DMOUSEHAND, 4, 5,34, D3DSTATETTw, D3DSTATETTb, 7.0f, 2.0f},
+ { D3DMOUSENO, 6, 7,35, D3DSTATETTw, D3DSTATETTb, 10.0f, 10.0f},
+ { D3DMOUSEEDIT, 8, 9,-1, D3DSTATETTb, D3DSTATETTw, 6.0f, 10.0f},
+ { D3DMOUSECROSS, 10,11,-1, D3DSTATETTb, D3DSTATETTw, 10.0f, 10.0f},
+ { D3DMOUSEMOVEV, 12,13,-1, D3DSTATETTb, D3DSTATETTw, 5.0f, 11.0f},
+ { D3DMOUSEMOVEH, 14,15,-1, D3DSTATETTb, D3DSTATETTw, 11.0f, 5.0f},
+ { D3DMOUSEMOVED, 16,17,-1, D3DSTATETTb, D3DSTATETTw, 9.0f, 9.0f},
+ { D3DMOUSEMOVEI, 18,19,-1, D3DSTATETTb, D3DSTATETTw, 9.0f, 9.0f},
+ { D3DMOUSEMOVE, 20,21,-1, D3DSTATETTb, D3DSTATETTw, 11.0f, 11.0f},
+ { D3DMOUSETARGET, 22,23,-1, D3DSTATETTb, D3DSTATETTw, 15.0f, 15.0f},
+ { D3DMOUSESCROLLL, 24,25,43, D3DSTATETTb, D3DSTATETTw, 2.0f, 9.0f},
+ { D3DMOUSESCROLLR, 26,27,44, D3DSTATETTb, D3DSTATETTw, 17.0f, 9.0f},
+ { D3DMOUSESCROLLU, 28,29,45, D3DSTATETTb, D3DSTATETTw, 9.0f, 2.0f},
+ { D3DMOUSESCROLLD, 30,31,46, D3DSTATETTb, D3DSTATETTw, 9.0f, 17.0f},
+ { D3DMOUSEHIDE },
+ };
+
+ if ( m_bMouseHide ) return;
+ if ( !m_app->RetNiceMouse() ) return; // mouse windows?
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse.r = 1.0f;
+ material.diffuse.g = 1.0f;
+ material.diffuse.b = 1.0f;
+ material.ambient.r = 0.5f;
+ material.ambient.g = 0.5f;
+ material.ambient.b = 0.5f;
+ SetMaterial(material);
+
+ SetTexture("mouse.tga");
+
+ i = 0;
+ while ( table[i].type != D3DMOUSEHIDE )
+ {
+ if ( m_mouseType == table[i].type )
+ {
+ dim.x = 0.05f*0.75f;
+ dim.y = 0.05f;
+
+ pos.x = m_mousePos.x - (table[i].hotx*dim.x)/32.0f;
+ pos.y = m_mousePos.y - ((32.0f-table[i].hoty)*dim.y)/32.0f;
+
+ ppos.x = pos.x+(4.0f/640.0f);
+ ppos.y = pos.y-(3.0f/480.0f);
+ SetState(D3DSTATETTw);
+ DrawSprite(ppos, dim, table[i].iconShadow);
+
+ SetState(table[i].mode1);
+ DrawSprite(pos, dim, table[i].icon1);
+
+ SetState(table[i].mode2);
+ DrawSprite(pos, dim, table[i].icon2);
+ break;
+ }
+ i ++;
+ }
+}
+
+// Draws the sprite of the mouse.
+
+void CD3DEngine::DrawSprite(FPOINT pos, FPOINT dim, int icon)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2;
+ D3DVECTOR n;
+ float u1, u2, v1, v2, dp;
+
+ if ( icon == -1 ) return;
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + dim.x;
+ p2.y = pos.y + dim.y;
+
+ u1 = (32.0f/256.0f)*(icon%8);
+ v1 = (32.0f/256.0f)*(icon/8); // u-v texture
+ u2 = (32.0f/256.0f)+u1;
+ v2 = (32.0f/256.0f)+v1;
+
+ dp = 0.5f/256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normal
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
diff --git a/src/graphics/d3d/d3dengine.h b/src/graphics/d3d/d3dengine.h
new file mode 100644
index 0000000..a99db93
--- /dev/null
+++ b/src/graphics/d3d/d3dengine.h
@@ -0,0 +1,686 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+// d3dengine.h
+
+#ifndef _D3DENGINE_H_
+#define _D3DENGINE_H_
+
+
+#include "struct.h"
+
+
+class CD3DApplication;
+class CInstanceManager;
+class CObject;
+class CLight;
+class CText;
+class CParticule;
+class CWater;
+class CCloud;
+class CBlitz;
+class CPlanet;
+class CSound;
+class CTerrain;
+
+
+#define D3DMAXOBJECT 1200
+#define D3DMAXSHADOW 500
+#define D3DMAXGROUNDSPOT 100
+
+
+enum D3DTypeObj
+{
+ TYPENULL = 0, // object doesn't exist
+ TYPETERRAIN = 1, // terrain
+ TYPEFIX = 2, // fixed object
+ TYPEVEHICULE = 3, // moving object
+ TYPEDESCENDANT = 4, // part of a moving object
+ TYPEQUARTZ = 5, // fixed object type quartz
+ TYPEMETAL = 6, // fixed object type metal
+};
+
+enum D3DTypeTri
+{
+ D3DTYPE6T = 1, // triangles
+ D3DTYPE6S = 2, // surfaces
+};
+
+enum D3DMaping
+{
+ D3DMAPPINGX = 1,
+ D3DMAPPINGY = 2,
+ D3DMAPPINGZ = 3,
+ D3DMAPPING1X = 4,
+ D3DMAPPING1Y = 5,
+ D3DMAPPING1Z = 6,
+};
+
+enum D3DMouse
+{
+ D3DMOUSEHIDE = 0, // no mouse
+ D3DMOUSENORM = 1,
+ D3DMOUSEWAIT = 2,
+ D3DMOUSEEDIT = 3,
+ D3DMOUSEHAND = 4,
+ D3DMOUSECROSS = 5,
+ D3DMOUSESHOW = 6,
+ D3DMOUSENO = 7,
+ D3DMOUSEMOVE = 8, // +
+ D3DMOUSEMOVEH = 9, // -
+ D3DMOUSEMOVEV = 10, // |
+ D3DMOUSEMOVED = 11, // /
+ D3DMOUSEMOVEI = 12, // \ //
+ D3DMOUSESCROLLL = 13, // <<
+ D3DMOUSESCROLLR = 14, // >>
+ D3DMOUSESCROLLU = 15, // ^
+ D3DMOUSESCROLLD = 16, // v
+ D3DMOUSETARGET = 17,
+};
+
+enum D3DShadowType
+{
+ D3DSHADOWNORM = 0,
+ D3DSHADOWWORM = 1,
+};
+
+
+#define D3DSTATENORMAL 0 // normal opaque materials
+#define D3DSTATETTb (1<<0) // the transparent texture (black = no)
+#define D3DSTATETTw (1<<1) // the transparent texture (white = no)
+#define D3DSTATETD (1<<2) // the transparent diffuse color
+#define D3DSTATEWRAP (1<<3) // texture wrappe
+#define D3DSTATECLAMP (1<<4) // texture borders with solid color
+#define D3DSTATELIGHT (1<<5) // light texture (ambient max)
+#define D3DSTATEDUALb (1<<6) // double black texturing
+#define D3DSTATEDUALw (1<<7) // double white texturing
+#define D3DSTATEPART1 (1<<8) // part 1 (no change in. MOD!)
+#define D3DSTATEPART2 (1<<9) // part 2
+#define D3DSTATEPART3 (1<<10) // part 3
+#define D3DSTATEPART4 (1<<11) // part 4
+#define D3DSTATE2FACE (1<<12) // double-sided face
+#define D3DSTATEALPHA (1<<13) // image using alpha channel
+#define D3DSTATESECOND (1<<14) // always use 2nd floor texturing
+#define D3DSTATEFOG (1<<15) // causes the fog
+#define D3DSTATETCb (1<<16) // the transparent color (black = no)
+#define D3DSTATETCw (1<<17) // the transparent color (white = no)
+
+
+typedef struct
+{
+ D3DVERTEX2 triangle[3];
+ D3DMATERIAL7 material;
+ int state;
+ char texName1[20];
+ char texName2[20];
+}
+D3DTriangle;
+
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ D3DMATERIAL7 material;
+ int state;
+ D3DTypeTri type; // D3DTYPE6x
+ D3DVERTEX2 vertex[1];
+}
+D3DObjLevel6;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ int reserve;
+ D3DObjLevel6* table[1];
+}
+D3DObjLevel5;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ float min, max;
+ D3DObjLevel5* table[1];
+}
+D3DObjLevel4;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ int objRank;
+ D3DObjLevel4* table[1];
+}
+D3DObjLevel3;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ char texName1[20];
+ char texName2[20];
+ D3DObjLevel3* table[1];
+}
+D3DObjLevel2;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ D3DObjLevel2* table[1];
+}
+D3DObjLevel1;
+
+
+typedef struct
+{
+ char bUsed; // TRUE -> object exists
+ char bVisible; // TRUE -> visible object
+ char bDrawWorld; // TRUE -> shape behind the interface
+ char bDrawFront; // TRUE -> shape before the interface
+ int totalTriangle; // number of triangles used
+ D3DTypeObj type; // type of the object (TYPE*)
+ D3DMATRIX transform; // transformation matrix
+ float distance; // distance point of view - original
+ D3DVECTOR bboxMin; // bounding box of the object
+ D3DVECTOR bboxMax; // (the origin 0, 0, 0 is always included)
+ float radius; // radius of the sphere at the origin
+ int shadowRank; // rank of the associated shadow
+ float transparency; // transparency of the object (0 .. 1)
+}
+D3DObject;
+
+typedef struct
+{
+ char bUsed; // TRUE -> object exists
+ char bHide; // TRUE -> invisible shadow (object carried by ex.)
+ int objRank; // rank of the object
+ D3DShadowType type; // type of shadow
+ D3DVECTOR pos; // position for the shadow
+ D3DVECTOR normal; // normal terrain
+ float angle; // angle of the shadow
+ float radius; // radius of the shadow
+ float intensity; // intensity of the shadow
+ float height; // height from the ground
+}
+D3DShadow;
+
+typedef struct
+{
+ char bUsed; // TRUE -> object exists
+ D3DCOLORVALUE color; // color of the shadow
+ float min, max; // altitudes min / max
+ float smooth; // transition area
+ D3DVECTOR pos; // position for the shadow
+ float radius; // radius of the shadow
+ D3DVECTOR drawPos; // drawn to position the shade
+ float drawRadius; // radius of the shadow drawn
+}
+D3DGroundSpot;
+
+typedef struct
+{
+ char bUsed; // TRUE -> object exists
+ char bDraw; // TRUE -> drawn mark
+ int phase; // 1 = increase, 2 = fixed, 3 = decrease
+ float delay[3]; // time for 3 phases
+ float fix; // fixed time
+ D3DVECTOR pos; // position for marks
+ float radius; // radius of marks
+ float intensity; // color intensity
+ D3DVECTOR drawPos; // drawn in position marks
+ float drawRadius; // radius marks drawn
+ float drawIntensity; // current drawn
+ int dx, dy; // dimensions table
+ char* table; // pointer to the table
+}
+D3DGroundMark;
+
+
+
+class CD3DEngine
+{
+public:
+ CD3DEngine(CInstanceManager *iMan, CD3DApplication *app);
+ ~CD3DEngine();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+ LPDIRECT3DDEVICE7 RetD3DDevice();
+
+ void SetTerrain(CTerrain* terrain);
+
+ BOOL WriteProfile();
+
+ void SetPause(BOOL bPause);
+ BOOL RetPause();
+
+ void SetMovieLock(BOOL bLock);
+ BOOL RetMovieLock();
+
+ void SetShowStat(BOOL bShow);
+ BOOL RetShowStat();
+
+ void SetRenderEnable(BOOL bEnable);
+
+ HRESULT OneTimeSceneInit();
+ HRESULT InitDeviceObjects();
+ HRESULT DeleteDeviceObjects();
+ HRESULT RestoreSurfaces();
+ HRESULT Render();
+ HRESULT FrameMove(float rTime);
+ void StepSimul(float rTime);
+ HRESULT FinalCleanup();
+ void AddStatisticTriangle(int nb);
+ int RetStatisticTriangle();
+ void SetHiliteRank(int *rankList);
+ BOOL GetHilite(FPOINT &p1, FPOINT &p2);
+ BOOL GetSpriteCoord(int &x, int &y);
+ void SetInfoText(int line, char* text);
+ char* RetInfoText(int line);
+ LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+ void FirstExecuteAdapt(BOOL bFirst);
+ int GetVidMemTotal();
+ BOOL IsVideo8MB();
+ BOOL IsVideo32MB();
+
+ BOOL EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes);
+ BOOL RetFullScreen();
+ BOOL ChangeDevice(char *device, char *mode, BOOL bFull);
+
+ D3DMATRIX* RetMatView();
+ D3DMATRIX* RetMatLeftView();
+ D3DMATRIX* RetMatRightView();
+
+ void TimeInit();
+ void TimeEnterGel();
+ void TimeExitGel();
+ float TimeGet();
+
+ int RetRestCreate();
+ int CreateObject();
+ void FlushObject();
+ BOOL DeleteObject(int objRank);
+ BOOL SetDrawWorld(int objRank, BOOL bDraw);
+ BOOL SetDrawFront(int objRank, BOOL bDraw);
+ BOOL AddTriangle(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ BOOL AddSurface(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ BOOL AddQuick(int objRank, D3DObjLevel6* buffer, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ D3DObjLevel6* SearchTriangle(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max);
+ void ChangeLOD();
+ BOOL ChangeSecondTexture(int objRank, char* texName2);
+ int RetTotalTriangles(int objRank);
+ int GetTriangles(int objRank, float min, float max, D3DTriangle* buffer, int size, float percent);
+ BOOL GetBBox(int objRank, D3DVECTOR &min, D3DVECTOR &max);
+ BOOL ChangeTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float au, float bu, float av, float bv);
+ BOOL TrackTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float pos, float factor, float tl, float ts, float tt);
+ BOOL SetObjectTransform(int objRank, const D3DMATRIX &transform);
+ BOOL GetObjectTransform(int objRank, D3DMATRIX &transform);
+ BOOL SetObjectType(int objRank, D3DTypeObj type);
+ D3DTypeObj RetObjectType(int objRank);
+ BOOL SetObjectTransparency(int objRank, float value);
+
+ BOOL ShadowCreate(int objRank);
+ void ShadowDelete(int objRank);
+ BOOL SetObjectShadowHide(int objRank, BOOL bHide);
+ BOOL SetObjectShadowType(int objRank, D3DShadowType type);
+ BOOL SetObjectShadowPos(int objRank, const D3DVECTOR &pos);
+ BOOL SetObjectShadowNormal(int objRank, const D3DVECTOR &n);
+ BOOL SetObjectShadowAngle(int objRank, float angle);
+ BOOL SetObjectShadowRadius(int objRank, float radius);
+ BOOL SetObjectShadowIntensity(int objRank, float intensity);
+ BOOL SetObjectShadowHeight(int objRank, float h);
+ float RetObjectShadowRadius(int objRank);
+
+ void GroundSpotFlush();
+ int GroundSpotCreate();
+ void GroundSpotDelete(int rank);
+ BOOL SetObjectGroundSpotPos(int rank, const D3DVECTOR &pos);
+ BOOL SetObjectGroundSpotRadius(int rank, float radius);
+ BOOL SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color);
+ BOOL SetObjectGroundSpotMinMax(int rank, float min, float max);
+ BOOL SetObjectGroundSpotSmooth(int rank, float smooth);
+
+ int GroundMarkCreate(D3DVECTOR pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table);
+ BOOL GroundMarkDelete(int rank);
+
+ void Update();
+
+ void SetViewParams(const D3DVECTOR &vEyePt, const D3DVECTOR &vLookatPt, const D3DVECTOR &vUpVec, FLOAT fEyeDistance);
+
+ BOOL FreeTexture(char* name);
+ BOOL LoadTexture(char* name, int stage=0);
+ BOOL LoadAllTexture();
+
+ void SetLimitLOD(int rank, float limit);
+ float RetLimitLOD(int rank, BOOL bLast=FALSE);
+
+ void SetTerrainVision(float vision);
+
+ void SetGroundSpot(BOOL bMode);
+ BOOL RetGroundSpot();
+ void SetShadow(BOOL bMode);
+ BOOL RetShadow();
+ void SetDirty(BOOL bMode);
+ BOOL RetDirty();
+ void SetFog(BOOL bMode);
+ BOOL RetFog();
+ BOOL RetStateColor();
+
+ void SetSecondTexture(int texNum);
+ int RetSecondTexture();
+
+ void SetRankView(int rank);
+ int RetRankView();
+
+ void SetDrawWorld(BOOL bDraw);
+ void SetDrawFront(BOOL bDraw);
+
+ void SetAmbiantColor(D3DCOLOR color, int rank=0);
+ D3DCOLOR RetAmbiantColor(int rank=0);
+
+ void SetWaterAddColor(D3DCOLORVALUE color);
+ D3DCOLORVALUE RetWaterAddColor();
+
+ void SetFogColor(D3DCOLOR color, int rank=0);
+ D3DCOLOR RetFogColor(int rank=0);
+
+ void SetDeepView(float length, int rank=0, BOOL bRef=FALSE);
+ float RetDeepView(int rank=0);
+
+ void SetFogStart(float start, int rank=0);
+ float RetFogStart(int rank=0);
+
+ void SetBackground(char *name, D3DCOLOR up=0, D3DCOLOR down=0, D3DCOLOR cloudUp=0, D3DCOLOR cloudDown=0, BOOL bFull=FALSE, BOOL bQuarter=FALSE);
+ void RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down, D3DCOLOR &cloudUp, D3DCOLOR &cloudDown, BOOL &bFull, BOOL &bQuarter);
+ void SetFrontsizeName(char *name);
+ void SetOverFront(BOOL bFront);
+ void SetOverColor(D3DCOLOR color=0, int mode=D3DSTATETCb);
+
+ void SetParticuleDensity(float value);
+ float RetParticuleDensity();
+ float ParticuleAdapt(float factor);
+
+ void SetClippingDistance(float value);
+ float RetClippingDistance();
+
+ void SetObjectDetail(float value);
+ float RetObjectDetail();
+
+ void SetGadgetQuantity(float value);
+ float RetGadgetQuantity();
+
+ void SetTextureQuality(int value);
+ int RetTextureQuality();
+
+ void SetTotoMode(BOOL bPresent);
+ BOOL RetTotoMode();
+
+ void SetLensMode(BOOL bPresent);
+ BOOL RetLensMode();
+
+ void SetWaterMode(BOOL bPresent);
+ BOOL RetWaterMode();
+
+ void SetBlitzMode(BOOL bPresent);
+ BOOL RetBlitzMode();
+
+ void SetSkyMode(BOOL bPresent);
+ BOOL RetSkyMode();
+
+ void SetBackForce(BOOL bPresent);
+ BOOL RetBackForce();
+
+ void SetPlanetMode(BOOL bPresent);
+ BOOL RetPlanetMode();
+
+ void SetLightMode(BOOL bPresent);
+ BOOL RetLightMode();
+
+ void SetEditIndentMode(BOOL bAuto);
+ BOOL RetEditIndentMode();
+
+ void SetEditIndentValue(int value);
+ int RetEditIndentValue();
+
+ void SetSpeed(float speed);
+ float RetSpeed();
+
+ void SetTracePrecision(float factor);
+ float RetTracePrecision();
+
+ void SetFocus(float focus);
+ float RetFocus();
+ D3DVECTOR RetEyePt();
+ D3DVECTOR RetLookatPt();
+ float RetEyeDirH();
+ float RetEyeDirV();
+ POINT RetDim();
+ void UpdateMatProj();
+
+ void ApplyChange();
+
+ void FlushPressKey();
+ void ResetKey();
+ void SetKey(int keyRank, int option, int key);
+ int RetKey(int keyRank, int option);
+
+ void SetJoystick(BOOL bEnable);
+ BOOL RetJoystick();
+
+ void SetDebugMode(BOOL bMode);
+ BOOL RetDebugMode();
+ BOOL RetSetupMode();
+
+ BOOL IsVisiblePoint(const D3DVECTOR &pos);
+
+ int DetectObject(FPOINT mouse);
+ void SetState(int state, D3DCOLOR color=0xffffffff);
+ void SetTexture(char *name, int stage=0);
+ void SetMaterial(const D3DMATERIAL7 &mat);
+
+ void MoveMousePos(FPOINT pos);
+ void SetMousePos(FPOINT pos);
+ FPOINT RetMousePos();
+ void SetMouseType(D3DMouse type);
+ D3DMouse RetMouseType();
+ void SetMouseHide(BOOL bHide);
+ BOOL RetMouseHide();
+ void SetNiceMouse(BOOL bNice);
+ BOOL RetNiceMouse();
+ BOOL RetNiceMouseCap();
+
+ CText* RetText();
+
+ BOOL ChangeColor(char *name, D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1, D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2, float tolerance1, float tolerance2, FPOINT ts, FPOINT ti, FPOINT *pExclu=0, float shift=0.0f, BOOL bHSV=FALSE);
+ BOOL OpenImage(char *name);
+ BOOL CopyImage();
+ BOOL LoadImage();
+ BOOL ScrollImage(int dx, int dy);
+ BOOL SetDot(int x, int y, D3DCOLORVALUE color);
+ BOOL CloseImage();
+ BOOL WriteScreenShot(char *filename, int width, int height);
+ BOOL GetRenderDC(HDC &hDC);
+ BOOL ReleaseRenderDC(HDC &hDC);
+ PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp);
+ BOOL CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
+
+protected:
+ void MemSpace1(D3DObjLevel1 *&p, int nb);
+ void MemSpace2(D3DObjLevel2 *&p, int nb);
+ void MemSpace3(D3DObjLevel3 *&p, int nb);
+ void MemSpace4(D3DObjLevel4 *&p, int nb);
+ void MemSpace5(D3DObjLevel5 *&p, int nb);
+ void MemSpace6(D3DObjLevel6 *&p, int nb);
+
+ D3DObjLevel2* AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2);
+ D3DObjLevel3* AddLevel2(D3DObjLevel2 *&p2, int objRank);
+ D3DObjLevel4* AddLevel3(D3DObjLevel3 *&p3, float min, float max);
+ D3DObjLevel5* AddLevel4(D3DObjLevel4 *&p4, int reserve);
+ D3DObjLevel6* AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type, const D3DMATERIAL7 &mat, int state, int nb);
+
+ BOOL IsVisible(int objRank);
+ BOOL DetectBBox(int objRank, FPOINT mouse);
+ BOOL DetectTriangle(FPOINT mouse, D3DVERTEX2 *triangle, int objRank, float &dist);
+ BOOL TransformPoint(D3DVECTOR &p2D, int objRank, D3DVECTOR p3D);
+ void ComputeDistance();
+ void UpdateGeometry();
+ void RenderGroundSpot();
+ void DrawShadow();
+ void DrawBackground();
+ void DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down);
+ void DrawBackgroundImageQuarter(FPOINT p1, FPOINT p2, char *name);
+ void DrawBackgroundImage();
+ void DrawPlanet();
+ void DrawFrontsize();
+ void DrawOverColor();
+ BOOL GetBBox2D(int objRank, FPOINT &min, FPOINT &max);
+ void DrawHilite();
+ void DrawMouse();
+ void DrawSprite(FPOINT pos, FPOINT dim, int icon);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DApplication* m_app;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+ CText* m_text;
+ CLight* m_light;
+ CParticule* m_particule;
+ CWater* m_water;
+ CCloud* m_cloud;
+ CBlitz* m_blitz;
+ CPlanet* m_planet;
+ CSound* m_sound;
+ CTerrain* m_terrain;
+
+ int m_blackSrcBlend[2];
+ int m_blackDestBlend[2];
+ int m_whiteSrcBlend[2];
+ int m_whiteDestBlend[2];
+ int m_diffuseSrcBlend[2];
+ int m_diffuseDestBlend[2];
+ int m_alphaSrcBlend[2];
+ int m_alphaDestBlend[2];
+
+ D3DMATRIX m_matProj;
+ D3DMATRIX m_matLeftView;
+ D3DMATRIX m_matRightView;
+ D3DMATRIX m_matView;
+ float m_focus;
+
+ D3DMATRIX m_matWorldInterface;
+ D3DMATRIX m_matProjInterface;
+ D3DMATRIX m_matViewInterface;
+
+ DWORD m_baseTime;
+ DWORD m_stopTime;
+ float m_absTime;
+ float m_lastTime;
+ float m_speed;
+ BOOL m_bPause;
+ BOOL m_bRender;
+ BOOL m_bMovieLock;
+
+ POINT m_dim;
+ POINT m_lastDim;
+ D3DObjLevel1* m_objectPointer;
+ int m_objectParamTotal;
+ D3DObject* m_objectParam;
+ int m_shadowTotal;
+ D3DShadow* m_shadow;
+ D3DGroundSpot* m_groundSpot;
+ D3DGroundMark m_groundMark;
+ D3DVECTOR m_eyePt;
+ D3DVECTOR m_lookatPt;
+ float m_eyeDirH;
+ float m_eyeDirV;
+ int m_rankView;
+ D3DCOLOR m_ambiantColor[2];
+ D3DCOLOR m_backColor[2];
+ D3DCOLOR m_fogColor[2];
+ float m_deepView[2];
+ float m_fogStart[2];
+ D3DCOLORVALUE m_waterAddColor;
+ int m_statisticTriangle;
+ BOOL m_bUpdateGeometry;
+ char m_infoText[10][200];
+ int m_alphaMode;
+ BOOL m_bStateColor;
+ BOOL m_bForceStateColor;
+ BOOL m_bGroundSpot;
+ BOOL m_bShadow;
+ BOOL m_bDirty;
+ BOOL m_bFog;
+ BOOL m_bFirstGroundSpot;
+ int m_secondTexNum;
+ char m_backgroundName[50];
+ D3DCOLOR m_backgroundColorUp;
+ D3DCOLOR m_backgroundColorDown;
+ D3DCOLOR m_backgroundCloudUp;
+ D3DCOLOR m_backgroundCloudDown;
+ BOOL m_bBackgroundFull;
+ BOOL m_bBackgroundQuarter;
+ BOOL m_bOverFront;
+ D3DCOLOR m_overColor;
+ int m_overMode;
+ char m_frontsizeName[50];
+ BOOL m_bDrawWorld;
+ BOOL m_bDrawFront;
+ float m_limitLOD[2];
+ float m_particuleDensity;
+ float m_clippingDistance;
+ float m_lastClippingDistance;
+ float m_objectDetail;
+ float m_lastObjectDetail;
+ float m_terrainVision;
+ float m_gadgetQuantity;
+ int m_textureQuality;
+ BOOL m_bTotoMode;
+ BOOL m_bLensMode;
+ BOOL m_bWaterMode;
+ BOOL m_bSkyMode;
+ BOOL m_bBackForce;
+ BOOL m_bPlanetMode;
+ BOOL m_bLightMode;
+ BOOL m_bEditIndentMode;
+ int m_editIndentValue;
+ float m_tracePrecision;
+
+ int m_hiliteRank[100];
+ BOOL m_bHilite;
+ FPOINT m_hiliteP1;
+ FPOINT m_hiliteP2;
+
+ int m_lastState;
+ D3DCOLOR m_lastColor;
+ char m_lastTexture[2][50];
+ D3DMATERIAL7 m_lastMaterial;
+
+ FPOINT m_mousePos;
+ D3DMouse m_mouseType;
+ BOOL m_bMouseHide;
+ BOOL m_bNiceMouse;
+
+ LPDIRECTDRAWSURFACE7 m_imageSurface;
+ DDSURFACEDESC2 m_imageDDSD;
+ WORD* m_imageCopy;
+ int m_imageDX;
+ int m_imageDY;
+};
+
+
+#endif //_D3DENGINE_H_
diff --git a/src/graphics/d3d/d3denum.cpp b/src/graphics/d3d/d3denum.cpp
new file mode 100644
index 0000000..46497d8
--- /dev/null
+++ b/src/graphics/d3d/d3denum.cpp
@@ -0,0 +1,621 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DEnum.cpp
+//
+// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <windowsx.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "d3denum.h"
+#include "d3dutil.h" // For DEBUG_MSG
+#include "d3dres.h" // For dialog controls
+
+
+
+
+//-----------------------------------------------------------------------------
+// Global data for the enumerator functions
+//-----------------------------------------------------------------------------
+static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL;
+
+static D3DEnum_DeviceInfo g_pDeviceList[20];
+static DWORD g_dwNumDevicesEnumerated = 0L;
+static DWORD g_dwNumDevices = 0L;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: SortModesCallback()
+// Desc: Callback function for sorting display modes.
+//-----------------------------------------------------------------------------
+int SortModesCallback( const VOID* arg1, const VOID* arg2 )
+{
+ DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1;
+ DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2;
+
+ if( p1->dwWidth < p2->dwWidth )
+ return -1;
+ if( p1->dwWidth > p2->dwWidth )
+ return +1;
+
+ if( p1->dwHeight < p2->dwHeight )
+ return -1;
+ if( p1->dwHeight > p2->dwHeight )
+ return +1;
+
+ if( p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount )
+ return -1;
+ if( p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount )
+ return +1;
+
+ return 0;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ModeEnumCallback()
+// Desc: Callback function for enumerating display modes.
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI ModeEnumCallback( DDSURFACEDESC2* pddsd,
+ VOID* pParentInfo )
+{
+ D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo;
+
+ // Reallocate storage for the modes
+ DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1];
+ memcpy( pddsdNewModes, pDevice->pddsdModes,
+ pDevice->dwNumModes * sizeof(DDSURFACEDESC2) );
+ delete pDevice->pddsdModes;
+ pDevice->pddsdModes = pddsdNewModes;
+
+ // Add the new mode
+ pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd);
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DeviceEnumCallback()
+// Desc: Callback function for enumerating devices
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI DeviceEnumCallback( TCHAR* strDesc, TCHAR* strName,
+ D3DDEVICEDESC7* pDesc,
+ VOID* pParentInfo )
+{
+ DWORD i;
+
+ // Keep track of # of devices that were enumerated
+ g_dwNumDevicesEnumerated++;
+
+ D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo;
+ D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices];
+ ZeroMemory( pDeviceInfo, sizeof(D3DEnum_DeviceInfo) );
+
+ // Select either the HAL or HEL device desc:
+ pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION;
+ memcpy( &pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7) );
+
+ // Set up device info for this device
+ pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible;
+ pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps;
+ pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps;
+ pDeviceInfo->guidDevice = pDesc->deviceGUID;
+ pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice;
+ pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes];
+
+ // Copy the driver GUID and description for the device
+ if( pDriverInfo->pDriverGUID )
+ {
+ pDeviceInfo->guidDriver = pDriverInfo->guidDriver;
+ pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver;
+ lstrcpyn( pDeviceInfo->strDesc, pDriverInfo->strDesc, 39 );
+ }
+ else
+ {
+ pDeviceInfo->pDriverGUID = NULL;
+ lstrcpyn( pDeviceInfo->strDesc, strName, 39 );
+ }
+
+//? if( strstr(strName, "T&L") != 0 ) return D3DENUMRET_OK;
+
+ // Avoid duplicates: only enum HW devices for secondary DDraw drivers.
+ if( NULL != pDeviceInfo->pDriverGUID && FALSE == pDeviceInfo->bHardware )
+ return D3DENUMRET_OK;
+
+ // Give the app a chance to accept or reject this device.
+ if( g_fnAppConfirmFn )
+ if( FAILED( g_fnAppConfirmFn( &pDeviceInfo->ddDriverCaps,
+ &pDeviceInfo->ddDeviceDesc ) ) )
+ return D3DENUMRET_OK;
+
+ // Build list of supported modes for the device
+ for( i=0; i<pDriverInfo->dwNumModes; i++ )
+ {
+ DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i];
+ DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth;
+ DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount;
+
+ // Accept modes that are compatable with the device
+ if( ( ( dwDepth == 32 ) && ( dwRenderDepths & DDBD_32 ) ) ||
+ ( ( dwDepth == 24 ) && ( dwRenderDepths & DDBD_24 ) ) ||
+ ( ( dwDepth == 16 ) && ( dwRenderDepths & DDBD_16 ) ) )
+ {
+ // Copy compatible modes to the list of device-supported modes
+ pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode;
+
+ // Record whether the device has any stereo modes
+ if( ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT )
+ pDeviceInfo->bStereoCompatible = TRUE;
+ }
+ }
+
+ // Bail if the device has no supported modes
+ if( 0 == pDeviceInfo->dwNumModes )
+ return D3DENUMRET_OK;
+
+ // Find a 640x480x16 mode for the default fullscreen mode
+ for( i=0; i<pDeviceInfo->dwNumModes; i++ )
+ {
+ if( ( pDeviceInfo->pddsdModes[i].dwWidth == 640 ) &&
+ ( pDeviceInfo->pddsdModes[i].dwHeight == 480 ) &&
+ ( pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16 ) )
+ {
+ pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i];
+ pDeviceInfo->dwCurrentMode = i;
+ }
+ }
+
+ // Select whether the device is initially windowed
+ pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible;
+
+ // Accept the device and return
+ g_dwNumDevices++;
+
+ return D3DENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DriverEnumCallback()
+// Desc: Callback function for enumerating drivers.
+//-----------------------------------------------------------------------------
+static BOOL WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,
+ TCHAR* strName, VOID*, HMONITOR )
+{
+ D3DEnum_DeviceInfo d3dDeviceInfo;
+ LPDIRECTDRAW7 pDD;
+ LPDIRECT3D7 pD3D;
+ HRESULT hr;
+
+ // Use the GUID to create the DirectDraw object
+ hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL );
+ if( FAILED(hr) )
+ {
+ DEBUG_MSG( _T("Can't create DDraw during enumeration!") );
+ return D3DENUMRET_OK;
+ }
+
+ // Create a D3D object, to enumerate the d3d devices
+ hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3D );
+ if( FAILED(hr) )
+ {
+ pDD->Release();
+ DEBUG_MSG( _T("Can't query IDirect3D7 during enumeration!") );
+ return D3DENUMRET_OK;
+ }
+
+ // Copy data to a device info structure
+ ZeroMemory( &d3dDeviceInfo, sizeof(d3dDeviceInfo) );
+ lstrcpyn( d3dDeviceInfo.strDesc, strDesc, 39 );
+ d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS);
+ d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS);
+ pDD->GetCaps( &d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps );
+ if( pGUID )
+ {
+ d3dDeviceInfo.guidDriver = (*pGUID);
+ d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver;
+ }
+
+ // Record whether the device can render into a desktop window
+ if( d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED )
+ if( NULL == d3dDeviceInfo.pDriverGUID )
+ d3dDeviceInfo.bDesktopCompatible = TRUE;
+
+ // Enumerate the fullscreen display modes.
+ pDD->EnumDisplayModes( 0, NULL, &d3dDeviceInfo, ModeEnumCallback );
+
+ // Sort list of display modes
+ qsort( d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes,
+ sizeof(DDSURFACEDESC2), SortModesCallback );
+
+ // Now, enumerate all the 3D devices
+ pD3D->EnumDevices( DeviceEnumCallback, &d3dDeviceInfo );
+
+ // Clean up and return
+ SAFE_DELETE( d3dDeviceInfo.pddsdModes );
+ pD3D->Release();
+ pDD->Release();
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_EnumerateDevices()
+// Desc: Enumerates all drivers, devices, and modes. The callback function is
+// called each device, to confirm that the device supports the feature
+// set required by the app.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_EnumerateDevices( HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) )
+{
+ // Store the device enumeration callback function
+ g_fnAppConfirmFn = AppConfirmFn;
+
+ // Enumerate drivers, devices, and modes
+ DirectDrawEnumerateEx( DriverEnumCallback, NULL,
+ DDENUM_ATTACHEDSECONDARYDEVICES |
+ DDENUM_DETACHEDSECONDARYDEVICES |
+ DDENUM_NONDISPLAYDEVICES );
+
+ // Make sure devices were actually enumerated
+ if( 0 == g_dwNumDevicesEnumerated )
+ {
+ DEBUG_MSG( _T("No devices and/or modes were enumerated!") );
+ return D3DENUMERR_ENUMERATIONFAILED;
+ }
+ if( 0 == g_dwNumDevices )
+ {
+ DEBUG_MSG( _T("No enumerated devices were accepted!") );
+ DEBUG_MSG( _T("Try enabling the D3D Reference Rasterizer.") );
+ return D3DENUMERR_SUGGESTREFRAST;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_FreeResources()
+// Desc: Cleans up any memory allocated during device enumeration
+//-----------------------------------------------------------------------------
+VOID D3DEnum_FreeResources()
+{
+ for( DWORD i=0; i<g_dwNumDevices; i++ )
+ {
+ SAFE_DELETE( g_pDeviceList[i].pddsdModes );
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_GetDevices()
+// Desc: Returns a ptr to the array of D3DEnum_DeviceInfo structures.
+//-----------------------------------------------------------------------------
+VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount )
+{
+ if( ppDevices )
+ (*ppDevices) = g_pDeviceList;
+ if( pdwCount )
+ (*pdwCount) = g_dwNumDevices;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: UpdateDialogControls()
+// Desc: Builds the list of devices and modes for the combo boxes in the device
+// select dialog box.
+//-----------------------------------------------------------------------------
+static VOID UpdateDialogControls( HWND hDlg, D3DEnum_DeviceInfo* pCurrentDevice,
+ DWORD dwCurrentMode, BOOL bWindowed,
+ BOOL bStereo )
+{
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Access to UI controls
+ HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
+ HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO );
+ HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX );
+ HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX );
+ HWND hwndFullscreenText = GetDlgItem( hDlg, IDC_FULLSCREEN_TEXT );
+
+ // Reset the content in each of the combo boxes
+ ComboBox_ResetContent( hwndDevice );
+ ComboBox_ResetContent( hwndMode );
+
+ // Don't let non-GDI devices be windowed
+ if( FALSE == pCurrentDevice->bDesktopCompatible )
+ bWindowed = FALSE;
+
+ // Add a list of devices to the device combo box
+ for( DWORD device = 0; device < dwNumDevices; device++ )
+ {
+ D3DEnum_DeviceInfo* pDevice = &pDeviceList[device];
+
+ // Add device name to the combo box
+ DWORD dwItem = ComboBox_AddString( hwndDevice, pDevice->strDesc );
+
+ // Set the remaining UI states for the current device
+ if( pDevice == pCurrentDevice )
+ {
+ // Set the combobox selection on the current device
+ ComboBox_SetCurSel( hwndDevice, dwItem );
+
+ // Enable/set the fullscreen checkbox, as appropriate
+ if( hwndWindowed )
+ {
+ EnableWindow( hwndWindowed, pDevice->bDesktopCompatible );
+ Button_SetCheck( hwndWindowed, bWindowed );
+ }
+
+ // Enable/set the stereo checkbox, as appropriate
+ if( hwndStereo )
+ {
+ EnableWindow( hwndStereo, pDevice->bStereoCompatible && !bWindowed );
+ Button_SetCheck( hwndStereo, bStereo );
+ }
+
+ // Enable/set the fullscreen modes combo, as appropriate
+ EnableWindow( hwndMode, !bWindowed );
+ EnableWindow( hwndFullscreenText, !bWindowed );
+
+ // Build the list of fullscreen modes
+ for( DWORD mode = 0; mode < pDevice->dwNumModes; mode++ )
+ {
+ DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode];
+
+ // Skip non-stereo modes, if the device is in stereo mode
+ if( 0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT) )
+ if( bStereo )
+ continue;
+
+ TCHAR strMode[80];
+ wsprintf( strMode, _T("%ld x %ld x %ld"),
+ pddsdMode->dwWidth, pddsdMode->dwHeight,
+ pddsdMode->ddpfPixelFormat.dwRGBBitCount );
+
+ // Add mode desc to the combo box
+ DWORD dwItem = ComboBox_AddString( hwndMode, strMode );
+
+ // Set the item data to identify this mode
+ ComboBox_SetItemData( hwndMode, dwItem, mode );
+
+ // Set the combobox selection on the current mode
+ if( mode == dwCurrentMode )
+ ComboBox_SetCurSel( hwndMode, dwItem );
+
+ // Since not all modes support stereo, select a default mode in
+ // case none was chosen yet.
+ if( bStereo && ( CB_ERR == ComboBox_GetCurSel( hwndMode ) ) )
+ ComboBox_SetCurSel( hwndMode, dwItem );
+ }
+ }
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ChangeDeviceProc()
+// Desc: Windows message handling function for the device select dialog
+//-----------------------------------------------------------------------------
+static INT_PTR CALLBACK ChangeDeviceProc( HWND hDlg, UINT uiMsg, WPARAM wParam,
+ LPARAM lParam )
+{
+ static D3DEnum_DeviceInfo** ppDeviceArg;
+ static D3DEnum_DeviceInfo* pCurrentDevice;
+ static DWORD dwCurrentMode;
+ static BOOL bCurrentWindowed;
+ static BOOL bCurrentStereo;
+
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Handle the initialization message
+ if( WM_INITDIALOG == uiMsg )
+ {
+ // Get the app's current device, passed in as an lParam argument
+ ppDeviceArg = (D3DEnum_DeviceInfo**)lParam;
+ if( NULL == ppDeviceArg )
+ return FALSE;
+
+ // Setup temp storage pointers for dialog
+ pCurrentDevice = (*ppDeviceArg);
+ dwCurrentMode = pCurrentDevice->dwCurrentMode;
+ bCurrentWindowed = pCurrentDevice->bWindowed;
+ bCurrentStereo = pCurrentDevice->bStereo;
+
+ UpdateDialogControls( hDlg, pCurrentDevice, dwCurrentMode,
+ bCurrentWindowed, bCurrentStereo );
+
+ return TRUE;
+ }
+ else if( WM_COMMAND == uiMsg )
+ {
+ HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
+ HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO );
+ HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX );
+ HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX );
+
+ // Get current UI state
+ DWORD dwDevice = ComboBox_GetCurSel( hwndDevice );
+ DWORD dwModeItem = ComboBox_GetCurSel( hwndMode );
+ DWORD dwMode = ComboBox_GetItemData( hwndMode, dwModeItem );
+ BOOL bWindowed = hwndWindowed ? Button_GetCheck( hwndWindowed ) : 0;
+ BOOL bStereo = hwndStereo ? Button_GetCheck( hwndStereo ) : 0;
+
+ D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice];
+
+ if( IDOK == LOWORD(wParam) )
+ {
+ // Handle the case when the user hits the OK button. Check if any
+ // of the options were changed
+ if( pDevice != pCurrentDevice || dwMode != dwCurrentMode ||
+ bWindowed != bCurrentWindowed || bStereo != bCurrentStereo )
+ {
+ // Return the newly selected device and its new properties
+ (*ppDeviceArg) = pDevice;
+ pDevice->bWindowed = bWindowed;
+ pDevice->bStereo = bStereo;
+ pDevice->dwCurrentMode = dwMode;
+ pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode];
+
+ EndDialog( hDlg, IDOK );
+ }
+ else
+ EndDialog( hDlg, IDCANCEL );
+
+ return TRUE;
+ }
+ else if( IDCANCEL == LOWORD(wParam) )
+ {
+ // Handle the case when the user hits the Cancel button
+ EndDialog( hDlg, IDCANCEL );
+ return TRUE;
+ }
+ else if( CBN_SELENDOK == HIWORD(wParam) )
+ {
+ if( LOWORD(wParam) == IDC_DEVICE_COMBO )
+ {
+ // Handle the case when the user chooses the device combo
+ dwMode = pDeviceList[dwDevice].dwCurrentMode;
+ bWindowed = pDeviceList[dwDevice].bWindowed;
+ bStereo = pDeviceList[dwDevice].bStereo;
+ }
+ }
+
+ // Keep the UI current
+ UpdateDialogControls( hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_UserChangeDevice()
+// Desc: Pops up a dialog which allows the user to select a new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice )
+{
+ if( IDOK == DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_CHANGEDEVICE),
+ GetForegroundWindow(),
+ ChangeDeviceProc, (LPARAM)ppDevice ) )
+ return S_OK;
+
+ return E_FAIL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_SelectDefaultDevice()
+// Desc: Pick a default device, preferably hardware and desktop compatible.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** ppDevice,
+ DWORD dwFlags )
+{
+ // Check arguments
+ if( NULL == ppDevice )
+ return E_INVALIDARG;
+
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Look for windowable software, hardware, and hardware TnL devices
+ D3DEnum_DeviceInfo* pRefRastDevice = NULL;
+ D3DEnum_DeviceInfo* pSoftwareDevice = NULL;
+ D3DEnum_DeviceInfo* pHardwareDevice = NULL;
+ D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL;
+
+ for( DWORD i=0; i<dwNumDevices; i++ )
+ {
+ if( pDeviceList[i].bDesktopCompatible )
+ {
+ if( pDeviceList[i].bHardware )
+ {
+ if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DTnLHalDevice )
+ pHardwareTnLDevice = &pDeviceList[i];
+ else
+ pHardwareDevice = &pDeviceList[i];
+ }
+ else
+ {
+ if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DRefDevice )
+ pRefRastDevice = &pDeviceList[i];
+ else
+ pSoftwareDevice = &pDeviceList[i];
+ }
+ }
+ }
+
+ // Prefer a hardware non-TnL device first, then a TnL hardware device, and
+ // finally, a software device.
+ if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareDevice )
+ (*ppDevice) = pHardwareDevice;
+ else if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareTnLDevice )
+ (*ppDevice) = pHardwareTnLDevice;
+ else if( pSoftwareDevice )
+ (*ppDevice) = pSoftwareDevice;
+ else if( pRefRastDevice )
+ (*ppDevice) = pRefRastDevice;
+ else
+ return D3DENUMERR_NOCOMPATIBLEDEVICES;
+
+ // Set the windowed state of the newly selected device
+ (*ppDevice)->bWindowed = TRUE;
+
+ return S_OK;
+}
+
+
+
+
+
diff --git a/src/graphics/d3d/d3denum.h b/src/graphics/d3d/d3denum.h
new file mode 100644
index 0000000..e728ffb
--- /dev/null
+++ b/src/graphics/d3d/d3denum.h
@@ -0,0 +1,136 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DEnum.h
+//
+// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DENUM_H
+#define D3DENUM_H
+#include <d3d.h>
+
+
+//-----------------------------------------------------------------------------
+// Flag and error definitions
+//-----------------------------------------------------------------------------
+#define D3DENUM_SOFTWAREONLY 0x00000001 // Software-devices only flag
+
+#define D3DENUMERR_NODIRECTDRAW 0x81000001 // Could not create DDraw
+#define D3DENUMERR_ENUMERATIONFAILED 0x81000002 // Enumeration failed
+#define D3DENUMERR_SUGGESTREFRAST 0x81000003 // Suggest using the RefRast
+#define D3DENUMERR_NOCOMPATIBLEDEVICES 0x81000004 // No devices were found that
+ // meet the app's desired
+ // capabilities
+#define D3DENUMERR_ENGINE 0x81000005 // 3D engine error
+#define D3DENUMERR_ROBOT 0x81000006 // robot error
+#define D3DENUMERR_SOUND 0x81000007 // sound error
+
+
+//-----------------------------------------------------------------------------
+// Name: struct D3DEnum_DeviceInfo
+// Desc: Structure to hold info about the enumerated Direct3D devices.
+//-----------------------------------------------------------------------------
+struct D3DEnum_DeviceInfo
+{
+ // D3D Device info
+ TCHAR strDesc[40];
+ GUID* pDeviceGUID;
+ D3DDEVICEDESC7 ddDeviceDesc;
+ BOOL bHardware;
+
+ // DDraw Driver info
+ GUID* pDriverGUID;
+ DDCAPS ddDriverCaps;
+ DDCAPS ddHELCaps;
+
+ // DDraw Mode Info
+ DDSURFACEDESC2 ddsdFullscreenMode;
+ BOOL bWindowed;
+ BOOL bStereo;
+
+ // For internal use (apps should not need to use these)
+ GUID guidDevice;
+ GUID guidDriver;
+ DDSURFACEDESC2* pddsdModes;
+ DWORD dwNumModes;
+ DWORD dwCurrentMode;
+ BOOL bDesktopCompatible;
+ BOOL bStereoCompatible;
+};
+
+
+// For code not yet switched to new struct name
+typedef D3DEnum_DeviceInfo D3DDEVICEINFO;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_EnumerateDevices()
+// Desc: Enumerates all drivers, devices, and modes. The callback function is
+// called each device, to confirm that the device supports the feature
+// set required by the app.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_EnumerateDevices( HRESULT (*fn)(DDCAPS*, D3DDEVICEDESC7*) );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_FreeResources()
+// Desc: Cleans up any memory allocated during device enumeration
+//-----------------------------------------------------------------------------
+VOID D3DEnum_FreeResources();
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_GetDevices()
+// Desc: Returns a ptr to the array of enumerated D3DDEVICEINFO structures.
+//-----------------------------------------------------------------------------
+VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_SelectDefaultDevice()
+// Desc: Picks a driver based on a set of passed in criteria. The
+// D3DENUM_SOFTWAREONLY flag can be used to pick a software device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** pDevice,
+ DWORD dwFlags = 0L );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_UserChangeDevice()
+// Desc: Pops up a dialog which allows the user to select a new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice );
+
+
+
+
+#endif // D3DENUM_H
+
+
+
diff --git a/src/graphics/d3d/d3dframe.cpp b/src/graphics/d3d/d3dframe.cpp
new file mode 100644
index 0000000..3207a4b
--- /dev/null
+++ b/src/graphics/d3d/d3dframe.cpp
@@ -0,0 +1,623 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DFrame.cpp
+//
+// Desc: Class functions to implement a Direct3D app framework.
+//
+// Copyright (c) 1995-1999 by Microsoft, all rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <windows.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "d3dframe.h"
+#include "d3dutil.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DFramework7()
+// Desc: The constructor. Clears static variables
+//-----------------------------------------------------------------------------
+CD3DFramework7::CD3DFramework7()
+{
+ m_hWnd = NULL;
+ m_bIsFullscreen = FALSE;
+ m_bIsStereo = FALSE;
+ m_dwRenderWidth = 0L;
+ m_dwRenderHeight = 0L;
+
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+
+ m_pddsZBuffer = NULL;
+ m_pd3dDevice = NULL;
+ m_pDD = NULL;
+ m_pD3D = NULL;
+ m_dwDeviceMemType = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CD3DFramework7()
+// Desc: The destructor. Deletes all objects
+//-----------------------------------------------------------------------------
+CD3DFramework7::~CD3DFramework7()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc: Cleans everything up upon deletion. This code returns an error
+// if any of the objects have remaining reference counts.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::DestroyObjects()
+{
+ LONG nDD = 0L; // Number of outstanding DDraw references
+ LONG nD3D = 0L; // Number of outstanding D3DDevice references
+
+ if( m_pDD )
+ {
+ HRESULT err = m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+ char s[100];
+ sprintf(s, "SetCooperativeLevel error=%d\n", err);
+ OutputDebugString(s);
+ }
+
+ // Do a safe check for releasing the D3DDEVICE. RefCount must be zero.
+ if( m_pd3dDevice )
+ if( 0 < ( nD3D = m_pd3dDevice->Release() ) )
+ DEBUG_MSG( _T("Error: D3DDevice object is still referenced!") );
+ m_pd3dDevice = NULL;
+
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsZBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+ SAFE_RELEASE( m_pD3D );
+
+ if( m_pDD )
+ {
+ // Do a safe check for releasing DDRAW. RefCount must be zero.
+ if( 0 < ( nDD = m_pDD->Release() ) )
+ DEBUG_MSG( _T("Error: DDraw object is still referenced!") );
+ }
+ m_pDD = NULL;
+
+ // Return successful, unless there are outstanding DD or D3DDevice refs.
+ return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Initialize()
+// Desc: Creates the internal objects for the framework
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::Initialize( HWND hWnd, GUID* pDriverGUID,
+ GUID* pDeviceGUID, DDSURFACEDESC2* pMode,
+ DWORD dwFlags )
+{
+ HRESULT hr;
+
+ // Check params. Note: A NULL mode is valid for windowed modes only.
+ if( ( NULL==hWnd ) || ( NULL==pDeviceGUID ) ||
+ ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) )
+ return E_INVALIDARG;
+
+ // Setup state for windowed/fullscreen mode
+ m_hWnd = hWnd;
+ m_bIsStereo = FALSE;
+ m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE;
+
+ // Support stereoscopic viewing for fullscreen modes which support it
+ if( ( dwFlags & D3DFW_STEREO ) && ( dwFlags & D3DFW_FULLSCREEN ) )
+ if( pMode->ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT )
+ m_bIsStereo = TRUE;
+
+ // Create the D3D rendering environment (surfaces, device, viewport, etc.)
+ if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode,
+ dwFlags ) ) )
+ {
+ DestroyObjects();
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateEnvironment()
+// Desc: Creates the internal objects for the framework
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID,
+ DDSURFACEDESC2* pMode, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ // Select the default memory type, for whether the device is HW or SW
+ if( IsEqualIID( *pDeviceGUID, IID_IDirect3DHALDevice) )
+ m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
+ else if( IsEqualIID( *pDeviceGUID, IID_IDirect3DTnLHalDevice) )
+ m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
+ else
+ m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY;
+
+ // Create the DDraw object
+ hr = CreateDirectDraw( pDriverGUID, dwFlags );
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create the front and back buffers, and attach a clipper
+ if( dwFlags & D3DFW_FULLSCREEN )
+ hr = CreateFullscreenBuffers( pMode );
+ else
+ hr = CreateWindowedBuffers();
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create the Direct3D object and the Direct3DDevice object
+ hr = CreateDirect3D( pDeviceGUID );
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create and attach the zbuffer
+ if( dwFlags & D3DFW_ZBUFFER )
+ hr = CreateZBuffer( pDeviceGUID );
+ if( FAILED( hr ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: EnumZBufferFormatsCallback()
+// Desc: Simply returns the first matching enumerated z-buffer format
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf,
+ VOID* pContext )
+{
+ DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext;
+
+ if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount )
+ {
+ (*pddpfOut) = (*pddpf);
+ return D3DENUMRET_CANCEL;
+ }
+
+ return D3DENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateDirectDraw()
+// Desc: Create the DirectDraw interface
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags )
+{
+ // Create the DirectDraw interface, and query for the DD7 interface
+ if( FAILED( DirectDrawCreateEx( pDriverGUID, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Could not create DirectDraw") );
+ return D3DFWERR_NODIRECTDRAW;
+ }
+
+ // Set the Windows cooperative level
+ DWORD dwCoopFlags = DDSCL_NORMAL;
+ if( m_bIsFullscreen )
+ dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN;
+
+ // By defualt, set the flag to allow D3D to optimize floating point calcs
+ if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) )
+ dwCoopFlags |= DDSCL_FPUSETUP;
+
+ if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) )
+ {
+ DEBUG_MSG( _T("Couldn't set coop level") );
+ return D3DFWERR_COULDNTSETCOOPLEVEL;
+ }
+
+ // Check that we are NOT in a palettized display. That case will fail,
+ // since the framework doesn't use palettes.
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pDD->GetDisplayMode( &ddsd );
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 )
+ return D3DFWERR_INVALIDMODE;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullscreenBuffers()
+// Desc: Creates the primary and (optional) backbuffer for rendering.
+// Windowed mode and fullscreen mode are handled differently.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateFullscreenBuffers( DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Get the dimensions of the screen bounds
+ // Store the rectangle which contains the renderer
+ SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight );
+ m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
+ m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
+
+ // Set the display mode to the requested dimensions. Check for
+ // 320x200x8 modes, and set flag to avoid using ModeX
+ DWORD dwModeFlags = 0;
+
+ if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) &&
+ (8==pddsd->ddpfPixelFormat.dwRGBBitCount) )
+ dwModeFlags |= DDSDM_STANDARDVGAMODE;
+
+ if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight,
+ pddsd->ddpfPixelFormat.dwRGBBitCount,
+ pddsd->dwRefreshRate, dwModeFlags ) ) )
+ {
+ DEBUG_MSG( _T("Can't set display mode") );
+ return D3DFWERR_BADDISPLAYMODE;
+ }
+
+ // Setup to create the primary surface w/backbuffer
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE |
+ DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ ddsd.dwBackBufferCount = 1;
+
+ // Support for stereoscopic viewing
+ if( m_bIsStereo )
+ {
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
+ }
+
+ // Create the primary surface
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Can't create primary surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOPRIMARY;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ // Get the backbuffer, which was created along with the primary.
+ DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 };
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Can't get the backbuffer") );
+ return D3DFWERR_NOBACKBUFFER;
+ }
+
+ // Increment the backbuffer count (for consistency with windowed mode)
+ m_pddsBackBuffer->AddRef();
+
+ // Support for stereoscopic viewing
+ if( m_bIsStereo )
+ {
+ // Get the left backbuffer, which was created along with the primary.
+ DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 };
+ if( FAILED( hr = m_pddsBackBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBufferLeft ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Can't get the left backbuffer") );
+ return D3DFWERR_NOBACKBUFFER;
+ }
+ m_pddsBackBufferLeft->AddRef();
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedBuffers()
+// Desc: Creates the primary and (optional) backbuffer for rendering.
+// Windowed mode and fullscreen mode are handled differently.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateWindowedBuffers()
+{
+ HRESULT hr;
+
+ // Get the dimensions of the viewport and screen bounds
+ GetClientRect( m_hWnd, &m_rcScreenRect );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right );
+ m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
+ m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Can't create primary surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOPRIMARY;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ // If in windowed-mode, create a clipper object
+ LPDIRECTDRAWCLIPPER pcClipper;
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't create clipper") );
+ return D3DFWERR_NOCLIPPER;
+ }
+
+ // Associate the clipper with the window
+ pcClipper->SetHWnd( 0, m_hWnd );
+ m_pddsFrontBuffer->SetClipper( pcClipper );
+ SAFE_RELEASE( pcClipper );
+
+ // Create a backbuffer
+ ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+ ddsd.dwWidth = m_dwRenderWidth;
+ ddsd.dwHeight = m_dwRenderHeight;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOBACKBUFFER;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateDirect3D()
+// Desc: Create the Direct3D interface
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateDirect3D( GUID* pDeviceGUID )
+{
+ // Query DirectDraw for access to Direct3D
+ if( FAILED( m_pDD->QueryInterface( IID_IDirect3D7, (VOID**)&m_pD3D ) ) )
+ {
+ DEBUG_MSG( _T("Couldn't get the Direct3D interface") );
+ return D3DFWERR_NODIRECT3D;
+ }
+
+ // Create the device
+ if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsBackBuffer,
+ &m_pd3dDevice) ) )
+ {
+ DEBUG_MSG( _T("Couldn't create the D3DDevice") );
+ return D3DFWERR_NO3DDEVICE;
+ }
+
+ // Finally, set the viewport for the newly created device
+ D3DVIEWPORT7 vp = { 0, 0, m_dwRenderWidth, m_dwRenderHeight, 0.0f, 1.0f };
+
+ if( FAILED( m_pd3dDevice->SetViewport( &vp ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't set current viewport to device") );
+ return D3DFWERR_NOVIEWPORT;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateZBuffer()
+// Desc: Internal function called by Create() to make and attach a zbuffer
+// to the renderer
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateZBuffer( GUID* pDeviceGUID )
+{
+ HRESULT hr;
+
+ // Check if the device supports z-bufferless hidden surface removal. If so,
+ // we don't really need a z-buffer
+ D3DDEVICEDESC7 ddDesc;
+ m_pd3dDevice->GetCaps( &ddDesc );
+ if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )
+ return S_OK;
+
+ // Get z-buffer dimensions from the render target
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsBackBuffer->GetSurfaceDesc( &ddsd );
+
+ // Setup the surface desc for the z-buffer.
+ ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType;
+ ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized
+
+ // Get an appropiate pixel format from enumeration of the formats. On the
+ // first pass, we look for a zbuffer dpeth which is equal to the frame
+ // buffer depth (as some cards unfornately require this).
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ // Try again, just accepting any 16-bit zbuffer
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ DEBUG_MSG( _T("Device doesn't support requested zbuffer format") );
+ return D3DFWERR_NOZBUFFER;
+ }
+ }
+
+ // Create and attach a z-buffer
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOZBUFFER;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ if( FAILED( m_pddsBackBuffer->AddAttachedSurface( m_pddsZBuffer ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ // For stereoscopic viewing, attach zbuffer to left surface as well
+ if( m_bIsStereo )
+ {
+ if( FAILED( m_pddsBackBufferLeft->AddAttachedSurface( m_pddsZBuffer ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't attach zbuffer to left render surface") );
+ return D3DFWERR_NOZBUFFER;
+ }
+ }
+
+ // Finally, this call rebuilds internal structures
+ if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsBackBuffer, 0L ) ) )
+ {
+ DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: RestoreSurfaces()
+// Desc: Checks for lost surfaces and restores them if lost. Note: Don't
+// restore render surface, since it's just a duplicate ptr.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::RestoreSurfaces()
+{
+ // Restore all surfaces (including video memory vertex buffers)
+ m_pDD->RestoreAllSurfaces();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Move()
+// Desc: Moves the screen rect for windowed renderers
+//-----------------------------------------------------------------------------
+VOID CD3DFramework7::Move( INT x, INT y )
+{
+ if( TRUE == m_bIsFullscreen )
+ return;
+
+ SetRect( &m_rcScreenRect, x, y, x + m_dwRenderWidth, y + m_dwRenderHeight );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: FlipToGDISurface()
+// Desc: Puts the GDI surface in front of the primary, so that dialog
+// boxes and other windows drawing funcs may happen.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::FlipToGDISurface( BOOL bDrawFrame )
+{
+ if( m_pDD && m_bIsFullscreen )
+ {
+ m_pDD->FlipToGDISurface();
+
+ if( bDrawFrame )
+ {
+ DrawMenuBar( m_hWnd );
+ RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ShowFrame()
+// Desc: Show the frame on the primary surface, via a blt or a flip.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::ShowFrame()
+{
+ if( NULL == m_pddsFrontBuffer )
+ return D3DFWERR_NOTINITIALIZED;
+
+ if( m_bIsFullscreen )
+ {
+ // We are in fullscreen mode, so perform a flip.
+ if( m_bIsStereo )
+ return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO );
+ else
+ return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT );
+ }
+ else
+ {
+ // We are in windowed mode, so perform a blit.
+ return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ }
+}
+
+
+
diff --git a/src/graphics/d3d/d3dframe.h b/src/graphics/d3d/d3dframe.h
new file mode 100644
index 0000000..8e41b83
--- /dev/null
+++ b/src/graphics/d3d/d3dframe.h
@@ -0,0 +1,142 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DFrame.h
+//
+// Desc: Class to manage the Direct3D environment objects such as buffers,
+// viewports, and 3D devices.
+//
+// The class is initialized with the Initialize() function, after which
+// the Get????() functions can be used to access the objects needed for
+// rendering. If the device or display needs to be changed, the
+// ChangeDevice() function can be called. If the display window is moved
+// the changes need to be reported with the Move() function.
+//
+// After rendering a frame, the ShowFrame() function filps or blits the
+// backbuffer contents to the primary. If surfaces are lost, they can be
+// restored with the RestoreSurfaces() function. Finally, if normal
+// Windows output is needed, the FlipToGDISurface() provides a GDI
+// surface to draw on.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DFRAME_H
+#define D3DFRAME_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DFramework7
+// Desc: The Direct3D sample framework class for DX7. Maintains the D3D
+// surfaces and device used for 3D rendering.
+//-----------------------------------------------------------------------------
+class CD3DFramework7
+{
+ // Internal variables for the framework class
+ HWND m_hWnd; // The window object
+ BOOL m_bIsFullscreen; // Fullscreen vs. windowed
+ BOOL m_bIsStereo; // Stereo view mode
+ DWORD m_dwRenderWidth; // Dimensions of the render target
+ DWORD m_dwRenderHeight;
+ RECT m_rcScreenRect; // Screen rect for window
+ LPDIRECTDRAW7 m_pDD; // The DirectDraw object
+ LPDIRECT3D7 m_pD3D; // The Direct3D object
+ LPDIRECT3DDEVICE7 m_pd3dDevice; // The D3D device
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer; // The primary surface
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer; // The backbuffer surface
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+ LPDIRECTDRAWSURFACE7 m_pddsZBuffer; // The zbuffer surface
+ DWORD m_dwDeviceMemType;
+
+ // Internal functions for the framework class
+ HRESULT CreateZBuffer( GUID* );
+ HRESULT CreateFullscreenBuffers( DDSURFACEDESC2* );
+ HRESULT CreateWindowedBuffers();
+ HRESULT CreateDirectDraw( GUID*, DWORD );
+ HRESULT CreateDirect3D( GUID* );
+ HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*, DWORD );
+
+public:
+ // Access functions for DirectX objects
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECT3D7 GetDirect3D() { return m_pD3D; }
+ LPDIRECT3DDEVICE7 GetD3DDevice() { return m_pd3dDevice; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetRenderSurface() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetRenderSurfaceLeft() { return m_pddsBackBufferLeft; }
+
+ // Functions to aid rendering
+ HRESULT RestoreSurfaces();
+ HRESULT ShowFrame();
+ HRESULT FlipToGDISurface( BOOL bDrawFrame = FALSE );
+
+ // Functions for managing screen and viewport bounds
+ BOOL IsFullscreen() { return m_bIsFullscreen; }
+ BOOL IsStereo() { return m_bIsStereo; }
+ VOID Move( INT x, INT y );
+
+ // Creates the Framework
+ HRESULT Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID,
+ DDSURFACEDESC2* pddsd, DWORD dwFlags );
+ HRESULT DestroyObjects();
+
+ CD3DFramework7();
+ ~CD3DFramework7();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags used for the Initialize() method of a CD3DFramework object
+//-----------------------------------------------------------------------------
+#define D3DFW_FULLSCREEN 0x00000001 // Use fullscreen mode
+#define D3DFW_STEREO 0x00000002 // Use stereo-scopic viewing
+#define D3DFW_ZBUFFER 0x00000004 // Create and use a zbuffer
+#define D3DFW_NO_FPUSETUP 0x00000008 // Don't use default DDSCL_FPUSETUP flag
+
+
+
+
+//-----------------------------------------------------------------------------
+// Errors that the Initialize() and ChangeDriver() calls may return
+//-----------------------------------------------------------------------------
+#define D3DFWERR_INITIALIZATIONFAILED 0x82000000
+#define D3DFWERR_NODIRECTDRAW 0x82000001
+#define D3DFWERR_COULDNTSETCOOPLEVEL 0x82000002
+#define D3DFWERR_NODIRECT3D 0x82000003
+#define D3DFWERR_NO3DDEVICE 0x82000004
+#define D3DFWERR_NOZBUFFER 0x82000005
+#define D3DFWERR_INVALIDZBUFFERDEPTH 0x82000006
+#define D3DFWERR_NOVIEWPORT 0x82000007
+#define D3DFWERR_NOPRIMARY 0x82000008
+#define D3DFWERR_NOCLIPPER 0x82000009
+#define D3DFWERR_BADDISPLAYMODE 0x8200000a
+#define D3DFWERR_NOBACKBUFFER 0x8200000b
+#define D3DFWERR_NONZEROREFCOUNT 0x8200000c
+#define D3DFWERR_NORENDERTARGET 0x8200000d
+#define D3DFWERR_INVALIDMODE 0x8200000e
+#define D3DFWERR_NOTINITIALIZED 0x8200000f
+
+
+#endif // D3DFRAME_H
+
+
diff --git a/src/graphics/d3d/d3dtextr.cpp b/src/graphics/d3d/d3dtextr.cpp
new file mode 100644
index 0000000..cceab99
--- /dev/null
+++ b/src/graphics/d3d/d3dtextr.cpp
@@ -0,0 +1,1080 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DTextr.cpp
+//
+// Desc: Functions to manage textures, including creating (loading from a
+// file), restoring lost surfaces, invalidating, and destroying.
+//
+// Note: the implementation of these fucntions maintain an internal list
+// of loaded textures. After creation, individual textures are referenced
+// via their ASCII names.
+//
+// Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <tchar.h>
+#include <stdio.h>
+#include "d3dtextr.h"
+#include "d3dutil.h"
+#include "language.h"
+#include "misc.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Macros, function prototypes and static variable
+//-----------------------------------------------------------------------------
+static TCHAR g_strTexturePath[512] = _T(""); // Path for files
+static BOOL g_bDebugMode = FALSE;
+
+
+
+void D3DTextr_SetDebugMode(BOOL bDebug)
+{
+ g_bDebugMode = bDebug;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureContainer
+// Desc: Linked list structure to hold info per texture
+//-----------------------------------------------------------------------------
+struct TextureContainer
+{
+ TextureContainer* m_pNext; // Linked list ptr
+
+ TCHAR m_strName[80]; // Name of texture (doubles as image filename)
+ DWORD m_dwWidth;
+ DWORD m_dwHeight;
+ DWORD m_dwStage; // Texture stage (for multitexture devices)
+ DWORD m_dwBPP;
+ DWORD m_dwFlags;
+ BOOL m_bHasAlpha;
+
+ LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture
+ HBITMAP m_hbmBitmap; // Bitmap containing texture image
+ DWORD* m_pRGBAData;
+
+public:
+ HRESULT LoadImageData();
+ HRESULT LoadBitmapFile( TCHAR* strPathname );
+ HRESULT LoadTargaFile( TCHAR* strPathname, TCHAR* strFilename );
+ HRESULT Restore( LPDIRECT3DDEVICE7 pd3dDevice );
+ HRESULT CopyBitmapToSurface();
+ HRESULT CopyRGBADataToSurface();
+
+ TextureContainer( TCHAR* strName, DWORD dwStage, DWORD dwFlags );
+ ~TextureContainer();
+};
+
+// Local list of textures
+static TextureContainer* g_ptcTextureList = NULL;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DTextureManager
+// Desc: Class used to automatically construct and destruct the static
+// texture engine class.
+//-----------------------------------------------------------------------------
+class CD3DTextureManager
+{
+public:
+ CD3DTextureManager() {}
+ ~CD3DTextureManager() { if( g_ptcTextureList ) delete g_ptcTextureList; }
+};
+
+// Global instance
+CD3DTextureManager g_StaticTextureEngine;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: struct TEXTURESEARCHINFO
+// Desc: Structure used to search for texture formats
+//-----------------------------------------------------------------------------
+struct TEXTURESEARCHINFO
+{
+ DWORD dwDesiredBPP; // Input for texture format search
+ BOOL bUseAlpha;
+ BOOL bUsePalette;
+ BOOL bFoundGoodFormat;
+
+ DDPIXELFORMAT* pddpf; // Output of texture format search
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureSearchCallback()
+// Desc: Enumeration callback routine to find a best-matching texture format.
+// The param data is the DDPIXELFORMAT of the best-so-far matching
+// texture. Note: the desired BPP is passed in the dwSize field, and the
+// default BPP is passed in the dwFlags field.
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf,
+ VOID* param )
+{
+ if( NULL==pddpf || NULL==param )
+ return DDENUMRET_OK;
+
+ TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
+
+ // Skip any funky modes
+ if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) )
+ return DDENUMRET_OK;
+
+ // Check for palettized formats
+ if( ptsi->bUsePalette )
+ {
+ if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) )
+ return DDENUMRET_OK;
+
+ // Accept the first 8-bit palettized format we get
+ memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
+ ptsi->bFoundGoodFormat = TRUE;
+ return DDENUMRET_CANCEL;
+ }
+
+ // Else, skip any paletized formats (all modes under 16bpp)
+ if( pddpf->dwRGBBitCount < 16 )
+ return DDENUMRET_OK;
+
+ // Skip any FourCC formats
+ if( pddpf->dwFourCC != 0 )
+ return DDENUMRET_OK;
+
+ // Skip any ARGB 4444 formats (which are best used for pre-authored
+ // content designed speciafically for an ARGB 4444 format).
+ if( pddpf->dwRGBAlphaBitMask == 0x0000f000 )
+ return DDENUMRET_OK;
+
+ // Make sure current alpha format agrees with requested format type
+ if( (ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) )
+ return DDENUMRET_OK;
+ if( (ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) )
+ return DDENUMRET_OK;
+
+ // Check if we found a good match
+ if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP )
+ {
+ memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
+ ptsi->bFoundGoodFormat = TRUE;
+ return DDENUMRET_CANCEL;
+ }
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: FindTexture()
+// Desc: Searches the internal list of textures for a texture specified by
+// its name. Returns the structure associated with that texture.
+//-----------------------------------------------------------------------------
+static TextureContainer* FindTexture( TCHAR* strTextureName )
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ if( !lstrcmpi( strTextureName, ptcTexture->m_strName ) )
+ return ptcTexture;
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureContainer()
+// Desc: Constructor for a texture object
+//-----------------------------------------------------------------------------
+TextureContainer::TextureContainer( TCHAR* strName, DWORD dwStage,
+ DWORD dwFlags )
+{
+ lstrcpy( m_strName, strName );
+ m_dwWidth = 0;
+ m_dwHeight = 0;
+ m_dwStage = dwStage;
+ m_dwBPP = 0;
+ m_dwFlags = dwFlags;
+ m_bHasAlpha = 0;
+
+ m_pddsSurface = NULL;
+ m_hbmBitmap = NULL;
+ m_pRGBAData = NULL;
+
+ // Add the texture to the head of the global texture list
+ m_pNext = g_ptcTextureList;
+ g_ptcTextureList = this;
+
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~TextureContainer()
+// Desc: Destructs the contents of the texture container
+//-----------------------------------------------------------------------------
+TextureContainer::~TextureContainer()
+{
+ SAFE_RELEASE( m_pddsSurface );
+ SAFE_DELETE( m_pRGBAData );
+ DeleteObject( m_hbmBitmap );
+
+ // Remove the texture container from the global list
+ if( g_ptcTextureList == this )
+ g_ptcTextureList = m_pNext;
+ else
+ {
+ for( TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext )
+ if( ptc->m_pNext == this )
+ ptc->m_pNext = m_pNext;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadImageData()
+// Desc: Loads the texture map's image data
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadImageData()
+{
+ TCHAR* strExtension;
+ TCHAR strMetaname[256];
+ TCHAR strFilename[256];
+
+ if ( g_bDebugMode )
+ {
+ if ( _tcsrchr( m_strName, _T('\\') ) == 0 )
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, g_strTexturePath );
+ lstrcat( strFilename, m_strName );
+ }
+ else
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, m_strName );
+ }
+ }
+ else
+ {
+ if ( _tcsrchr( m_strName, _T('\\') ) == 0 )
+ {
+#if _SCHOOL
+ lstrcpy( strMetaname, "ceebot1.dat" );
+#else
+ lstrcpy( strMetaname, "colobot1.dat" );
+#endif
+ lstrcpy( strFilename, m_strName );
+ }
+ else
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, m_strName );
+ }
+ }
+
+ if ( !g_metafile.IsExist(strMetaname, strFilename) )
+ {
+ return DDERR_NOTFOUND;
+ }
+
+ // Get the filename extension
+ if ( NULL == ( strExtension = _tcsrchr( m_strName, _T('.') ) ) )
+ {
+ return DDERR_UNSUPPORTED;
+ }
+
+ // Load bitmap files
+ if ( strMetaname[0] == 0 && !lstrcmpi( strExtension, _T(".bmp") ) )
+ {
+ return LoadBitmapFile( strFilename );
+ }
+
+ // Load targa files
+ if ( !lstrcmpi( strExtension, _T(".tga") ) )
+ {
+ return LoadTargaFile( strMetaname, strFilename );
+ }
+
+ // Can add code here to check for other file formats before failing
+ return DDERR_UNSUPPORTED;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadBitmapFile()
+// Desc: Loads data from a .bmp file, and stores it in a bitmap structure.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadBitmapFile( TCHAR* strPathname )
+{
+ // Try to load the bitmap as a file
+ m_hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname, IMAGE_BITMAP, 0, 0,
+ LR_LOADFROMFILE|LR_CREATEDIBSECTION );
+ if( m_hbmBitmap )
+ return S_OK;
+
+ return DDERR_NOTFOUND;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadTargaFile()
+// Desc: Loads RGBA data from a .tga file, and stores it in allocated memory
+// for the specified texture container
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadTargaFile( TCHAR* strMetaname, TCHAR* strFilename )
+{
+ if( g_metafile.Open(strMetaname, strFilename) != 0 )
+ return E_FAIL;
+
+ struct TargaHeader
+ {
+ BYTE IDLength;
+ BYTE ColormapType;
+ BYTE ImageType;
+ BYTE ColormapSpecification[5];
+ WORD XOrigin;
+ WORD YOrigin;
+ WORD ImageWidth;
+ WORD ImageHeight;
+ BYTE PixelDepth;
+ BYTE ImageDescriptor;
+ } tga;
+
+ g_metafile.Read(&tga, sizeof(TargaHeader));
+
+ // Only true color, non-mapped images are supported
+ if( ( 0 != tga.ColormapType ) ||
+ ( tga.ImageType != 10 && tga.ImageType != 2 ) )
+ {
+ g_metafile.Close();
+ return E_FAIL;
+ }
+
+ // Skip the ID field. The first byte of the header is the length of this field
+ if( tga.IDLength )
+ {
+ g_metafile.Seek(tga.IDLength);
+ }
+
+ m_dwWidth = tga.ImageWidth;
+ m_dwHeight = tga.ImageHeight;
+ m_dwBPP = tga.PixelDepth;
+ m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight];
+
+ if( m_pRGBAData == NULL )
+ {
+ g_metafile.Close();
+ return E_FAIL;
+ }
+
+ for( DWORD y=0; y<m_dwHeight; y++ )
+ {
+ DWORD dwOffset = y*m_dwWidth;
+
+ if( 0 == ( tga.ImageDescriptor & 0x0010 ) )
+ dwOffset = (m_dwHeight-y-1)*m_dwWidth;
+
+ for( DWORD x=0; x<m_dwWidth; x )
+ {
+ if( tga.ImageType == 10 )
+ {
+ BYTE PacketInfo = g_metafile.GetByte();
+ WORD PacketType = 0x80 & PacketInfo;
+ WORD PixelCount = ( 0x007f & PacketInfo ) + 1;
+
+ if( PacketType )
+ {
+ DWORD b = g_metafile.GetWord();
+ DWORD g = g_metafile.GetWord();
+ DWORD r = g_metafile.GetWord();
+ DWORD a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetWord();
+
+ while( PixelCount-- )
+ {
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ else
+ {
+ while( PixelCount-- )
+ {
+ BYTE b = g_metafile.GetByte();
+ BYTE g = g_metafile.GetByte();
+ BYTE r = g_metafile.GetByte();
+ BYTE a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetByte();
+
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ }
+ else
+ {
+ BYTE b = g_metafile.GetByte();
+ BYTE g = g_metafile.GetByte();
+ BYTE r = g_metafile.GetByte();
+ BYTE a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetByte();
+
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ }
+
+ g_metafile.Close();
+
+ // Check for alpha content
+ for( DWORD i=0; i<(m_dwWidth*m_dwHeight); i++ )
+ {
+//? if( m_pRGBAData[i] & 0x000000ff != 0xff )
+ if( (m_pRGBAData[i] & 0x000000ff) != 0xff ) // erreur corrig�e !
+ {
+ m_bHasAlpha = TRUE;
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Restore()
+// Desc: Rebuilds the texture surface using the new device.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::Restore( LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ // Release any previously created objects
+ SAFE_RELEASE( m_pddsSurface );
+
+ // Check params
+ if( NULL == pd3dDevice )
+ return DDERR_INVALIDPARAMS;
+
+ // Get the device caps
+ D3DDEVICEDESC7 ddDesc;
+ if( FAILED( pd3dDevice->GetCaps( &ddDesc) ) )
+ return E_FAIL;
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ D3DUtil_InitSurfaceDesc( ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|
+ DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+ ddsd.dwTextureStage = m_dwStage;
+ ddsd.dwWidth = m_dwWidth;
+ ddsd.dwHeight = m_dwHeight;
+
+ // Turn on texture management for hardware devices
+ if( ddDesc.deviceGUID == IID_IDirect3DHALDevice )
+ ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
+ else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice )
+ ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ // Adjust width and height to be powers of 2, if the device requires it
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )
+ {
+ for( ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1 );
+ for( ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 );
+ }
+
+ // Limit max texture sizes, if the driver can't handle large textures
+ DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth;
+ DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight;
+ ddsd.dwWidth = min( ddsd.dwWidth, ( dwMaxWidth ? dwMaxWidth : 256 ) );
+ ddsd.dwHeight = min( ddsd.dwHeight, ( dwMaxHeight ? dwMaxHeight : 256 ) );
+
+ // Make the texture square, if the driver requires it
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
+ {
+ if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth;
+ else ddsd.dwWidth = ddsd.dwHeight;
+ }
+
+ // Setup the structure to be used for texture enumration.
+ TEXTURESEARCHINFO tsi;
+ tsi.bFoundGoodFormat = FALSE;
+ tsi.pddpf = &ddsd.ddpfPixelFormat;
+ tsi.dwDesiredBPP = m_dwBPP;
+ tsi.bUsePalette = ( m_dwBPP <= 8 );
+ tsi.bUseAlpha = m_bHasAlpha;
+ if( m_dwFlags & D3DTEXTR_16BITSPERPIXEL )
+ tsi.dwDesiredBPP = 16;
+ else if( m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
+ tsi.dwDesiredBPP = 32;
+
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ if( tsi.bUsePalette )
+ {
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE )
+ {
+ tsi.bUseAlpha = TRUE;
+ tsi.bUsePalette = TRUE;
+ }
+ else
+ {
+ tsi.bUseAlpha = TRUE;
+ tsi.bUsePalette = FALSE;
+ }
+ }
+ }
+
+ // Enumerate the texture formats, and find the closest device-supported
+ // texture pixel format
+ pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
+
+ // If we couldn't find a format, let's try a default format
+ if( FALSE == tsi.bFoundGoodFormat )
+ {
+ tsi.bUsePalette = FALSE;
+ tsi.dwDesiredBPP = 16;
+ pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
+
+ // If we still fail, we cannot create this texture
+ if( FALSE == tsi.bFoundGoodFormat )
+ return E_FAIL;
+ }
+
+ // Get the DirectDraw interface for creating surfaces
+ LPDIRECTDRAW7 pDD;
+ LPDIRECTDRAWSURFACE7 pddsRender;
+ pd3dDevice->GetRenderTarget( &pddsRender );
+ pddsRender->GetDDInterface( (VOID**)&pDD );
+ pddsRender->Release();
+
+ // Create a new surface for the texture
+ HRESULT hr = pDD->CreateSurface( &ddsd, &m_pddsSurface, NULL );
+
+ // Done with DDraw
+ pDD->Release();
+
+ if( FAILED(hr) )
+ return hr;
+
+ // For bitmap-based textures, copy the bitmap image.
+ if( m_hbmBitmap )
+ return CopyBitmapToSurface();
+
+ if( m_pRGBAData )
+ return CopyRGBADataToSurface();
+
+ // At this point, code can be added to handle other file formats (such as
+ // .dds files, .jpg files, etc.).
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CopyBitmapToSurface()
+// Desc: Copies the image of a bitmap into a surface
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::CopyBitmapToSurface()
+{
+ // Get a DDraw object to create a temporary surface
+ LPDIRECTDRAW7 pDD;
+ m_pddsSurface->GetDDInterface( (VOID**)&pDD );
+
+ // Get the bitmap structure (to extract width, height, and bpp)
+ BITMAP bm;
+ GetObject( m_hbmBitmap, sizeof(BITMAP), &bm );
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsSurface->GetSurfaceDesc( &ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
+ DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
+ ddsd.ddsCaps.dwCaps2 = 0L;
+ ddsd.dwWidth = bm.bmWidth;
+ ddsd.dwHeight = bm.bmHeight;
+
+ // Create a new surface for the texture
+ LPDIRECTDRAWSURFACE7 pddsTempSurface;
+ HRESULT hr;
+ if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
+ {
+ pDD->Release();
+ return hr;
+ }
+
+ // Get a DC for the bitmap
+ HDC hdcBitmap = CreateCompatibleDC( NULL );
+ if( NULL == hdcBitmap )
+ {
+ pddsTempSurface->Release();
+ pDD->Release();
+ return hr;
+ }
+ SelectObject( hdcBitmap, m_hbmBitmap );
+
+ // Handle palettized textures. Need to attach a palette
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )
+ {
+ LPDIRECTDRAWPALETTE pPalette;
+ DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256;
+ DWORD pe[256];
+ WORD wNumColors = GetDIBColorTable( hdcBitmap, 0, 256, (RGBQUAD*)pe );
+
+ // Create the color table
+ for( WORD i=0; i<wNumColors; i++ )
+ {
+ pe[i] = RGB( GetBValue(pe[i]), GetGValue(pe[i]), GetRValue(pe[i]) );
+
+ // Handle textures with transparent pixels
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ // Set alpha for opaque pixels
+ if( m_dwFlags & D3DTEXTR_TRANSPARENTBLACK )
+ {
+ if( pe[i] != 0x00000000 )
+ pe[i] |= 0xff000000;
+ }
+ else if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
+ {
+ if( pe[i] != 0x00ffffff )
+ pe[i] |= 0xff000000;
+ }
+ }
+ }
+ // Add DDPCAPS_ALPHA flag for textures with transparent pixels
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ dwPaletteFlags |= DDPCAPS_ALPHA;
+
+ // Create & attach a palette
+ pDD->CreatePalette( dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL );
+ pddsTempSurface->SetPalette( pPalette );
+ m_pddsSurface->SetPalette( pPalette );
+ SAFE_RELEASE( pPalette );
+ }
+
+ // Copy the bitmap image to the surface.
+ HDC hdcSurface;
+ if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) )
+ {
+ BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0,
+ SRCCOPY );
+ pddsTempSurface->ReleaseDC( hdcSurface );
+ }
+ DeleteDC( hdcBitmap );
+
+ // Copy the temp surface to the real texture surface
+ m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
+
+ // Done with the temp surface
+ pddsTempSurface->Release();
+
+ // For textures with real alpha (not palettized), set transparent bits
+ if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask )
+ {
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ // Lock the texture surface
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) ==
+ DDERR_WASSTILLDRAWING );
+
+ DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
+ DWORD dwRGBMask = ( ddsd.ddpfPixelFormat.dwRBitMask |
+ ddsd.ddpfPixelFormat.dwGBitMask |
+ ddsd.ddpfPixelFormat.dwBBitMask );
+ DWORD dwColorkey = 0x00000000; // Colorkey on black
+ if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
+ dwColorkey = dwRGBMask; // Colorkey on white
+
+ // Add an opaque alpha value to each non-colorkeyed pixel
+ for( DWORD y=0; y<ddsd.dwHeight; y++ )
+ {
+ WORD* p16 = (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
+ DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
+
+ for( DWORD x=0; x<ddsd.dwWidth; x++ )
+ {
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ if( ( *p16 &= dwRGBMask ) != dwColorkey )
+ *p16 |= dwAlphaMask;
+ p16++;
+ }
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 32 )
+ {
+ if( ( *p32 &= dwRGBMask ) != dwColorkey )
+ *p32 |= dwAlphaMask;
+ p32++;
+ }
+ }
+ }
+ m_pddsSurface->Unlock( NULL );
+ }
+ }
+
+ pDD->Release();
+
+ return S_OK;;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CopyRGBADataToSurface()
+// Desc: Invalidates the current texture objects and rebuilds new ones
+// using the new device.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::CopyRGBADataToSurface()
+{
+ // Get a DDraw object to create a temporary surface
+ LPDIRECTDRAW7 pDD;
+ m_pddsSurface->GetDDInterface( (VOID**)&pDD );
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsSurface->GetSurfaceDesc( &ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
+ DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
+ ddsd.ddsCaps.dwCaps2 = 0L;
+ ddsd.dwWidth = m_dwWidth;
+ ddsd.dwHeight = m_dwHeight;
+
+ // Create a new surface for the texture
+ LPDIRECTDRAWSURFACE7 pddsTempSurface;
+ HRESULT hr;
+ if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
+ {
+ pDD->Release();
+ return NULL;
+ }
+
+ while( pddsTempSurface->Lock( NULL, &ddsd, 0, 0 ) == DDERR_WASSTILLDRAWING );
+ DWORD lPitch = ddsd.lPitch;
+ BYTE* pBytes = (BYTE*)ddsd.lpSurface;
+
+ DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask;
+ DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask;
+ DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask;
+ DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
+
+ DWORD dwRShiftL = 8, dwRShiftR = 0;
+ DWORD dwGShiftL = 8, dwGShiftR = 0;
+ DWORD dwBShiftL = 8, dwBShiftR = 0;
+ DWORD dwAShiftL = 8, dwAShiftR = 0;
+
+ DWORD dwMask;
+ for( dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwRShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwRShiftL--;
+
+ for( dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwGShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwGShiftL--;
+
+ for( dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwBShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwBShiftL--;
+
+ for( dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwAShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwAShiftL--;
+
+ for( DWORD y=0; y<ddsd.dwHeight; y++ )
+ {
+ DWORD* pDstData32 = (DWORD*)pBytes;
+ WORD* pDstData16 = (WORD*)pBytes;
+
+ for( DWORD x=0; x<ddsd.dwWidth; x++ )
+ {
+ DWORD dwPixel = m_pRGBAData[y*ddsd.dwWidth+x];
+
+ BYTE r = (BYTE)((dwPixel>>24)&0x000000ff);
+ BYTE g = (BYTE)((dwPixel>>16)&0x000000ff);
+ BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff);
+ BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff);
+
+ DWORD dr = ((r>>(dwRShiftL))<<dwRShiftR)&dwRMask;
+ DWORD dg = ((g>>(dwGShiftL))<<dwGShiftR)&dwGMask;
+ DWORD db = ((b>>(dwBShiftL))<<dwBShiftR)&dwBMask;
+ DWORD da = ((a>>(dwAShiftL))<<dwAShiftR)&dwAMask;
+
+ if( 32 == ddsd.ddpfPixelFormat.dwRGBBitCount )
+ pDstData32[x] = (DWORD)(dr+dg+db+da);
+ else
+ pDstData16[x] = (WORD)(dr+dg+db+da);
+ }
+
+ pBytes += ddsd.lPitch;
+ }
+
+ pddsTempSurface->Unlock(0);
+
+ // Copy the temp surface to the real texture surface
+ m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
+
+ // Done with the temp objects
+ pddsTempSurface->Release();
+ pDD->Release();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_SetTexturePath()
+// Desc: Enumeration callback routine to find a best-matching texture format.
+//-----------------------------------------------------------------------------
+VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath )
+{
+ if( NULL == strTexturePath )
+ strTexturePath = _T("");
+ lstrcpy( g_strTexturePath, strTexturePath );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_CreateTextureFromFile()
+// Desc: Is passed a filename and creates a local Bitmap from that file.
+// The texture can not be used until it is restored, however.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage,
+ DWORD dwFlags )
+{
+ // Check parameters
+ if( NULL == strName )
+ return E_INVALIDARG;
+
+ // Check first to see if the texture is already loaded
+ if( NULL != FindTexture( strName ) )
+ return S_OK;
+
+ // Allocate and add the texture to the linked list of textures;
+ TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
+ dwFlags );
+ if( NULL == ptcTexture )
+ return E_OUTOFMEMORY;
+
+ // Create a bitmap and load the texture file into it,
+ if( FAILED( ptcTexture->LoadImageData() ) )
+ {
+ delete ptcTexture;
+ return E_FAIL;
+ }
+
+ // Save the image's dimensions
+ if( ptcTexture->m_hbmBitmap )
+ {
+ BITMAP bm;
+ GetObject( ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm );
+ ptcTexture->m_dwWidth = (DWORD)bm.bmWidth;
+ ptcTexture->m_dwHeight = (DWORD)bm.bmHeight;
+ ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_CreateEmptyTexture()
+// Desc: Creates an empty texture.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwStage,
+ DWORD dwFlags )
+{
+ // Check parameters
+ if( NULL == strName )
+ return E_INVALIDARG;
+
+ // Check first to see if the texture is already loaded
+ if( NULL != FindTexture( strName ) )
+ return E_FAIL;
+
+ // Allocate and add the texture to the linked list of textures;
+ TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
+ dwFlags );
+ if( NULL == ptcTexture )
+ return E_OUTOFMEMORY;
+
+ // Save dimensions
+ ptcTexture->m_dwWidth = dwWidth;
+ ptcTexture->m_dwHeight = dwHeight;
+ ptcTexture->m_dwBPP = 16;
+ if( ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
+ ptcTexture->m_dwBPP = 32;
+
+ // Save alpha usage flag
+ if( dwFlags & D3DTEXTR_CREATEWITHALPHA )
+ ptcTexture->m_bHasAlpha = TRUE;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_Restore()
+// Desc: Invalidates the current texture objects and rebuilds new ones
+// using the new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+ if( NULL == ptcTexture )
+ return DDERR_NOTFOUND;
+
+ // Restore the texture (this recreates the new surface for this device).
+ return ptcTexture->Restore( pd3dDevice );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_RestoreAllTextures()
+// Desc: This function is called when a mode is changed. It updates all
+// texture objects to be valid with the new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ D3DTextr_Restore( ptcTexture->m_strName, pd3dDevice );
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_Invalidate()
+// Desc: Used to bump a texture out of (video) memory, this function
+// actually destroys the d3dtexture and ddsurface of the texture
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Invalidate( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+ if( NULL == ptcTexture )
+ return DDERR_NOTFOUND;
+
+ SAFE_RELEASE( ptcTexture->m_pddsSurface );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_InvalidateAllTextures()
+// Desc: This function is called when a mode is changed. It invalidates
+// all texture objects so their device can be safely released.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_InvalidateAllTextures()
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ SAFE_RELEASE( ptcTexture->m_pddsSurface );
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_DestroyTexture()
+// Desc: Frees the resources for the specified texture container
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_DestroyTexture( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+
+ SAFE_DELETE( ptcTexture );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_GetSurface()
+// Desc: Returns a pointer to a d3dSurface from the name of the texture
+//-----------------------------------------------------------------------------
+LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+
+ return ptcTexture ? ptcTexture->m_pddsSurface : NULL;
+}
+
+
+
+
+
diff --git a/src/graphics/d3d/d3dtextr.h b/src/graphics/d3d/d3dtextr.h
new file mode 100644
index 0000000..54a79bb
--- /dev/null
+++ b/src/graphics/d3d/d3dtextr.h
@@ -0,0 +1,80 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DTextr.h
+//
+// Desc: Functions to manage textures, including creating (loading from a
+// file), restoring lost surfaces, invalidating, and destroying.
+//
+// Note: the implementation of these fucntions maintain an internal list
+// of loaded textures. After creation, individual textures are referenced
+// via their ASCII names.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DTEXTR_H
+#define D3DTEXTR_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Access functions for loaded textures. Note: these functions search
+// an internal list of the textures, and use the texture associated with the
+// ASCII name.
+//-----------------------------------------------------------------------------
+LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Texture invalidation and restoration functions
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Invalidate( TCHAR* strName );
+HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice );
+HRESULT D3DTextr_InvalidateAllTextures();
+HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Texture creation and deletion functions
+//-----------------------------------------------------------------------------
+#define D3DTEXTR_TRANSPARENTWHITE 0x00000001
+#define D3DTEXTR_TRANSPARENTBLACK 0x00000002
+#define D3DTEXTR_32BITSPERPIXEL 0x00000004
+#define D3DTEXTR_16BITSPERPIXEL 0x00000008
+#define D3DTEXTR_CREATEWITHALPHA 0x00000010
+
+
+HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage=0L,
+ DWORD dwFlags=0L );
+HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwStage,
+ DWORD dwFlags );
+HRESULT D3DTextr_DestroyTexture( TCHAR* strName );
+VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath );
+
+void D3DTextr_SetDebugMode(BOOL bDebug);
+
+
+
+#endif // D3DTEXTR_H
diff --git a/src/graphics/d3d/d3dutil.cpp b/src/graphics/d3d/d3dutil.cpp
new file mode 100644
index 0000000..b4a0eb7
--- /dev/null
+++ b/src/graphics/d3d/d3dutil.cpp
@@ -0,0 +1,327 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DUtil.cpp
+//
+// Desc: Shortcut macros and functions for using DX objects
+//
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define D3D_OVERLOADS
+#define STRICT
+#include <math.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "d3dutil.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_GetDXSDKMediaPath()
+// Desc: Returns the DirectX SDK media path, as stored in the system registry
+// during the SDK install.
+//-----------------------------------------------------------------------------
+const TCHAR* D3DUtil_GetDXSDKMediaPath()
+{
+ static TCHAR strNull[2] = _T("");
+ static TCHAR strPath[512];
+ HKEY key;
+ DWORD type, size = 512;
+
+ // Open the appropriate registry key
+ LONG result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ _T("Software\\Microsoft\\DirectX"),
+ 0, KEY_READ, &key );
+ if( ERROR_SUCCESS != result )
+ return strNull;
+
+ result = RegQueryValueEx( key, _T("DXSDK Samples Path"), NULL,
+ &type, (BYTE*)strPath, &size );
+ RegCloseKey( key );
+
+ if( ERROR_SUCCESS != result )
+ return strNull;
+
+ lstrcat( strPath, _T("\\D3DIM\\Media\\") );
+
+ return strPath;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitSurfaceDesc()
+// Desc: Helper function called to build a DDSURFACEDESC2 structure,
+// typically before calling CreateSurface() or GetSurfaceDesc()
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags,
+ DWORD dwCaps )
+{
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = dwFlags;
+ ddsd.ddsCaps.dwCaps = dwCaps;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitMaterial()
+// Desc: Helper function called to build a D3DMATERIAL7 structure
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r, FLOAT g, FLOAT b,
+ FLOAT a )
+{
+ ZeroMemory( &mtrl, sizeof(D3DMATERIAL7) );
+ mtrl.dcvDiffuse.r = mtrl.dcvAmbient.r = r;
+ mtrl.dcvDiffuse.g = mtrl.dcvAmbient.g = g;
+ mtrl.dcvDiffuse.b = mtrl.dcvAmbient.b = b;
+ mtrl.dcvDiffuse.a = mtrl.dcvAmbient.a = a;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitLight()
+// Desc: Initializes a D3DLIGHT7 structure
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType,
+ FLOAT x, FLOAT y, FLOAT z )
+{
+ ZeroMemory( &light, sizeof(D3DLIGHT7) );
+ light.dltType = ltType;
+ light.dcvDiffuse.r = 1.0f;
+ light.dcvDiffuse.g = 1.0f;
+ light.dcvDiffuse.b = 1.0f;
+ light.dcvSpecular = light.dcvDiffuse;
+ light.dvPosition.x = light.dvDirection.x = x;
+ light.dvPosition.y = light.dvDirection.y = y;
+ light.dvPosition.z = light.dvDirection.z = z;
+ light.dvAttenuation0 = 1.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetViewMatrix()
+// Desc: Given an eye point, a lookat point, and an up vector, this
+// function builds a 4x4 view matrix.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom,
+ D3DVECTOR& vAt, D3DVECTOR& vWorldUp )
+{
+ // Get the z basis vector, which points straight ahead. This is the
+ // difference from the eyepoint to the lookat point.
+ D3DVECTOR vView = vAt - vFrom;
+
+ FLOAT fLength = Magnitude( vView );
+ if( fLength < 1e-6f )
+ return E_INVALIDARG;
+
+ // Normalize the z basis vector
+ vView /= fLength;
+
+ // Get the dot product, and calculate the projection of the z basis
+ // vector onto the up vector. The projection is the y basis vector.
+ FLOAT fDotProduct = DotProduct( vWorldUp, vView );
+
+ D3DVECTOR vUp = vWorldUp - fDotProduct * vView;
+
+ // If this vector has near-zero length because the input specified a
+ // bogus up vector, let's try a default up vector
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ {
+ vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView;
+
+ // If we still have near-zero length, resort to a different axis.
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ {
+ vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView;
+
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ return E_INVALIDARG;
+ }
+ }
+
+ // Normalize the y basis vector
+ vUp /= fLength;
+
+ // The x basis vector is found simply with the cross product of the y
+ // and z basis vectors
+ D3DVECTOR vRight = CrossProduct( vUp, vView );
+
+ // Start building the matrix. The first three rows contains the basis
+ // vectors used to rotate the view to point at the lookat point
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x;
+ mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y;
+ mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z;
+
+ // Do the translation values (rotations are still about the eyepoint)
+ mat._41 = - DotProduct( vFrom, vRight );
+ mat._42 = - DotProduct( vFrom, vUp );
+ mat._43 = - DotProduct( vFrom, vView );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetProjectionMatrix()
+// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built
+// from the field-of-view (fov, in y), aspect ratio, near plane (D),
+// and far plane (F). Note that the projection matrix is normalized for
+// element [3][4] to be 1.0. This is performed so that W-based range fog
+// will work correctly.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect,
+ FLOAT fNearPlane, FLOAT fFarPlane )
+{
+ if( fabs(fFarPlane-fNearPlane) < 0.01f )
+ return E_INVALIDARG;
+ if( fabs(sin(fFOV/2)) < 0.01f )
+ return E_INVALIDARG;
+
+ FLOAT w = fAspect * ( cosf(fFOV/2)/sinf(fFOV/2) );
+ FLOAT h = 1.0f * ( cosf(fFOV/2)/sinf(fFOV/2) );
+ FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane );
+
+ ZeroMemory( &mat, sizeof(D3DMATRIX) );
+ mat._11 = w;
+ mat._22 = h;
+ mat._33 = Q;
+ mat._34 = 1.0f;
+ mat._43 = -Q*fNearPlane;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateXMatrix()
+// Desc: Create Rotation matrix about X axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._22 = cosf( fRads );
+ mat._23 = sinf( fRads );
+ mat._32 = -sinf( fRads );
+ mat._33 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateYMatrix()
+// Desc: Create Rotation matrix about Y axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = cosf( fRads );
+ mat._13 = -sinf( fRads );
+ mat._31 = sinf( fRads );
+ mat._33 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateZMatrix()
+// Desc: Create Rotation matrix about Z axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = cosf( fRads );
+ mat._12 = sinf( fRads );
+ mat._21 = -sinf( fRads );
+ mat._22 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotationMatrix
+// Desc: Create a Rotation matrix about vector direction
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, FLOAT fRads )
+{
+ FLOAT fCos = cosf( fRads );
+ FLOAT fSin = sinf( fRads );
+ D3DVECTOR v = Normalize( vDir );
+
+ mat._11 = ( v.x * v.x ) * ( 1.0f - fCos ) + fCos;
+ mat._12 = ( v.x * v.y ) * ( 1.0f - fCos ) - (v.z * fSin);
+ mat._13 = ( v.x * v.z ) * ( 1.0f - fCos ) + (v.y * fSin);
+
+ mat._21 = ( v.y * v.x ) * ( 1.0f - fCos ) + (v.z * fSin);
+ mat._22 = ( v.y * v.y ) * ( 1.0f - fCos ) + fCos ;
+ mat._23 = ( v.y * v.z ) * ( 1.0f - fCos ) - (v.x * fSin);
+
+ mat._31 = ( v.z * v.x ) * ( 1.0f - fCos ) - (v.y * fSin);
+ mat._32 = ( v.z * v.y ) * ( 1.0f - fCos ) + (v.x * fSin);
+ mat._33 = ( v.z * v.z ) * ( 1.0f - fCos ) + fCos;
+
+ mat._14 = mat._24 = mat._34 = 0.0f;
+ mat._41 = mat._42 = mat._43 = 0.0f;
+ mat._44 = 1.0f;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: _DbgOut()
+// Desc: Outputs a message to the debug stream
+//-----------------------------------------------------------------------------
+HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg )
+{
+ TCHAR buffer[256];
+ wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine );
+ OutputDebugString( buffer );
+ OutputDebugString( strMsg );
+
+ if( hr )
+ {
+ wsprintf( buffer, _T("(hr=%08lx)\n"), hr );
+ OutputDebugString( buffer );
+ }
+
+ OutputDebugString( _T("\n") );
+
+ return hr;
+}
+
+
+
diff --git a/src/graphics/d3d/d3dutil.h b/src/graphics/d3d/d3dutil.h
new file mode 100644
index 0000000..494722d
--- /dev/null
+++ b/src/graphics/d3d/d3dutil.h
@@ -0,0 +1,114 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+//-----------------------------------------------------------------------------
+// File: D3DUtil.h
+//
+// Desc: Helper functions and typing shortcuts for Direct3D programming.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DUTIL_H
+#define D3DUTIL_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Miscellaneous helper functions
+//-----------------------------------------------------------------------------
+const TCHAR* D3DUtil_GetDXSDKMediaPath();
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Short cut functions for creating and using DX structures
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC7& ddDevDesc );
+VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags=0,
+ DWORD dwCaps=0 );
+VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r=0.0f, FLOAT g=0.0f,
+ FLOAT b=0.0f, FLOAT a=1.0f );
+VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType,
+ FLOAT x=0.0f, FLOAT y=0.0f, FLOAT z=0.0f );
+
+
+
+
+//-----------------------------------------------------------------------------
+// D3D Matrix functions. For performance reasons, some functions are inline.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom,
+ D3DVECTOR& vAt, D3DVECTOR& vUp );
+HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV = 1.570795f,
+ FLOAT fAspect = 1.0f,
+ FLOAT fNearPlane = 1.0f,
+ FLOAT fFarPlane = 1000.0f );
+
+inline VOID D3DUtil_SetIdentityMatrix( D3DMATRIX& m )
+{
+ m._12 = m._13 = m._14 = m._21 = m._23 = m._24 = 0.0f;
+ m._31 = m._32 = m._34 = m._41 = m._42 = m._43 = 0.0f;
+ m._11 = m._22 = m._33 = m._44 = 1.0f;
+}
+
+inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty,
+ FLOAT tz )
+{ D3DUtil_SetIdentityMatrix( m ); m._41 = tx; m._42 = ty; m._43 = tz; }
+
+inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, D3DVECTOR& v )
+{ D3DUtil_SetTranslateMatrix( m, v.x, v.y, v.z ); }
+
+inline VOID D3DUtil_SetScaleMatrix( D3DMATRIX& m, FLOAT sx, FLOAT sy,
+ FLOAT sz )
+{ D3DUtil_SetIdentityMatrix( m ); m._11 = sx; m._22 = sy; m._33 = sz; }
+
+inline VOID SetScaleMatrix( D3DMATRIX& m, D3DVECTOR& v )
+{ D3DUtil_SetScaleMatrix( m, v.x, v.y, v.z ); }
+
+VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir,
+ FLOAT fRads );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Debug printing support
+//-----------------------------------------------------------------------------
+
+HRESULT _DbgOut( TCHAR*, DWORD, HRESULT, TCHAR* );
+
+#if defined(DEBUG) | defined(_DEBUG)
+ #define DEBUG_MSG(str) _DbgOut( __FILE__, (DWORD)__LINE__, 0, str )
+ #define DEBUG_ERR(hr,str) _DbgOut( __FILE__, (DWORD)__LINE__, hr, str )
+#else
+ #define DEBUG_MSG(str) (0L)
+ #define DEBUG_ERR(hr,str) (hr)
+#endif
+
+
+
+
+#endif // D3DUTIL_H