colobot/src/d3dengine.cpp

5728 lines
138 KiB
C++
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

// * 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);
}