From ebed57aa22b772211387a5561f995eee8f5faed1 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Tue, 26 Jun 2012 22:23:05 +0200 Subject: Whitespace and language change - changed tabs to spaces and DOS line endings to Unix (except in CBot and metafile) - changed language to English - fixed #include in d3dengine.h --- src/old/blitz.cpp | 950 ++-- src/old/blitz.h | 166 +- src/old/camera.cpp | 4218 +++++++++--------- src/old/camera.h | 538 +-- src/old/cloud.cpp | 676 +-- src/old/cloud.h | 176 +- src/old/d3dapp.cpp | 4902 ++++++++++---------- src/old/d3dapp.h | 332 +- src/old/d3dengine.cpp | 11650 ++++++++++++++++++++++++------------------------ src/old/d3dengine.h | 1354 +++--- src/old/d3denum.cpp | 1240 +++--- src/old/d3denum.h | 266 +- src/old/d3dframe.cpp | 1244 +++--- src/old/d3dframe.h | 282 +- src/old/d3dmath.cpp | 686 +-- src/old/d3dmath.h | 214 +- src/old/d3dres.h | 110 +- src/old/d3dtextr.cpp | 2162 ++++----- src/old/d3dtextr.h | 158 +- src/old/d3dutil.cpp | 650 +-- src/old/d3dutil.h | 226 +- src/old/joystick.cpp | 488 +- src/old/joystick.h | 54 +- src/old/light.cpp | 1008 ++--- src/old/light.h | 218 +- src/old/math3d.cpp | 2394 +++++----- src/old/math3d.h | 96 +- src/old/model.cpp | 6456 +++++++++++++-------------- src/old/model.h | 272 +- src/old/modfile.cpp | 1058 ++--- src/old/modfile.h | 114 +- src/old/particule.cpp | 8802 ++++++++++++++++++------------------ src/old/particule.h | 674 +-- src/old/planet.cpp | 494 +- src/old/planet.h | 152 +- src/old/pyro.cpp | 4972 ++++++++++----------- src/old/pyro.h | 340 +- src/old/resource.h | 110 +- src/old/sound.cpp | 3318 +++++++------- src/old/sound.h | 484 +- src/old/terrain.cpp | 4540 +++++++++---------- src/old/terrain.h | 418 +- src/old/text.cpp | 3758 ++++++++-------- src/old/text.h | 222 +- src/old/water.cpp | 1688 +++---- src/old/water.h | 260 +- 46 files changed, 37296 insertions(+), 37294 deletions(-) (limited to 'src/old') diff --git a/src/old/blitz.cpp b/src/old/blitz.cpp index 15488d2..b3708bb 100644 --- a/src/old/blitz.cpp +++ b/src/old/blitz.cpp @@ -1,475 +1,475 @@ -// * 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/. - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/terrain.h" -#include "old/math3d.h" -#include "object/object.h" -#include "old/camera.h" -#include "object/auto/auto.h" -#include "object/auto/autopara.h" -#include "old/sound.h" -#include "old/blitz.h" - - - - -// Constructor of the terrain. - -CBlitz::CBlitz(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_BLITZ, this); - - m_engine = engine; - m_terrain = 0; - m_camera = 0; - m_sound = 0; - Flush(); -} - -// Destructor of the terrain. - -CBlitz::~CBlitz() -{ -} - - -// Removes lightning. - -void CBlitz::Flush() -{ - int i; - - m_bBlitzExist = false; - m_time = 0.0f; - m_phase = BPH_WAIT; - m_speed = 0.0f; - m_progress = 0.0f; - - for ( i=0 ; iRetPause() ) return true; - if ( m_engine->RetMovieLock() ) return true; - - m_time += event.rTime; - m_progress += event.rTime*m_speed; - - if ( m_phase == BPH_WAIT ) - { - if ( m_progress >= 1.0f ) - { -#if 1 - m_pos.x = (Math::Rand()-0.5f)*(3200.0f-200.0f); - m_pos.z = (Math::Rand()-0.5f)*(3200.0f-200.0f); -#else - m_pos.x = (Math::Rand()-0.5f)*(3200.0f-2800.0f); - m_pos.z = (Math::Rand()-0.5f)*(3200.0f-2800.0f); -#endif - m_pos.y = 0.0f; - - pObj = SearchObject(m_pos); - if ( pObj == 0 ) - { - m_terrain->MoveOnFloor(m_pos, true); - } - else - { - m_pos = pObj->RetPosition(0); - m_terrain->MoveOnFloor(m_pos, true); - - type = pObj->RetType(); - if ( type == OBJECT_BASE ) - { - m_pos.y += 120.0f; // top of the rocket - } - else if ( type == OBJECT_PARA ) - { - automat = (CAutoPara*)pObj->RetAuto(); - if ( automat != 0 ) - { - automat->StartBlitz(); - } - m_pos.y += 67.0f; // top of lightning rod - } - else - { - pObj->ExploObject(EXPLO_BOUM, 1.0f); - } - } - - eye = m_engine->RetEyePt(); - dist = Math::Distance(m_pos, eye); - deep = m_engine->RetDeepView(); - - if ( dist < deep ) - { - pos = eye+((m_pos-eye)*0.2f); // like so close! - m_sound->Play(SOUND_BLITZ, pos); - - m_camera->StartOver(OE_BLITZ, m_pos, 1.0f); - - m_phase = BPH_BLITZ; - m_progress = 0.0f; - m_speed = 1.0f/1.0f; - } - } - } - - if ( m_phase == BPH_BLITZ ) - { - if ( m_progress < 1.0f ) - { - max = 5.0f; - for ( i=0 ; i max ) m_shift[i].x = max; - - m_shift[i].y += (Math::Rand()-0.5f)*max*2.0f; - if ( m_shift[i].y < -max ) m_shift[i].y = -max; - if ( m_shift[i].y > max ) m_shift[i].y = max; - - m_width[i] += (Math::Rand()-0.5f)*2.0f; - if ( m_width[i] < 1.0f ) m_width[i] = 1.0f; - if ( m_width[i] > 6.0f ) m_width[i] = 6.0f; - } - m_shift[0].x = 0.0f; - m_shift[0].y = 0.0f; - m_width[0] = 0.0f; - } - else - { - m_phase = BPH_WAIT; - m_progress = 0.0f; - m_speed = 1.0f/(1.0f+Math::Rand()*m_delay); - } - } - - return true; -} - - -// Draw lightning. - -void CBlitz::Draw() -{ - LPDIRECT3DDEVICE7 device; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector corner[4], eye, n, p, p1, p2; - Math::Matrix matrix; - Math::Point texInf, texSup, rot; - float a; - int i; - - if ( !m_bBlitzExist ) return; - if ( m_phase != BPH_BLITZ ) return; - - device = m_engine->RetD3DDevice(); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - m_engine->SetTexture("effect00.tga"); - m_engine->SetState(D3DSTATETTb); - texInf.x = 64.5f/256.0f; - texInf.y = 33.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 34.0f/256.0f; // blank - - p1 = m_pos; - eye = m_engine->RetEyePt(); - a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); - n = Normalize(p1-eye); - - for ( i=0 ; iDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - - p1 = p2; - } - - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); -} - - -// Triggers lightning. - -bool CBlitz::Create(float sleep, float delay, float magnetic) -{ - m_bBlitzExist = true; - if ( sleep < 1.0f ) sleep = 1.0f; - m_sleep = sleep; - m_delay = delay; - m_magnetic = magnetic; - - m_phase = BPH_WAIT; - m_progress = 0.0f; - m_speed = 1.0f/m_sleep; - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - - if ( m_camera == 0 ) - { - m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA); - } - - if ( m_sound == 0 ) - { - m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); - } - - return false; -} - - -// Gives the status of lightning. - -bool CBlitz::GetStatus(float &sleep, float &delay, float &magnetic, float &progress) -{ - if ( !m_bBlitzExist ) return false; - - sleep = m_sleep; - delay = m_delay; - magnetic = m_magnetic; - progress = m_progress; - - return true; -} - -// Specifies the status of lightning. - -bool CBlitz::SetStatus(float sleep, float delay, float magnetic, float progress) -{ - m_bBlitzExist = true; - - m_sleep = sleep; - m_delay = delay; - m_magnetic = magnetic; - m_progress = progress; - m_phase = BPH_WAIT; - m_speed = 1.0f/m_sleep; - - return true; -} - - -// Seeking the object closest to the lightning. - -CObject* CBlitz::SearchObject(Math::Vector pos) -{ - CObject *pObj, *pBest, *pObjPara[100]; - Math::Vector oPos, pPos[100]; - ObjectType type; - float min, dist, detect; - int i, nbPara; - - // Seeking the object closest to the point of impact of lightning. - pBest = 0; - min = 100000.0f; - nbPara = 0; - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( !pObj->RetActif() ) continue; // inactive object? - if ( pObj->RetTruck() != 0 ) continue; // object transported? - - type = pObj->RetType(); - if ( type == OBJECT_BASE || - type == OBJECT_PARA ) // building a lightning effect? - { - pObjPara[nbPara] = pObj; - pPos[nbPara] = pObj->RetPosition(0); - nbPara ++; - } - - detect = 0.0f; - if ( type == OBJECT_BASE || - type == OBJECT_DERRICK || - type == OBJECT_FACTORY || - type == OBJECT_REPAIR || - type == OBJECT_DESTROYER|| - type == OBJECT_STATION || - type == OBJECT_CONVERT || - type == OBJECT_TOWER || - type == OBJECT_RESEARCH || - type == OBJECT_RADAR || - type == OBJECT_INFO || - type == OBJECT_ENERGY || - type == OBJECT_LABO || - type == OBJECT_NUCLEAR || - type == OBJECT_PARA || - type == OBJECT_SAFE || - type == OBJECT_HUSTON ) - { - detect = m_magnetic; - } - if ( type == OBJECT_METAL || - type == OBJECT_POWER || - type == OBJECT_ATOMIC ) - { - detect = m_magnetic*0.3f; - } - if ( type == OBJECT_MOBILEfa || - type == OBJECT_MOBILEta || - type == OBJECT_MOBILEwa || - type == OBJECT_MOBILEia || - type == OBJECT_MOBILEfc || - type == OBJECT_MOBILEtc || - type == OBJECT_MOBILEwc || - type == OBJECT_MOBILEic || - type == OBJECT_MOBILEfi || - type == OBJECT_MOBILEti || - type == OBJECT_MOBILEwi || - type == OBJECT_MOBILEii || - type == OBJECT_MOBILEfs || - type == OBJECT_MOBILEts || - type == OBJECT_MOBILEws || - type == OBJECT_MOBILEis || - type == OBJECT_MOBILErt || - type == OBJECT_MOBILErc || - type == OBJECT_MOBILErr || - type == OBJECT_MOBILErs || - type == OBJECT_MOBILEsa || - type == OBJECT_MOBILEft || - type == OBJECT_MOBILEtt || - type == OBJECT_MOBILEwt || - type == OBJECT_MOBILEit || - type == OBJECT_MOBILEdr ) - { - detect = m_magnetic*0.5f; - } - if ( detect == 0.0f ) continue; - - oPos = pObj->RetPosition(0); - dist = Math::DistanceProjected(oPos, pos); - if ( dist > detect ) continue; - if ( dist < min ) - { - min = dist; - pBest = pObj; - } - } - if ( pBest == 0 ) return 0; // nothing found - - // Under the protection of a lightning conductor? - oPos = pBest->RetPosition(0); - for ( i=nbPara-1 ; i>=0 ; i-- ) - { - dist = Math::DistanceProjected(oPos, pPos[i]); - if ( dist <= BLITZPARA ) - { - return pObjPara[i]; - } - } - return pBest; -} - +// * 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/. + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/terrain.h" +#include "old/math3d.h" +#include "object/object.h" +#include "old/camera.h" +#include "object/auto/auto.h" +#include "object/auto/autopara.h" +#include "old/sound.h" +#include "old/blitz.h" + + + + +// Constructor of the terrain. + +CBlitz::CBlitz(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_BLITZ, this); + + m_engine = engine; + m_terrain = 0; + m_camera = 0; + m_sound = 0; + Flush(); +} + +// Destructor of the terrain. + +CBlitz::~CBlitz() +{ +} + + +// Removes lightning. + +void CBlitz::Flush() +{ + int i; + + m_bBlitzExist = false; + m_time = 0.0f; + m_phase = BPH_WAIT; + m_speed = 0.0f; + m_progress = 0.0f; + + for ( i=0 ; iRetPause() ) return true; + if ( m_engine->RetMovieLock() ) return true; + + m_time += event.rTime; + m_progress += event.rTime*m_speed; + + if ( m_phase == BPH_WAIT ) + { + if ( m_progress >= 1.0f ) + { +#if 1 + m_pos.x = (Math::Rand()-0.5f)*(3200.0f-200.0f); + m_pos.z = (Math::Rand()-0.5f)*(3200.0f-200.0f); +#else + m_pos.x = (Math::Rand()-0.5f)*(3200.0f-2800.0f); + m_pos.z = (Math::Rand()-0.5f)*(3200.0f-2800.0f); +#endif + m_pos.y = 0.0f; + + pObj = SearchObject(m_pos); + if ( pObj == 0 ) + { + m_terrain->MoveOnFloor(m_pos, true); + } + else + { + m_pos = pObj->RetPosition(0); + m_terrain->MoveOnFloor(m_pos, true); + + type = pObj->RetType(); + if ( type == OBJECT_BASE ) + { + m_pos.y += 120.0f; // top of the rocket + } + else if ( type == OBJECT_PARA ) + { + automat = (CAutoPara*)pObj->RetAuto(); + if ( automat != 0 ) + { + automat->StartBlitz(); + } + m_pos.y += 67.0f; // top of lightning rod + } + else + { + pObj->ExploObject(EXPLO_BOUM, 1.0f); + } + } + + eye = m_engine->RetEyePt(); + dist = Math::Distance(m_pos, eye); + deep = m_engine->RetDeepView(); + + if ( dist < deep ) + { + pos = eye+((m_pos-eye)*0.2f); // like so close! + m_sound->Play(SOUND_BLITZ, pos); + + m_camera->StartOver(OE_BLITZ, m_pos, 1.0f); + + m_phase = BPH_BLITZ; + m_progress = 0.0f; + m_speed = 1.0f/1.0f; + } + } + } + + if ( m_phase == BPH_BLITZ ) + { + if ( m_progress < 1.0f ) + { + max = 5.0f; + for ( i=0 ; i max ) m_shift[i].x = max; + + m_shift[i].y += (Math::Rand()-0.5f)*max*2.0f; + if ( m_shift[i].y < -max ) m_shift[i].y = -max; + if ( m_shift[i].y > max ) m_shift[i].y = max; + + m_width[i] += (Math::Rand()-0.5f)*2.0f; + if ( m_width[i] < 1.0f ) m_width[i] = 1.0f; + if ( m_width[i] > 6.0f ) m_width[i] = 6.0f; + } + m_shift[0].x = 0.0f; + m_shift[0].y = 0.0f; + m_width[0] = 0.0f; + } + else + { + m_phase = BPH_WAIT; + m_progress = 0.0f; + m_speed = 1.0f/(1.0f+Math::Rand()*m_delay); + } + } + + return true; +} + + +// Draw lightning. + +void CBlitz::Draw() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector corner[4], eye, n, p, p1, p2; + Math::Matrix matrix; + Math::Point texInf, texSup, rot; + float a; + int i; + + if ( !m_bBlitzExist ) return; + if ( m_phase != BPH_BLITZ ) return; + + device = m_engine->RetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + m_engine->SetTexture("effect00.tga"); + m_engine->SetState(D3DSTATETTb); + texInf.x = 64.5f/256.0f; + texInf.y = 33.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 34.0f/256.0f; // blank + + p1 = m_pos; + eye = m_engine->RetEyePt(); + a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); + n = Normalize(p1-eye); + + for ( i=0 ; iDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + p1 = p2; + } + + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); +} + + +// Triggers lightning. + +bool CBlitz::Create(float sleep, float delay, float magnetic) +{ + m_bBlitzExist = true; + if ( sleep < 1.0f ) sleep = 1.0f; + m_sleep = sleep; + m_delay = delay; + m_magnetic = magnetic; + + m_phase = BPH_WAIT; + m_progress = 0.0f; + m_speed = 1.0f/m_sleep; + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + + if ( m_camera == 0 ) + { + m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA); + } + + if ( m_sound == 0 ) + { + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + } + + return false; +} + + +// Gives the status of lightning. + +bool CBlitz::GetStatus(float &sleep, float &delay, float &magnetic, float &progress) +{ + if ( !m_bBlitzExist ) return false; + + sleep = m_sleep; + delay = m_delay; + magnetic = m_magnetic; + progress = m_progress; + + return true; +} + +// Specifies the status of lightning. + +bool CBlitz::SetStatus(float sleep, float delay, float magnetic, float progress) +{ + m_bBlitzExist = true; + + m_sleep = sleep; + m_delay = delay; + m_magnetic = magnetic; + m_progress = progress; + m_phase = BPH_WAIT; + m_speed = 1.0f/m_sleep; + + return true; +} + + +// Seeking the object closest to the lightning. + +CObject* CBlitz::SearchObject(Math::Vector pos) +{ + CObject *pObj, *pBest, *pObjPara[100]; + Math::Vector oPos, pPos[100]; + ObjectType type; + float min, dist, detect; + int i, nbPara; + + // Seeking the object closest to the point of impact of lightning. + pBest = 0; + min = 100000.0f; + nbPara = 0; + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( !pObj->RetActif() ) continue; // inactive object? + if ( pObj->RetTruck() != 0 ) continue; // object transported? + + type = pObj->RetType(); + if ( type == OBJECT_BASE || + type == OBJECT_PARA ) // building a lightning effect? + { + pObjPara[nbPara] = pObj; + pPos[nbPara] = pObj->RetPosition(0); + nbPara ++; + } + + detect = 0.0f; + if ( type == OBJECT_BASE || + type == OBJECT_DERRICK || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_STATION || + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA || + type == OBJECT_SAFE || + type == OBJECT_HUSTON ) + { + detect = m_magnetic; + } + if ( type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC ) + { + detect = m_magnetic*0.3f; + } + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) + { + detect = m_magnetic*0.5f; + } + if ( detect == 0.0f ) continue; + + oPos = pObj->RetPosition(0); + dist = Math::DistanceProjected(oPos, pos); + if ( dist > detect ) continue; + if ( dist < min ) + { + min = dist; + pBest = pObj; + } + } + if ( pBest == 0 ) return 0; // nothing found + + // Under the protection of a lightning conductor? + oPos = pBest->RetPosition(0); + for ( i=nbPara-1 ; i>=0 ; i-- ) + { + dist = Math::DistanceProjected(oPos, pPos[i]); + if ( dist <= BLITZPARA ) + { + return pObjPara[i]; + } + } + return pBest; +} + diff --git a/src/old/blitz.h b/src/old/blitz.h index 87e9a76..8289576 100644 --- a/src/old/blitz.h +++ b/src/old/blitz.h @@ -1,83 +1,83 @@ -// * 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/. - -// blitz.h - -#pragma once - - -#include "common/misc.h" -#include "math/point.h" -#include "old/d3dengine.h" - - -class CObject; -class CInstanceManager; -class CD3DEngine; -class CTerrain; -class CCamera; -class CSound; - - - -const float BLITZPARA = 200.0f; // radius of lightning protection -const int BLITZMAX = 50; - -enum BlitzPhase -{ - BPH_WAIT, - BPH_BLITZ, -}; - - - -class CBlitz -{ -public: - CBlitz(CInstanceManager* iMan, CD3DEngine* engine); - ~CBlitz(); - - void Flush(); - bool EventProcess(const Event &event); - bool Create(float sleep, float delay, float magnetic); - bool GetStatus(float &sleep, float &delay, float &magnetic, float &progress); - bool SetStatus(float sleep, float delay, float magnetic, float progress); - void Draw(); - -protected: - bool EventFrame(const Event &event); - CObject* SearchObject(Math::Vector pos); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - CTerrain* m_terrain; - CCamera* m_camera; - CSound* m_sound; - - bool m_bBlitzExist; - float m_sleep; - float m_delay; - float m_magnetic; - BlitzPhase m_phase; - float m_time; - float m_speed; - float m_progress; - Math::Vector m_pos; - Math::Point m_shift[BLITZMAX]; - float m_width[BLITZMAX]; -}; - +// * 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/. + +// blitz.h + +#pragma once + + +#include "common/misc.h" +#include "math/point.h" +#include "old/d3dengine.h" + + +class CObject; +class CInstanceManager; +class CD3DEngine; +class CTerrain; +class CCamera; +class CSound; + + + +const float BLITZPARA = 200.0f; // radius of lightning protection +const int BLITZMAX = 50; + +enum BlitzPhase +{ + BPH_WAIT, + BPH_BLITZ, +}; + + + +class CBlitz +{ +public: + CBlitz(CInstanceManager* iMan, CD3DEngine* engine); + ~CBlitz(); + + void Flush(); + bool EventProcess(const Event &event); + bool Create(float sleep, float delay, float magnetic); + bool GetStatus(float &sleep, float &delay, float &magnetic, float &progress); + bool SetStatus(float sleep, float delay, float magnetic, float progress); + void Draw(); + +protected: + bool EventFrame(const Event &event); + CObject* SearchObject(Math::Vector pos); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + CTerrain* m_terrain; + CCamera* m_camera; + CSound* m_sound; + + bool m_bBlitzExist; + float m_sleep; + float m_delay; + float m_magnetic; + BlitzPhase m_phase; + float m_time; + float m_speed; + float m_progress; + Math::Vector m_pos; + Math::Point m_shift[BLITZMAX]; + float m_width[BLITZMAX]; +}; + diff --git a/src/old/camera.cpp b/src/old/camera.cpp index 2c2ffef..cea9113 100644 --- a/src/old/camera.cpp +++ b/src/old/camera.cpp @@ -1,2109 +1,2109 @@ -// * 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/. - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "common/language.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/terrain.h" -#include "old/water.h" -#include "object/object.h" -#include "physics/physics.h" -#include "old/camera.h" - - - - -// Object's constructor. - -CCamera::CCamera(CInstanceManager* iMan) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_CAMERA, this); - - m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); - - m_type = CAMERA_FREE; - m_smooth = CS_NORM; - m_cameraObj = 0; - - m_eyeDistance = 10.0f; - m_initDelay = 0.0f; - - m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f); - m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f); - m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f); - m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f); - m_normEye = Math::Vector(0.0f, 0.0f, 0.0f); - m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f); - m_focus = 1.0f; - - m_bRightDown = false; - m_rightPosInit = Math::Point(0.5f, 0.5f); - m_rightPosCenter = Math::Point(0.5f, 0.5f); - m_rightPosMove = Math::Point(0.5f, 0.5f); - - m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); - m_directionH = 0.0f; - m_directionV = 0.0f; - m_heightEye = 20.0f; - m_heightLookat = 0.0f; - m_speed = 2.0f; - - m_backDist = 0.0f; - m_backMin = 0.0f; - m_addDirectionH = 0.0f; - m_addDirectionV = 0.0f; - m_bTransparency = false; - - m_fixDist = 0.0f; - m_fixDirectionH = 0.0f; - m_fixDirectionV = 0.0f; - - m_visitGoal = Math::Vector(0.0f, 0.0f, 0.0f); - m_visitDist = 0.0f; - m_visitTime = 0.0f; - m_visitType = CAMERA_NULL; - m_visitDirectionH = 0.0f; - m_visitDirectionV = 0.0f; - - m_editHeight = 40.0f; - - m_remotePan = 0.0f; - m_remoteZoom = 0.0f; - - m_mouseDirH = 0.0f; - m_mouseDirV = 0.0f; - m_mouseMarging = 0.01f; - - m_motorTurn = 0.0f; - - m_centeringPhase = CP_NULL; - m_centeringAngleH = 0.0f; - m_centeringAngleV = 0.0f; - m_centeringDist = 0.0f; - m_centeringCurrentH = 0.0f; - m_centeringCurrentV = 0.0f; - m_centeringTime = 0.0f; - m_centeringProgress = 0.0f; - - m_effectType = CE_NULL; - m_effectPos = Math::Vector(0.0f, 0.0f, 0.0f); - m_effectForce = 0.0f; - m_effectProgress = 0.0f; - m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); - - m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f); - m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f); - - m_bEffect = true; - m_bCameraScroll = true; - m_bCameraInvertX = false; - m_bCameraInvertY = false; -} - -// Object's constructor. - -CCamera::~CCamera() -{ -} - - -void CCamera::SetEffect(bool bEnable) -{ - m_bEffect = bEnable; -} - -void CCamera::SetCameraScroll(bool bScroll) -{ - m_bCameraScroll = bScroll; -} - -void CCamera::SetCameraInvertX(bool bInvert) -{ - m_bCameraInvertX = bInvert; -} - -void CCamera::SetCameraInvertY(bool bInvert) -{ - m_bCameraInvertY = bInvert; -} - - -// Returns an additional force to turn. - -float CCamera::RetMotorTurn() -{ - if ( m_type == CAMERA_BACK ) return m_motorTurn; - return 0.0f; -} - - - -// Initializes the camera. - -void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) -{ - Math::Vector vUpVec; - - m_initDelay = delay; - - eye.y += m_terrain->RetFloorLevel(eye, true); - lookat.y += m_terrain->RetFloorLevel(lookat, true); - - m_type = CAMERA_FREE; - m_eyePt = eye; - - m_directionH = Math::RotateAngle(eye.x-lookat.x, eye.z-lookat.z)+Math::PI/2.0f; - m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y-lookat.y); - - m_eyeDistance = 10.0f; - m_heightLookat = 10.0f; - m_backDist = 30.0f; - m_backMin = 10.0f; - m_addDirectionH = 0.0f; - m_addDirectionV = -Math::PI*0.05f; - m_fixDist = 50.0f; - m_fixDirectionH = Math::PI*0.25f; - m_fixDirectionV = -Math::PI*0.10f; - m_centeringPhase = CP_NULL; - m_actualEye = m_eyePt; - m_actualLookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); - m_finalEye = m_actualEye; - m_finalLookat = m_actualLookat; - m_scriptEye = m_actualEye; - m_scriptLookat = m_actualLookat; - m_focus = 1.00f; - m_remotePan = 0.0f; - m_remoteZoom = 0.0f; - - FlushEffect(); - FlushOver(); - SetType(CAMERA_FREE); -} - - -// Gives the object controlling the camera. - -void CCamera::SetObject(CObject* object) -{ - m_cameraObj = object; -} - -CObject* CCamera::RetObject() -{ - return m_cameraObj; -} - - -// Changes the level of transparency of an object and objects -// transported (battery & cargo). - -void SetTransparency(CObject* pObj, float value) -{ - CObject* pFret; - - pObj->SetTransparency(value); - - pFret = pObj->RetFret(); - if ( pFret != 0 ) - { - pFret->SetTransparency(value); - } - - pFret = pObj->RetPower(); - if ( pFret != 0 ) - { - pFret->SetTransparency(value); - } -} - -// Change the type of camera. - -void CCamera::SetType(CameraType type) -{ - CObject* pObj; - ObjectType oType; - Math::Vector vUpVec; - int i; - - m_remotePan = 0.0f; - m_remoteZoom = 0.0f; - - if ( m_type == CAMERA_BACK && m_bTransparency ) - { - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( pObj->RetTruck() ) continue; // battery or cargo? - - SetTransparency(pObj, 0.0f); // opaque object - } - } - m_bTransparency = false; - - if ( type == CAMERA_INFO || - type == CAMERA_VISIT ) // xx -> info ? - { - m_normEye = m_engine->RetEyePt(); - m_normLookat = m_engine->RetLookatPt(); - - m_engine->SetFocus(1.00f); // normal - m_type = type; - return; - } - - if ( m_type == CAMERA_INFO || - m_type == CAMERA_VISIT ) // info -> xx ? - { - m_engine->SetFocus(m_focus); // gives initial focus - m_type = type; - - vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); - SetViewParams(m_normEye, m_normLookat, vUpVec); - return; - } - - if ( m_type == CAMERA_BACK && type == CAMERA_FREE ) // back -> free ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); - } - - if ( m_type == CAMERA_BACK && type == CAMERA_EDIT ) // back -> edit ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f); - } - - if ( m_type == CAMERA_ONBOARD && type == CAMERA_FREE ) // onboard -> free ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); - } - - if ( m_type == CAMERA_ONBOARD && type == CAMERA_EDIT ) // onboard -> edit ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); - } - - if ( m_type == CAMERA_ONBOARD && type == CAMERA_EXPLO ) // onboard -> explo ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); - } - - if ( m_type == CAMERA_BACK && type == CAMERA_EXPLO ) // back -> explo ? - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f); - } - - if ( type == CAMERA_FIX || - type == CAMERA_PLANE ) - { - AbortCentering(); // Special stops framing - } - - m_fixDist = 50.0f; - if ( type == CAMERA_PLANE ) - { - m_fixDist = 60.0f; - } - - if ( type == CAMERA_BACK ) - { - AbortCentering(); // Special stops framing - m_addDirectionH = 0.0f; - m_addDirectionV = -Math::PI*0.05f; - - if ( m_cameraObj == 0 ) oType = OBJECT_NULL; - else oType = m_cameraObj->RetType(); - - m_backDist = 30.0f; - if ( oType == OBJECT_BASE ) m_backDist = 200.0f; - if ( oType == OBJECT_HUMAN ) m_backDist = 20.0f; - if ( oType == OBJECT_TECH ) m_backDist = 20.0f; - if ( oType == OBJECT_FACTORY ) m_backDist = 50.0f; - if ( oType == OBJECT_RESEARCH ) m_backDist = 40.0f; - if ( oType == OBJECT_DERRICK ) m_backDist = 40.0f; - if ( oType == OBJECT_REPAIR ) m_backDist = 35.0f; - if ( oType == OBJECT_DESTROYER) m_backDist = 35.0f; - if ( oType == OBJECT_TOWER ) m_backDist = 45.0f; - if ( oType == OBJECT_NUCLEAR ) m_backDist = 70.0f; - if ( oType == OBJECT_PARA ) m_backDist = 180.0f; - if ( oType == OBJECT_SAFE ) m_backDist = 50.0f; - if ( oType == OBJECT_HUSTON ) m_backDist = 120.0f; - - m_backMin = m_backDist/3.0f; - if ( oType == OBJECT_HUMAN ) m_backMin = 10.0f; - if ( oType == OBJECT_TECH ) m_backMin = 10.0f; - if ( oType == OBJECT_FACTORY ) m_backMin = 30.0f; - if ( oType == OBJECT_RESEARCH ) m_backMin = 20.0f; - if ( oType == OBJECT_NUCLEAR ) m_backMin = 32.0f; - if ( oType == OBJECT_PARA ) m_backMin = 40.0f; - if ( oType == OBJECT_SAFE ) m_backMin = 25.0f; - if ( oType == OBJECT_HUSTON ) m_backMin = 80.0f; - } - - if ( type != CAMERA_ONBOARD && m_cameraObj != 0 ) - { - m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right - } - - if ( type == CAMERA_ONBOARD ) - { - m_focus = 1.50f; // Wide - } - else - { - m_focus = 1.00f; // normal - } - m_engine->SetFocus(m_focus); - - m_type = type; - - SetSmooth(CS_NORM); -} - -CameraType CCamera::RetType() -{ - return m_type; -} - - -// Management of the smoothing mode. - -void CCamera::SetSmooth(CameraSmooth type) -{ - m_smooth = type; -} - -CameraSmooth CCamera::RetSmoth() -{ - return m_smooth; -} - - -// Management of the setback distance. - -void CCamera::SetDist(float dist) -{ - m_fixDist = dist; -} - -float CCamera::RetDist() -{ - return m_fixDist; -} - - -// Manage angle mode CAMERA_FIX. - -void CCamera::SetFixDirection(float angle) -{ - m_fixDirectionH = angle; -} - -float CCamera::RetFixDirection() -{ - return m_fixDirectionH; -} - - -// Managing the triggering mode of the camera panning. - -void CCamera::SetRemotePan(float value) -{ - m_remotePan = value; -} - -float CCamera::RetRemotePan() -{ - return m_remotePan; -} - -// Management of the remote zoom (0 .. 1) of the camera. - -void CCamera::SetRemoteZoom(float value) -{ - value = Math::Norm(value); - - if ( m_type == CAMERA_BACK ) - { - m_backDist = m_backMin+(200.0f-m_backMin)*value; - } - - if ( m_type == CAMERA_FIX || - m_type == CAMERA_PLANE ) - { - m_fixDist = 10.0f+(200.0f-10.0f)*value; - } -} - -float CCamera::RetRemoteZoom() -{ - if ( m_type == CAMERA_BACK ) - { - return (m_backDist-m_backMin)/(200.0f-m_backMin); - } - - if ( m_type == CAMERA_FIX || - m_type == CAMERA_PLANE ) - { - return (m_fixDist-10.0f)/(200.0f-10.0f); - } - return 0.0f; -} - - - -// Start with a tour round the camera. - -void CCamera::StartVisit(Math::Vector goal, float dist) -{ - m_visitType = m_type; - SetType(CAMERA_VISIT); - m_visitGoal = goal; - m_visitDist = dist; - m_visitTime = 0.0f; - m_visitDirectionH = 0.0f; - m_visitDirectionV = -Math::PI*0.10f; -} - -// Circular end of a visit with the camera. - -void CCamera::StopVisit() -{ - SetType(m_visitType); // presents the initial type -} - - -// Returns the point of view of the camera. - -void CCamera::RetCamera(Math::Vector &eye, Math::Vector &lookat) -{ - eye = m_eyePt; - lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); -} - - -// Specifies a special movement of camera to frame action. - -bool CCamera::StartCentering(CObject *object, float angleH, float angleV, - float dist, float time) -{ - if ( m_type != CAMERA_BACK ) return false; - if ( object != m_cameraObj ) return false; - - if ( m_centeringPhase != CP_NULL ) return false; - - if ( m_addDirectionH > Math::PI ) - { - angleH = Math::PI*2.0f-angleH; - } - - m_centeringPhase = CP_START; - m_centeringAngleH = angleH; - m_centeringAngleV = angleV; - m_centeringDist = dist; - m_centeringCurrentH = 0.0f; - m_centeringCurrentV = 0.0f; - m_centeringTime = time; - m_centeringProgress = 0.0f; - - return true; -} - -// Ends a special movement of camera to frame action. - -bool CCamera::StopCentering(CObject *object, float time) -{ - if ( m_type != CAMERA_BACK ) return false; - if ( object != m_cameraObj ) return false; - - if ( m_centeringPhase != CP_START && - m_centeringPhase != CP_WAIT ) return false; - - m_centeringPhase = CP_STOP; - - if ( m_centeringAngleH != 99.9f ) - { - m_centeringAngleH = m_centeringCurrentH; - } - if ( m_centeringAngleV != 99.9f ) - { - m_centeringAngleV = m_centeringCurrentV; - } - - m_centeringTime = time; - m_centeringProgress = 0.0f; - - return true; -} - -// Stop framing special in the current position. - -void CCamera::AbortCentering() -{ - if ( m_type == CAMERA_INFO || - m_type == CAMERA_VISIT ) return; - - if ( m_centeringPhase == CP_NULL ) return; - - m_centeringPhase = CP_NULL; - - if ( m_centeringAngleH != 99.9f ) - { - m_addDirectionH = m_centeringCurrentH; - } - if ( m_centeringAngleV != 99.9f ) - { - m_addDirectionV = m_centeringCurrentV; - } -} - - - -// Removes the special effect with the camera - -void CCamera::FlushEffect() -{ - m_effectType = CE_NULL; - m_effectForce = 0.0f; - m_effectProgress = 0.0f; - m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); -} - -// Starts a special effect with the camera. - -void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) -{ - if ( !m_bEffect ) return; - - m_effectType = effect; - m_effectPos = pos; - m_effectForce = force; - m_effectProgress = 0.0f; -} - -// Advances the effect of the camera. - -void CCamera::EffectFrame(const Event &event) -{ - float dist, force; - - if ( m_type == CAMERA_INFO || - m_type == CAMERA_VISIT ) return; - - if ( m_effectType == CE_NULL ) return; - - m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); - force = m_effectForce; - - if ( m_effectType == CE_TERRAFORM ) - { - m_effectProgress += event.rTime*0.7f; - m_effectOffset.x = (Math::Rand()-0.5f)*10.0f; - m_effectOffset.y = (Math::Rand()-0.5f)*10.0f; - m_effectOffset.z = (Math::Rand()-0.5f)*10.0f; - - force *= 1.0f-m_effectProgress; - } - - if ( m_effectType == CE_EXPLO ) - { - m_effectProgress += event.rTime*1.0f; - m_effectOffset.x = (Math::Rand()-0.5f)*5.0f; - m_effectOffset.y = (Math::Rand()-0.5f)*5.0f; - m_effectOffset.z = (Math::Rand()-0.5f)*5.0f; - - force *= 1.0f-m_effectProgress; - } - - if ( m_effectType == CE_SHOT ) - { - m_effectProgress += event.rTime*1.0f; - m_effectOffset.x = (Math::Rand()-0.5f)*2.0f; - m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; - m_effectOffset.z = (Math::Rand()-0.5f)*2.0f; - - force *= 1.0f-m_effectProgress; - } - - if ( m_effectType == CE_CRASH ) - { - m_effectProgress += event.rTime*5.0f; - m_effectOffset.y = sinf(m_effectProgress*Math::PI)*1.5f; - m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); - m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); - } - - if ( m_effectType == CE_VIBRATION ) - { - m_effectProgress += event.rTime*0.1f; - m_effectOffset.y = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); - m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); - m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); - } - - if ( m_effectType == CE_PET ) - { - m_effectProgress += event.rTime*5.0f; - m_effectOffset.x = (Math::Rand()-0.5f)*0.2f; - m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; - m_effectOffset.z = (Math::Rand()-0.5f)*0.2f; - } - - dist = Math::Distance(m_eyePt, m_effectPos); - dist = Math::Norm((dist-100.f)/100.0f); - - force *= 1.0f-dist; -#if _TEEN - force *= 2.0f; -#endif - m_effectOffset *= force; - - if ( m_effectProgress >= 1.0f ) - { - FlushEffect(); - } -} - - -// Removes the effect of superposition in the foreground. - -void CCamera::FlushOver() -{ - m_overType = OE_NULL; - m_overColorBase.r = 0.0f; // black - m_overColorBase.g = 0.0f; - m_overColorBase.b = 0.0f; - m_overColorBase.a = 0.0f; - m_engine->SetOverColor(); // nothing -} - -// Specifies the base color. - -void CCamera::SetOverBaseColor(D3DCOLORVALUE color) -{ - m_overColorBase = color; -} - -// Starts a layering effect in the foreground. - -void CCamera::StartOver(OverEffect effect, Math::Vector pos, float force) -{ - D3DCOLOR color; - float dist, decay; - - m_overType = effect; - m_overTime = 0.0f; - - if ( m_overType == OE_BLITZ ) decay = 400.0f; - else decay = 100.0f; - dist = Math::Distance(m_eyePt, pos); - dist = (dist-decay)/decay; - if ( dist < 0.0f ) dist = 0.0f; - if ( dist > 1.0f ) dist = 1.0f; - - m_overForce = force * (1.0f-dist); - - if ( m_overType == OE_BLOOD ) - { - m_overColor.r = 0.8f; - m_overColor.g = 0.1f; - m_overColor.b = 0.1f; // red - m_overMode = D3DSTATETCb; - - m_overFadeIn = 0.4f; - m_overFadeOut = 0.8f; - m_overForce = 1.0f; - } - - if ( m_overType == OE_FADEINw ) - { - m_overColor.r = 1.0f; - m_overColor.g = 1.0f; - m_overColor.b = 1.0f; // white - m_overMode = D3DSTATETCb; - - m_overFadeIn = 0.0f; - m_overFadeOut =20.0f; - m_overForce = 1.0f; - } - - if ( m_overType == OE_FADEOUTw ) - { - m_overColor.r = 1.0f; - m_overColor.g = 1.0f; - m_overColor.b = 1.0f; // white - m_overMode = D3DSTATETCb; - - m_overFadeIn = 6.0f; - m_overFadeOut = 100000.0f; - m_overForce = 1.0f; - } - - if ( m_overType == OE_FADEOUTb ) - { - color = m_engine->RetFogColor(1); // fog color underwater - m_overColor = RetColor(color); - m_overMode = D3DSTATETCw; - - m_overFadeIn = 4.0f; - m_overFadeOut = 100000.0f; - m_overForce = 1.0f; - } - - if ( m_overType == OE_BLITZ ) - { - m_overColor.r = 0.9f; - m_overColor.g = 1.0f; - m_overColor.b = 1.0f; // white-cyan - m_overMode = D3DSTATETCb; - - m_overFadeIn = 0.0f; - m_overFadeOut = 1.0f; - } -} - -// Advanced overlay effect in the foreground. - -void CCamera::OverFrame(const Event &event) -{ - D3DCOLORVALUE color; - float intensity; - - if ( m_type == CAMERA_INFO || - m_type == CAMERA_VISIT ) return; - - if ( m_overType == OE_NULL ) - { - return; - } - - m_overTime += event.rTime; - - if ( m_overType == OE_BLITZ ) - { - if ( rand()%2 == 0 ) - { - color.r = m_overColor.r*m_overForce; - color.g = m_overColor.g*m_overForce; - color.b = m_overColor.b*m_overForce; - } - else - { - color.r = 0.0f; - color.g = 0.0f; - color.b = 0.0f; - } - color.a = 0.0f; - m_engine->SetOverColor(RetColor(color), m_overMode); - } - else - { - if ( m_overFadeIn > 0.0f && m_overTime < m_overFadeIn ) - { - intensity = m_overTime/m_overFadeIn; - intensity *= m_overForce; - - if ( m_overMode == D3DSTATETCw ) - { - color.r = 1.0f-(1.0f-m_overColor.r)*intensity; - color.g = 1.0f-(1.0f-m_overColor.g)*intensity; - color.b = 1.0f-(1.0f-m_overColor.b)*intensity; - } - else - { - color.r = m_overColor.r*intensity; - color.g = m_overColor.g*intensity; - color.b = m_overColor.b*intensity; - - color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); - color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); - color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); - } - color.a = 0.0f; - m_engine->SetOverColor(RetColor(color), m_overMode); - } - else if ( m_overFadeOut > 0.0f && m_overTime-m_overFadeIn < m_overFadeOut ) - { - intensity = 1.0f-(m_overTime-m_overFadeIn)/m_overFadeOut; - intensity *= m_overForce; - - if ( m_overMode == D3DSTATETCw ) - { - color.r = 1.0f-(1.0f-m_overColor.r)*intensity; - color.g = 1.0f-(1.0f-m_overColor.g)*intensity; - color.b = 1.0f-(1.0f-m_overColor.b)*intensity; - } - else - { - color.r = m_overColor.r*intensity; - color.g = m_overColor.g*intensity; - color.b = m_overColor.b*intensity; - - color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); - color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); - color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); - } - color.a = 0.0f; - m_engine->SetOverColor(RetColor(color), m_overMode); - } - } - - if ( m_overTime >= m_overFadeIn+m_overFadeOut ) - { - FlushOver(); - return; - } -} - - - -// Sets the soft movement of the camera. - -void CCamera::FixCamera() -{ - m_initDelay = 0.0f; - m_actualEye = m_finalEye = m_scriptEye; - m_actualLookat = m_finalLookat = m_scriptLookat; - SetViewTime(m_scriptEye, m_scriptLookat, 0.0f); -} - -// Specifies the location and direction of view to the 3D engine. - -void CCamera::SetViewTime(const Math::Vector &vEyePt, - const Math::Vector &vLookatPt, - float rTime) -{ - Math::Vector vUpVec, eye, lookat; - float prog, dist, h; - - if ( m_type == CAMERA_INFO ) - { - eye = vEyePt; - lookat = vLookatPt; - } - else - { - if ( m_initDelay > 0.0f ) - { - m_initDelay -= rTime; - if ( m_initDelay < 0.0f ) m_initDelay = 0.0f; - rTime /= 1.0f+m_initDelay; - } - - eye = vEyePt; - lookat = vLookatPt; - if ( !IsCollision(eye, lookat) ) - { - m_finalEye = eye; - m_finalLookat = lookat; - } - - dist = Math::Distance(m_finalEye, m_actualEye); - if ( m_smooth == CS_NONE ) prog = dist; - if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*0.5f; - if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; - if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*0.05f; - if ( dist == 0.0f ) - { - m_actualEye = m_finalEye; - } - else - { - if ( prog > dist ) prog = dist; - m_actualEye = (m_finalEye-m_actualEye)/dist*prog + m_actualEye; - } - - dist = Math::Distance(m_finalLookat, m_actualLookat); - if ( m_smooth == CS_NONE ) prog = dist; - if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*2.0f; - if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; - if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*4.0f; - if ( dist == 0.0f ) - { - m_actualLookat = m_finalLookat; - } - else - { - if ( prog > dist ) prog = dist; - m_actualLookat = (m_finalLookat-m_actualLookat)/dist*prog + m_actualLookat; - } - - eye = m_effectOffset+m_actualEye; - m_water->AdjustEye(eye); - - h = m_terrain->RetFloorLevel(eye); - if ( eye.y < h+4.0f ) - { - eye.y = h+4.0f; - } - - lookat = m_effectOffset+m_actualLookat; - } - - vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); - SetViewParams(eye, lookat, vUpVec); -} - - -// Avoid the obstacles. - -bool CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) -{ - if ( m_type == CAMERA_BACK ) return IsCollisionBack(eye, lookat); - if ( m_type == CAMERA_FIX ) return IsCollisionFix(eye, lookat); - if ( m_type == CAMERA_PLANE ) return IsCollisionFix(eye, lookat); - return false; -} - -// Avoid the obstacles. - -bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) -{ -#if 0 - CObject *pObj; - Math::Vector oPos, min, max, proj; - ObjectType oType, iType; - float oRadius, dpp, dpl, del, dist, len, prox; - int i; - - if ( m_cameraObj == 0 ) - { - iType = OBJECT_NULL; - } - else - { - iType = m_cameraObj->RetType(); - } - - min.x = Math::Min(eye.x, lookat.x); - min.y = Math::Min(eye.y, lookat.y); - min.z = Math::Min(eye.z, lookat.z); - - max.x = Math::Max(eye.x, lookat.x); - max.y = Math::Max(eye.y, lookat.y); - max.z = Math::Max(eye.z, lookat.z); - - prox = 8.0f; // maximum proximity of the vehicle - - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( pObj == m_cameraObj ) continue; - - oType = pObj->RetType(); - if ( oType == OBJECT_TOTO || - oType == OBJECT_FIX || - oType == OBJECT_FRET || - oType == OBJECT_STONE || - oType == OBJECT_URANIUM || - oType == OBJECT_METAL || - oType == OBJECT_POWER || - oType == OBJECT_ATOMIC || - oType == OBJECT_BULLET || - oType == OBJECT_BBOX || - oType == OBJECT_TNT || - oType == OBJECT_BOMB || - oType == OBJECT_WAYPOINTb || - oType == OBJECT_WAYPOINTr || - oType == OBJECT_WAYPOINTg || - oType == OBJECT_WAYPOINTy || - oType == OBJECT_WAYPOINTv || - oType == OBJECT_FLAGb || - oType == OBJECT_FLAGr || - oType == OBJECT_FLAGg || - oType == OBJECT_FLAGy || - oType == OBJECT_FLAGv || - oType == OBJECT_ANT || - oType == OBJECT_SPIDER || - oType == OBJECT_BEE || - oType == OBJECT_WORM ) continue; - - pObj->GetGlobalSphere(oPos, oRadius); - if ( oRadius <= 0.0f ) continue; - - if ( oPos.x+oRadius < min.x || - oPos.y+oRadius < min.y || - oPos.z+oRadius < min.z || - oPos.x-oRadius > max.x || - oPos.y-oRadius > max.y || - oPos.z-oRadius > max.z ) continue; - - if ( iType == OBJECT_FACTORY ) - { - dpl = Math::Distance(oPos, lookat); - if ( dpl < oRadius ) continue; - } - - proj = Projection(eye, lookat, oPos); - dpp = Math::Distance(proj, oPos); - if ( dpp > oRadius ) continue; - - del = Math::Distance(eye, lookat); - len = Math::Distance(eye, proj); - if ( len > del ) continue; - - dist = sqrtf(oRadius*oRadius + dpp*dpp)-3.0f; - if ( dist < 0.0f ) dist = 0.0f; - proj = (lookat-eye)*dist/del + proj; - len = Math::Distance(eye, proj); - - if ( len < del-prox ) - { - eye = proj; - eye.y += len/5.0f; - return false; - } - else - { - eye = (eye-lookat)*prox/del + lookat; - eye.y += (del-prox)/5.0f; - return false; - } - } - return false; -#else - CObject *pObj; - Math::Vector oPos, min, max, proj; - ObjectType oType, iType; - float oRadius, dpp, del, len, angle; - int i; - - if ( m_cameraObj == 0 ) - { - iType = OBJECT_NULL; - } - else - { - iType = m_cameraObj->RetType(); - } - - min.x = Math::Min(m_actualEye.x, m_actualLookat.x); - min.y = Math::Min(m_actualEye.y, m_actualLookat.y); - min.z = Math::Min(m_actualEye.z, m_actualLookat.z); - - max.x = Math::Max(m_actualEye.x, m_actualLookat.x); - max.y = Math::Max(m_actualEye.y, m_actualLookat.y); - max.z = Math::Max(m_actualEye.z, m_actualLookat.z); - - m_bTransparency = false; - - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( pObj->RetTruck() ) continue; // battery or cargo? - - SetTransparency(pObj, 0.0f); // opaque object - - if ( pObj == m_cameraObj ) continue; - - if ( iType == OBJECT_BASE || // building? - iType == OBJECT_DERRICK || - iType == OBJECT_FACTORY || - iType == OBJECT_STATION || - iType == OBJECT_CONVERT || - iType == OBJECT_REPAIR || - iType == OBJECT_DESTROYER|| - iType == OBJECT_TOWER || - iType == OBJECT_RESEARCH || - iType == OBJECT_RADAR || - iType == OBJECT_ENERGY || - iType == OBJECT_LABO || - iType == OBJECT_NUCLEAR || - iType == OBJECT_PARA || - iType == OBJECT_SAFE || - iType == OBJECT_HUSTON ) continue; - - oType = pObj->RetType(); - if ( oType == OBJECT_HUMAN || - oType == OBJECT_TECH || - oType == OBJECT_TOTO || - oType == OBJECT_FIX || - oType == OBJECT_FRET || - oType == OBJECT_ANT || - oType == OBJECT_SPIDER || - oType == OBJECT_BEE || - oType == OBJECT_WORM ) continue; - - pObj->GetGlobalSphere(oPos, oRadius); - if ( oRadius <= 2.0f ) continue; // ignores small objects - - if ( oPos.x+oRadius < min.x || - oPos.y+oRadius < min.y || - oPos.z+oRadius < min.z || - oPos.x-oRadius > max.x || - oPos.y-oRadius > max.y || - oPos.z-oRadius > max.z ) continue; - - proj = Projection(m_actualEye, m_actualLookat, oPos); - dpp = Math::Distance(proj, oPos); - if ( dpp > oRadius ) continue; - - if ( oType == OBJECT_FACTORY ) - { - angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW ! - angle = Math::Direction(angle, pObj->RetAngleY(0)); - if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate? - } - - del = Math::Distance(m_actualEye, m_actualLookat); - if ( oType == OBJECT_FACTORY ) - { - del += oRadius; - } - - len = Math::Distance(m_actualEye, proj); - if ( len > del ) continue; - - SetTransparency(pObj, 1.0f); // transparent object - m_bTransparency = true; - } - return false; -#endif -} - -// Avoid the obstacles. - -bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) -{ - CObject *pObj; - Math::Vector oPos, proj; - ObjectType type; - float oRadius, dist; - int i; - - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( pObj == m_cameraObj ) continue; - - type = pObj->RetType(); - if ( type == OBJECT_TOTO || - type == OBJECT_FRET || - type == OBJECT_STONE || - type == OBJECT_URANIUM || - type == OBJECT_METAL || - type == OBJECT_POWER || - type == OBJECT_ATOMIC || - type == OBJECT_BULLET || - type == OBJECT_BBOX || - type == OBJECT_KEYa || - type == OBJECT_KEYb || - type == OBJECT_KEYc || - type == OBJECT_KEYd || - type == OBJECT_ANT || - type == OBJECT_SPIDER || - type == OBJECT_BEE || - type == OBJECT_WORM ) continue; - - pObj->GetGlobalSphere(oPos, oRadius); - if ( oRadius == 0.0f ) continue; - - dist = Math::Distance(eye, oPos); - if ( dist < oRadius ) - { - dist = Math::Distance(eye, lookat); - proj = Projection(eye, lookat, oPos); - eye = (lookat-eye)*oRadius/dist + proj; - return false; - } - } - return false; -} - - -// Management of an event. - -bool CCamera::EventProcess(const Event &event) -{ - switch( event.event ) - { - case EVENT_FRAME: - EventFrame(event); - break; - -#if 0 - case EVENT_RBUTTONDOWN: - m_bRightDown = true; - m_rightPosInit = event.pos; - m_rightPosCenter = Math::Point(0.5f, 0.5f); - m_engine->MoveMousePos(m_rightPosCenter); -//? m_engine->SetMouseHide(true); // cache la souris - break; - - case EVENT_RBUTTONUP: - m_bRightDown = false; - m_engine->MoveMousePos(m_rightPosInit); -//? m_engine->SetMouseHide(false); // remontre la souris - m_addDirectionH = 0.0f; - m_addDirectionV = -Math::PI*0.05f; - break; -#endif - - case EVENT_MOUSEMOVE: - EventMouseMove(event); - break; - - case EVENT_KEYDOWN: - if ( event.param == VK_WHEELUP ) EventMouseWheel(+1); - if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1); - break; - } - return true; -} - -// Changed the camera according to the mouse moved. - -bool CCamera::EventMouseMove(const Event &event) -{ - m_mousePos = event.pos; - return true; -} - -// Mouse wheel operated. - -void CCamera::EventMouseWheel(int dir) -{ - if ( m_type == CAMERA_BACK ) - { - if ( dir > 0 ) - { - m_backDist -= 8.0f; - if ( m_backDist < m_backMin ) m_backDist = m_backMin; - } - if ( dir < 0 ) - { - m_backDist += 8.0f; - if ( m_backDist > 200.0f ) m_backDist = 200.0f; - } - } - - if ( m_type == CAMERA_FIX || - m_type == CAMERA_PLANE ) - { - if ( dir > 0 ) - { - m_fixDist -= 8.0f; - if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; - } - if ( dir < 0 ) - { - m_fixDist += 8.0f; - if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; - } - } - - if ( m_type == CAMERA_VISIT ) - { - if ( dir > 0 ) - { - m_visitDist -= 8.0f; - if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; - } - if ( dir < 0 ) - { - m_visitDist += 8.0f; - if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; - } - } -} - -// Changed the camera according to the time elapsed. - -bool CCamera::EventFrame(const Event &event) -{ - EffectFrame(event); - OverFrame(event); - - if ( m_type == CAMERA_FREE ) - { - return EventFrameFree(event); - } - if ( m_type == CAMERA_EDIT ) - { - return EventFrameEdit(event); - } - if ( m_type == CAMERA_DIALOG ) - { - return EventFrameDialog(event); - } - if ( m_type == CAMERA_BACK ) - { - return EventFrameBack(event); - } - if ( m_type == CAMERA_FIX || - m_type == CAMERA_PLANE ) - { - return EventFrameFix(event); - } - if ( m_type == CAMERA_EXPLO ) - { - return EventFrameExplo(event); - } - if ( m_type == CAMERA_ONBOARD ) - { - return EventFrameOnBoard(event); - } - if ( m_type == CAMERA_SCRIPT ) - { - return EventFrameScript(event); - } - if ( m_type == CAMERA_INFO ) - { - return EventFrameInfo(event); - } - if ( m_type == CAMERA_VISIT ) - { - return EventFrameVisit(event); - } - - return true; -} - - -// Returns the default sprite to use for the mouse. - -D3DMouse CCamera::RetMouseDef(Math::Point pos) -{ - D3DMouse type; - - type = D3DMOUSENORM; - m_mousePos = pos; - - if ( m_type == CAMERA_INFO ) return type; - - if ( m_bRightDown ) // the right button pressed? - { - m_rightPosMove.x = pos.x - m_rightPosCenter.x; - m_rightPosMove.y = pos.y - m_rightPosCenter.y; - type = D3DMOUSEMOVE; - } - else - { - if ( !m_bCameraScroll ) return type; - - m_mouseDirH = 0.0f; - m_mouseDirV = 0.0f; - - if ( pos.x < m_mouseMarging ) - { - m_mouseDirH = pos.x/m_mouseMarging - 1.0f; - } - - if ( pos.x > 1.0f-m_mouseMarging ) - { - m_mouseDirH = 1.0f - (1.0f-pos.x)/m_mouseMarging; - } - - if ( pos.y < m_mouseMarging ) - { - m_mouseDirV = pos.y/m_mouseMarging - 1.0f; - } - - if ( pos.y > 1.0f-m_mouseMarging ) - { - m_mouseDirV = 1.0f - (1.0f-pos.y)/m_mouseMarging; - } - - if ( m_type == CAMERA_FREE || - m_type == CAMERA_EDIT || - m_type == CAMERA_BACK || - m_type == CAMERA_FIX || - m_type == CAMERA_PLANE || - m_type == CAMERA_EXPLO ) - { - if ( m_mouseDirH > 0.0f ) - { - type = D3DMOUSESCROLLR; - } - if ( m_mouseDirH < 0.0f ) - { - type = D3DMOUSESCROLLL; - } - } - - if ( m_type == CAMERA_FREE || - m_type == CAMERA_EDIT ) - { - if ( m_mouseDirV > 0.0f ) - { - type = D3DMOUSESCROLLU; - } - if ( m_mouseDirV < 0.0f ) - { - type = D3DMOUSESCROLLD; - } - } - - if ( m_bCameraInvertX ) - { - m_mouseDirH = -m_mouseDirH; - } - } - - return type; -} - - - -// Moves the point of view. - -bool CCamera::EventFrameFree(const Event &event) -{ - Math::Vector pos, vLookatPt; - float factor; - - factor = m_heightEye*0.5f+30.0f; - - if ( m_mouseDirH != 0.0f ) - { - m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; - } - if ( m_mouseDirV != 0.0f ) - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); - } - - // Up/Down. - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, event.axeY*event.rTime*factor*m_speed); - - // Left/Right. - if ( event.keyState & KS_CONTROL ) - { - if ( event.axeX < 0.0f ) - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH+Math::PI/2.0f, m_directionV, -event.axeX*event.rTime*factor*m_speed); - } - if ( event.axeX > 0.0f ) - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH-Math::PI/2.0f, m_directionV, event.axeX*event.rTime*factor*m_speed); - } - } - else - { - m_directionH -= event.axeX*event.rTime*0.7f*m_speed; - } - - // PageUp/PageDown. - if ( event.keyState & KS_NUMMINUS ) - { - if ( m_heightEye < 500.0f ) - { - m_heightEye += event.rTime*factor*m_speed; - } - } - if ( event.keyState & KS_NUMPLUS ) - { - if ( m_heightEye > -2.0f ) - { - m_heightEye -= event.rTime*factor*m_speed; - } - } - - m_terrain->ValidPosition(m_eyePt, 10.0f); - - if ( m_terrain->MoveOnFloor(m_eyePt, true) ) - { - m_eyePt.y += m_heightEye; - - pos = m_eyePt; - if ( m_terrain->MoveOnFloor(pos, true) ) - { - pos.y -= 2.0f; - if ( m_eyePt.y < pos.y ) - { - m_eyePt.y = pos.y; - } - } - - } - - vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); - - if ( m_terrain->MoveOnFloor(vLookatPt, true) ) - { - vLookatPt.y += m_heightLookat; - } - - SetViewTime(m_eyePt, vLookatPt, event.rTime); - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameEdit(const Event &event) -{ - Math::Vector pos, vLookatPt; - float factor; - - factor = m_editHeight*0.5f+30.0f; - - if ( m_mouseDirH != 0.0f ) - { - m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; - } - if ( m_mouseDirV != 0.0f ) - { - m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); - } - - if ( m_bCameraScroll ) - { - // Left/Right. - m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; - m_fixDirectionH = Math::NormAngle(m_fixDirectionH); - - // Up/Down. -//? m_fixDirectionV -= m_mouseDirV*event.rTime*0.5f*m_speed; -//? if ( m_fixDirectionV < -Math::PI*0.40f ) m_fixDirectionV = -Math::PI*0.40f; -//? if ( m_fixDirectionV > Math::PI*0.20f ) m_fixDirectionV = Math::PI*0.20f; - } - - m_terrain->ValidPosition(m_eyePt, 10.0f); - - if ( m_terrain->MoveOnFloor(m_eyePt, false) ) - { - m_eyePt.y += m_editHeight; - - pos = m_eyePt; - if ( m_terrain->MoveOnFloor(pos, false) ) - { - pos.y += 2.0f; - if ( m_eyePt.y < pos.y ) - { - m_eyePt.y = pos.y; - } - } - - } - - vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); - - if ( m_terrain->MoveOnFloor(vLookatPt, true) ) - { - vLookatPt.y += m_heightLookat; - } - - SetViewTime(m_eyePt, vLookatPt, event.rTime); - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameDialog(const Event &event) -{ - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameBack(const Event &event) -{ - CPhysics* physics; - ObjectType type; - Math::Vector pos, vLookatPt; - Math::Point mouse; - float centeringH, centeringV, centeringD, h, v, d, floor; - - if ( m_cameraObj == 0 ) - { - type = OBJECT_NULL; - } - else - { - type = m_cameraObj->RetType(); - } - - // +/-. - if ( event.keyState & KS_NUMPLUS ) - { - m_backDist -= event.rTime*30.0f*m_speed; - if ( m_backDist < m_backMin ) m_backDist = m_backMin; - } - if ( event.keyState & KS_NUMMINUS ) - { - m_backDist += event.rTime*30.0f*m_speed; - if ( m_backDist > 200.0f ) m_backDist = 200.0f; - } - - m_motorTurn = 0.0f; - - if ( m_bRightDown ) - { - m_addDirectionH = m_rightPosMove.x*6.0f; - m_addDirectionV = -m_rightPosMove.y*2.0f; - } - else - { - if ( m_bCameraScroll ) - { -#if 1 - // Left/Right. - m_addDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; - m_addDirectionH = Math::NormAngle(m_addDirectionH); - - // Up/Down. -//? m_backDist -= m_mouseDirV*event.rTime*30.0f*m_speed; -//? if ( m_backDist < 10.0f ) m_backDist = 10.0f; -//? if ( m_backDist > 200.0f ) m_backDist = 200.0f; -#else - if ( m_mousePos.y >= 0.18f && m_mousePos.y <= 0.93f ) - { -//? m_addDirectionH = -(m_mousePos.x-0.5f)*4.0f; - m_addDirectionV = (m_mousePos.y-0.5f)*2.0f; -//? if ( m_bCameraInvertX ) m_addDirectionH = -m_addDirectionH; - if ( m_bCameraInvertY ) m_addDirectionV = -m_addDirectionV; - - if ( m_mousePos.x < 0.5f ) m_motorTurn = -1.0f; - if ( m_mousePos.x > 0.5f ) m_motorTurn = 1.0f; - - mouse = m_mousePos; - mouse.x = 0.5f; - m_engine->MoveMousePos(mouse); - } - else - { - m_addDirectionH = 0.0f; - m_addDirectionV = 0.0f; - } -#endif - } - } - - if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) - { - AbortCentering(); // special stops framing - } - - // Increase the special framework. - centeringH = 0.0f; - centeringV = 0.0f; - centeringD = 0.0f; - - if ( m_centeringPhase == CP_START ) - { - m_centeringProgress += event.rTime/m_centeringTime; - if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; - centeringH = m_centeringProgress; - centeringV = m_centeringProgress; - centeringD = m_centeringProgress; - if ( m_centeringProgress >= 1.0f ) - { - m_centeringPhase = CP_WAIT; - } - } - - if ( m_centeringPhase == CP_WAIT ) - { - centeringH = 1.0f; - centeringV = 1.0f; - centeringD = 1.0f; - } - - if ( m_centeringPhase == CP_STOP ) - { - m_centeringProgress += event.rTime/m_centeringTime; - if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; - centeringH = 1.0f-m_centeringProgress; - centeringV = 1.0f-m_centeringProgress; - centeringD = 1.0f-m_centeringProgress; - if ( m_centeringProgress >= 1.0f ) - { - m_centeringPhase = CP_NULL; - } - } - - if ( m_centeringAngleH == 99.9f ) centeringH = 0.0f; - if ( m_centeringAngleV == 99.9f ) centeringV = 0.0f; - if ( m_centeringDist == 0.0f ) centeringD = 0.0f; - - if ( m_cameraObj != 0 ) - { - vLookatPt = m_cameraObj->RetPosition(0); - if ( type == OBJECT_BASE ) vLookatPt.y += 40.0f; - else if ( type == OBJECT_HUMAN ) vLookatPt.y += 1.0f; - else if ( type == OBJECT_TECH ) vLookatPt.y += 1.0f; - else vLookatPt.y += 4.0f; - - h = -m_cameraObj->RetAngleY(0); // angle vehicle / building - - if ( type == OBJECT_DERRICK || - type == OBJECT_FACTORY || - type == OBJECT_REPAIR || - type == OBJECT_DESTROYER|| - type == OBJECT_STATION || - type == OBJECT_CONVERT || - type == OBJECT_TOWER || - type == OBJECT_RESEARCH || - type == OBJECT_RADAR || - type == OBJECT_INFO || - type == OBJECT_ENERGY || - type == OBJECT_LABO || - type == OBJECT_NUCLEAR || - type == OBJECT_PARA || - type == OBJECT_SAFE || - type == OBJECT_HUSTON || - type == OBJECT_START || - type == OBJECT_END ) // building? - { - h += Math::PI*0.20f; // nearly face - } - else // vehicle? - { - h += Math::PI; // back - } - h = Math::NormAngle(h)+m_remotePan; - v = 0.0f; //? - - h += m_centeringCurrentH; - h += m_addDirectionH*(1.0f-centeringH); - h = Math::NormAngle(h); - - if ( type == OBJECT_MOBILEdr ) // designer? - { - v -= 0.3f; // Camera top - } - - v += m_centeringCurrentV; - v += m_addDirectionV*(1.0f-centeringV); - - d = m_backDist; - d += m_centeringDist*centeringD; - - m_centeringCurrentH = m_centeringAngleH*centeringH; - m_centeringCurrentV = m_centeringAngleV*centeringV; - - m_eyePt = RotateView(vLookatPt, h, v, d); - - physics = m_cameraObj->RetPhysics(); - if ( physics != 0 && physics->RetLand() ) // ground? - { - pos = vLookatPt+(vLookatPt-m_eyePt); - floor = m_terrain->RetFloorHeight(pos)-4.0f; - if ( floor > 0.0f ) - { - m_eyePt.y += floor; // shows the descent in front - } - } - - m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); - m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); - - SetViewTime(m_eyePt, vLookatPt, event.rTime); - - m_directionH = h+Math::PI/2.0f; - m_directionV = v; - } - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameFix(const Event &event) -{ - Math::Vector pos, vLookatPt; - float h, v, d; - - // +/-. - if ( event.keyState & KS_NUMPLUS ) - { - m_fixDist -= event.rTime*30.0f*m_speed; - if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; - } - if ( event.keyState & KS_NUMMINUS ) - { - m_fixDist += event.rTime*30.0f*m_speed; - if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; - } - - if ( m_bCameraScroll ) - { - // Left/Right. - m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; - m_fixDirectionH = Math::NormAngle(m_fixDirectionH); - - // Up/Down. -//? m_fixDist -= m_mouseDirV*event.rTime*30.0f*m_speed; -//? if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; -//? if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; - } - - if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) - { - AbortCentering(); // special stops framing - } - - if ( m_cameraObj != 0 ) - { - vLookatPt = m_cameraObj->RetPosition(0); - - h = m_fixDirectionH+m_remotePan; - v = m_fixDirectionV; - - d = m_fixDist; -//- if ( m_type == CAMERA_PLANE ) d += 20.0f; - m_eyePt = RotateView(vLookatPt, h, v, d); -//- if ( m_type == CAMERA_PLANE ) m_eyePt.y += 50.0f; - if ( m_type == CAMERA_PLANE ) m_eyePt.y += m_fixDist/2.0f; - m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); - m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); - - SetViewTime(m_eyePt, vLookatPt, event.rTime); - - m_directionH = h+Math::PI/2.0f; - m_directionV = v; - } - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameExplo(const Event &event) -{ - Math::Vector pos, vLookatPt; - float factor; - - factor = m_heightEye*0.5f+30.0f; - - if ( m_mouseDirH != 0.0f ) - { - m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; - } - - m_terrain->ValidPosition(m_eyePt, 10.0f); - - if ( m_terrain->MoveOnFloor(m_eyePt, false) ) - { - m_eyePt.y += m_heightEye; - - pos = m_eyePt; - if ( m_terrain->MoveOnFloor(pos, false) ) - { - pos.y += 2.0f; - if ( m_eyePt.y < pos.y ) - { - m_eyePt.y = pos.y; - } - } - - } - - vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); - - if ( m_terrain->MoveOnFloor(vLookatPt, true) ) - { - vLookatPt.y += m_heightLookat; - } - - SetViewTime(m_eyePt, vLookatPt, event.rTime); - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameOnBoard(const Event &event) -{ - Math::Vector vLookatPt, vUpVec, eye, lookat, pos; - - if ( m_cameraObj != 0 ) - { - m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV, - vLookatPt, vUpVec, m_type); - eye = m_effectOffset*0.3f+m_eyePt; - lookat = m_effectOffset*0.3f+vLookatPt; - - SetViewParams(eye, lookat, vUpVec); - m_actualEye = eye; - m_actualLookat = lookat; - } - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameInfo(const Event &event) -{ - SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f), - Math::Vector(0.0f, 0.0f, 1.0f), - event.rTime); - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameVisit(const Event &event) -{ - Math::Vector eye; - float angleH, angleV; - - m_visitTime += event.rTime; - - // +/-. - if ( event.keyState & KS_NUMPLUS ) - { - m_visitDist -= event.rTime*50.0f*m_speed; - if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; - } - if ( event.keyState & KS_NUMMINUS ) - { - m_visitDist += event.rTime*50.0f*m_speed; - if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; - } - - // PageUp/Down. - if ( event.keyState & KS_PAGEUP ) - { - m_visitDirectionV -= event.rTime*1.0f*m_speed; - if ( m_visitDirectionV < -Math::PI*0.40f ) m_visitDirectionV = -Math::PI*0.40f; - } - if ( event.keyState & KS_PAGEDOWN ) - { - m_visitDirectionV += event.rTime*1.0f*m_speed; - if ( m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f; - } - - if ( m_bCameraScroll ) - { - m_visitDist -= m_mouseDirV*event.rTime*30.0f*m_speed; - if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; - if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; - } - - angleH = (m_visitTime/10.0f)*(Math::PI*2.0f); - angleV = m_visitDirectionV; - eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist); - eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV); - eye = ExcludeObject(eye, m_visitGoal, angleH, angleV); - SetViewTime(eye, m_visitGoal, event.rTime); - - return true; -} - -// Moves the point of view. - -bool CCamera::EventFrameScript(const Event &event) -{ - SetViewTime(m_scriptEye+m_effectOffset, - m_scriptLookat+m_effectOffset, event.rTime); - return true; -} - -void CCamera::SetScriptEye(Math::Vector eye) -{ - m_scriptEye = eye; -} - -void CCamera::SetScriptLookat(Math::Vector lookat) -{ - m_scriptLookat = lookat; -} - - -// Specifies the location and direction of view. - -void CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, - const Math::Vector &up) -{ - bool bUnder; - - m_engine->SetViewParams(eye, lookat, up, m_eyeDistance); - - bUnder = (eye.y < m_water->RetLevel()); // Is it underwater? - if ( m_type == CAMERA_INFO ) bUnder = false; - m_engine->SetRankView(bUnder?1:0); -} - - -// Adjusts the camera not to enter the field. - -Math::Vector CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat, - float &angleH, float &angleV) -{ - Math::Vector pos; - float dist; - - pos = eye; - if ( m_terrain->MoveOnFloor(pos) ) - { - dist = Math::DistanceProjected(lookat, pos); - pos.y += 2.0f+dist*0.1f; - if ( pos.y > eye.y ) - { - angleV = -Math::RotateAngle(dist, pos.y-lookat.y); - eye = RotateView(lookat, angleH, angleV, dist); - } - } - return eye; -} - -// Adjusts the camera not to enter an object. - -Math::Vector CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat, - float &angleH, float &angleV) -{ - CObject* pObj; - Math::Vector oPos; - float oRad, dist; - int i, j; - -return eye; -//? - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - j = 0; - while ( pObj->GetCrashSphere(j++, oPos, oRad) ) - { - dist = Math::Distance(oPos, eye); - if ( dist < oRad+2.0f ) - { - eye.y = oPos.y+oRad+2.0f; - } - } - } - - return eye; -} - - +// * 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/. + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "common/language.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/terrain.h" +#include "old/water.h" +#include "object/object.h" +#include "physics/physics.h" +#include "old/camera.h" + + + + +// Object's constructor. + +CCamera::CCamera(CInstanceManager* iMan) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_CAMERA, this); + + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); + + m_type = CAMERA_FREE; + m_smooth = CS_NORM; + m_cameraObj = 0; + + m_eyeDistance = 10.0f; + m_initDelay = 0.0f; + + m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_normEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f); + m_focus = 1.0f; + + m_bRightDown = false; + m_rightPosInit = Math::Point(0.5f, 0.5f); + m_rightPosCenter = Math::Point(0.5f, 0.5f); + m_rightPosMove = Math::Point(0.5f, 0.5f); + + m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); + m_directionH = 0.0f; + m_directionV = 0.0f; + m_heightEye = 20.0f; + m_heightLookat = 0.0f; + m_speed = 2.0f; + + m_backDist = 0.0f; + m_backMin = 0.0f; + m_addDirectionH = 0.0f; + m_addDirectionV = 0.0f; + m_bTransparency = false; + + m_fixDist = 0.0f; + m_fixDirectionH = 0.0f; + m_fixDirectionV = 0.0f; + + m_visitGoal = Math::Vector(0.0f, 0.0f, 0.0f); + m_visitDist = 0.0f; + m_visitTime = 0.0f; + m_visitType = CAMERA_NULL; + m_visitDirectionH = 0.0f; + m_visitDirectionV = 0.0f; + + m_editHeight = 40.0f; + + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + m_mouseDirH = 0.0f; + m_mouseDirV = 0.0f; + m_mouseMarging = 0.01f; + + m_motorTurn = 0.0f; + + m_centeringPhase = CP_NULL; + m_centeringAngleH = 0.0f; + m_centeringAngleV = 0.0f; + m_centeringDist = 0.0f; + m_centeringCurrentH = 0.0f; + m_centeringCurrentV = 0.0f; + m_centeringTime = 0.0f; + m_centeringProgress = 0.0f; + + m_effectType = CE_NULL; + m_effectPos = Math::Vector(0.0f, 0.0f, 0.0f); + m_effectForce = 0.0f; + m_effectProgress = 0.0f; + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); + + m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f); + m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f); + + m_bEffect = true; + m_bCameraScroll = true; + m_bCameraInvertX = false; + m_bCameraInvertY = false; +} + +// Object's constructor. + +CCamera::~CCamera() +{ +} + + +void CCamera::SetEffect(bool bEnable) +{ + m_bEffect = bEnable; +} + +void CCamera::SetCameraScroll(bool bScroll) +{ + m_bCameraScroll = bScroll; +} + +void CCamera::SetCameraInvertX(bool bInvert) +{ + m_bCameraInvertX = bInvert; +} + +void CCamera::SetCameraInvertY(bool bInvert) +{ + m_bCameraInvertY = bInvert; +} + + +// Returns an additional force to turn. + +float CCamera::RetMotorTurn() +{ + if ( m_type == CAMERA_BACK ) return m_motorTurn; + return 0.0f; +} + + + +// Initializes the camera. + +void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) +{ + Math::Vector vUpVec; + + m_initDelay = delay; + + eye.y += m_terrain->RetFloorLevel(eye, true); + lookat.y += m_terrain->RetFloorLevel(lookat, true); + + m_type = CAMERA_FREE; + m_eyePt = eye; + + m_directionH = Math::RotateAngle(eye.x-lookat.x, eye.z-lookat.z)+Math::PI/2.0f; + m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y-lookat.y); + + m_eyeDistance = 10.0f; + m_heightLookat = 10.0f; + m_backDist = 30.0f; + m_backMin = 10.0f; + m_addDirectionH = 0.0f; + m_addDirectionV = -Math::PI*0.05f; + m_fixDist = 50.0f; + m_fixDirectionH = Math::PI*0.25f; + m_fixDirectionV = -Math::PI*0.10f; + m_centeringPhase = CP_NULL; + m_actualEye = m_eyePt; + m_actualLookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); + m_finalEye = m_actualEye; + m_finalLookat = m_actualLookat; + m_scriptEye = m_actualEye; + m_scriptLookat = m_actualLookat; + m_focus = 1.00f; + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + FlushEffect(); + FlushOver(); + SetType(CAMERA_FREE); +} + + +// Gives the object controlling the camera. + +void CCamera::SetObject(CObject* object) +{ + m_cameraObj = object; +} + +CObject* CCamera::RetObject() +{ + return m_cameraObj; +} + + +// Changes the level of transparency of an object and objects +// transported (battery & cargo). + +void SetTransparency(CObject* pObj, float value) +{ + CObject* pFret; + + pObj->SetTransparency(value); + + pFret = pObj->RetFret(); + if ( pFret != 0 ) + { + pFret->SetTransparency(value); + } + + pFret = pObj->RetPower(); + if ( pFret != 0 ) + { + pFret->SetTransparency(value); + } +} + +// Change the type of camera. + +void CCamera::SetType(CameraType type) +{ + CObject* pObj; + ObjectType oType; + Math::Vector vUpVec; + int i; + + m_remotePan = 0.0f; + m_remoteZoom = 0.0f; + + if ( m_type == CAMERA_BACK && m_bTransparency ) + { + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj->RetTruck() ) continue; // battery or cargo? + + SetTransparency(pObj, 0.0f); // opaque object + } + } + m_bTransparency = false; + + if ( type == CAMERA_INFO || + type == CAMERA_VISIT ) // xx -> info ? + { + m_normEye = m_engine->RetEyePt(); + m_normLookat = m_engine->RetLookatPt(); + + m_engine->SetFocus(1.00f); // normal + m_type = type; + return; + } + + if ( m_type == CAMERA_INFO || + m_type == CAMERA_VISIT ) // info -> xx ? + { + m_engine->SetFocus(m_focus); // gives initial focus + m_type = type; + + vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); + SetViewParams(m_normEye, m_normLookat, vUpVec); + return; + } + + if ( m_type == CAMERA_BACK && type == CAMERA_FREE ) // back -> free ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + } + + if ( m_type == CAMERA_BACK && type == CAMERA_EDIT ) // back -> edit ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_FREE ) // onboard -> free ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_EDIT ) // onboard -> edit ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_EXPLO ) // onboard -> explo ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + } + + if ( m_type == CAMERA_BACK && type == CAMERA_EXPLO ) // back -> explo ? + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f); + } + + if ( type == CAMERA_FIX || + type == CAMERA_PLANE ) + { + AbortCentering(); // Special stops framing + } + + m_fixDist = 50.0f; + if ( type == CAMERA_PLANE ) + { + m_fixDist = 60.0f; + } + + if ( type == CAMERA_BACK ) + { + AbortCentering(); // Special stops framing + m_addDirectionH = 0.0f; + m_addDirectionV = -Math::PI*0.05f; + + if ( m_cameraObj == 0 ) oType = OBJECT_NULL; + else oType = m_cameraObj->RetType(); + + m_backDist = 30.0f; + if ( oType == OBJECT_BASE ) m_backDist = 200.0f; + if ( oType == OBJECT_HUMAN ) m_backDist = 20.0f; + if ( oType == OBJECT_TECH ) m_backDist = 20.0f; + if ( oType == OBJECT_FACTORY ) m_backDist = 50.0f; + if ( oType == OBJECT_RESEARCH ) m_backDist = 40.0f; + if ( oType == OBJECT_DERRICK ) m_backDist = 40.0f; + if ( oType == OBJECT_REPAIR ) m_backDist = 35.0f; + if ( oType == OBJECT_DESTROYER) m_backDist = 35.0f; + if ( oType == OBJECT_TOWER ) m_backDist = 45.0f; + if ( oType == OBJECT_NUCLEAR ) m_backDist = 70.0f; + if ( oType == OBJECT_PARA ) m_backDist = 180.0f; + if ( oType == OBJECT_SAFE ) m_backDist = 50.0f; + if ( oType == OBJECT_HUSTON ) m_backDist = 120.0f; + + m_backMin = m_backDist/3.0f; + if ( oType == OBJECT_HUMAN ) m_backMin = 10.0f; + if ( oType == OBJECT_TECH ) m_backMin = 10.0f; + if ( oType == OBJECT_FACTORY ) m_backMin = 30.0f; + if ( oType == OBJECT_RESEARCH ) m_backMin = 20.0f; + if ( oType == OBJECT_NUCLEAR ) m_backMin = 32.0f; + if ( oType == OBJECT_PARA ) m_backMin = 40.0f; + if ( oType == OBJECT_SAFE ) m_backMin = 25.0f; + if ( oType == OBJECT_HUSTON ) m_backMin = 80.0f; + } + + if ( type != CAMERA_ONBOARD && m_cameraObj != 0 ) + { + m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right + } + + if ( type == CAMERA_ONBOARD ) + { + m_focus = 1.50f; // Wide + } + else + { + m_focus = 1.00f; // normal + } + m_engine->SetFocus(m_focus); + + m_type = type; + + SetSmooth(CS_NORM); +} + +CameraType CCamera::RetType() +{ + return m_type; +} + + +// Management of the smoothing mode. + +void CCamera::SetSmooth(CameraSmooth type) +{ + m_smooth = type; +} + +CameraSmooth CCamera::RetSmoth() +{ + return m_smooth; +} + + +// Management of the setback distance. + +void CCamera::SetDist(float dist) +{ + m_fixDist = dist; +} + +float CCamera::RetDist() +{ + return m_fixDist; +} + + +// Manage angle mode CAMERA_FIX. + +void CCamera::SetFixDirection(float angle) +{ + m_fixDirectionH = angle; +} + +float CCamera::RetFixDirection() +{ + return m_fixDirectionH; +} + + +// Managing the triggering mode of the camera panning. + +void CCamera::SetRemotePan(float value) +{ + m_remotePan = value; +} + +float CCamera::RetRemotePan() +{ + return m_remotePan; +} + +// Management of the remote zoom (0 .. 1) of the camera. + +void CCamera::SetRemoteZoom(float value) +{ + value = Math::Norm(value); + + if ( m_type == CAMERA_BACK ) + { + m_backDist = m_backMin+(200.0f-m_backMin)*value; + } + + if ( m_type == CAMERA_FIX || + m_type == CAMERA_PLANE ) + { + m_fixDist = 10.0f+(200.0f-10.0f)*value; + } +} + +float CCamera::RetRemoteZoom() +{ + if ( m_type == CAMERA_BACK ) + { + return (m_backDist-m_backMin)/(200.0f-m_backMin); + } + + if ( m_type == CAMERA_FIX || + m_type == CAMERA_PLANE ) + { + return (m_fixDist-10.0f)/(200.0f-10.0f); + } + return 0.0f; +} + + + +// Start with a tour round the camera. + +void CCamera::StartVisit(Math::Vector goal, float dist) +{ + m_visitType = m_type; + SetType(CAMERA_VISIT); + m_visitGoal = goal; + m_visitDist = dist; + m_visitTime = 0.0f; + m_visitDirectionH = 0.0f; + m_visitDirectionV = -Math::PI*0.10f; +} + +// Circular end of a visit with the camera. + +void CCamera::StopVisit() +{ + SetType(m_visitType); // presents the initial type +} + + +// Returns the point of view of the camera. + +void CCamera::RetCamera(Math::Vector &eye, Math::Vector &lookat) +{ + eye = m_eyePt; + lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); +} + + +// Specifies a special movement of camera to frame action. + +bool CCamera::StartCentering(CObject *object, float angleH, float angleV, + float dist, float time) +{ + if ( m_type != CAMERA_BACK ) return false; + if ( object != m_cameraObj ) return false; + + if ( m_centeringPhase != CP_NULL ) return false; + + if ( m_addDirectionH > Math::PI ) + { + angleH = Math::PI*2.0f-angleH; + } + + m_centeringPhase = CP_START; + m_centeringAngleH = angleH; + m_centeringAngleV = angleV; + m_centeringDist = dist; + m_centeringCurrentH = 0.0f; + m_centeringCurrentV = 0.0f; + m_centeringTime = time; + m_centeringProgress = 0.0f; + + return true; +} + +// Ends a special movement of camera to frame action. + +bool CCamera::StopCentering(CObject *object, float time) +{ + if ( m_type != CAMERA_BACK ) return false; + if ( object != m_cameraObj ) return false; + + if ( m_centeringPhase != CP_START && + m_centeringPhase != CP_WAIT ) return false; + + m_centeringPhase = CP_STOP; + + if ( m_centeringAngleH != 99.9f ) + { + m_centeringAngleH = m_centeringCurrentH; + } + if ( m_centeringAngleV != 99.9f ) + { + m_centeringAngleV = m_centeringCurrentV; + } + + m_centeringTime = time; + m_centeringProgress = 0.0f; + + return true; +} + +// Stop framing special in the current position. + +void CCamera::AbortCentering() +{ + if ( m_type == CAMERA_INFO || + m_type == CAMERA_VISIT ) return; + + if ( m_centeringPhase == CP_NULL ) return; + + m_centeringPhase = CP_NULL; + + if ( m_centeringAngleH != 99.9f ) + { + m_addDirectionH = m_centeringCurrentH; + } + if ( m_centeringAngleV != 99.9f ) + { + m_addDirectionV = m_centeringCurrentV; + } +} + + + +// Removes the special effect with the camera + +void CCamera::FlushEffect() +{ + m_effectType = CE_NULL; + m_effectForce = 0.0f; + m_effectProgress = 0.0f; + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); +} + +// Starts a special effect with the camera. + +void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) +{ + if ( !m_bEffect ) return; + + m_effectType = effect; + m_effectPos = pos; + m_effectForce = force; + m_effectProgress = 0.0f; +} + +// Advances the effect of the camera. + +void CCamera::EffectFrame(const Event &event) +{ + float dist, force; + + if ( m_type == CAMERA_INFO || + m_type == CAMERA_VISIT ) return; + + if ( m_effectType == CE_NULL ) return; + + m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); + force = m_effectForce; + + if ( m_effectType == CE_TERRAFORM ) + { + m_effectProgress += event.rTime*0.7f; + m_effectOffset.x = (Math::Rand()-0.5f)*10.0f; + m_effectOffset.y = (Math::Rand()-0.5f)*10.0f; + m_effectOffset.z = (Math::Rand()-0.5f)*10.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == CE_EXPLO ) + { + m_effectProgress += event.rTime*1.0f; + m_effectOffset.x = (Math::Rand()-0.5f)*5.0f; + m_effectOffset.y = (Math::Rand()-0.5f)*5.0f; + m_effectOffset.z = (Math::Rand()-0.5f)*5.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == CE_SHOT ) + { + m_effectProgress += event.rTime*1.0f; + m_effectOffset.x = (Math::Rand()-0.5f)*2.0f; + m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; + m_effectOffset.z = (Math::Rand()-0.5f)*2.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == CE_CRASH ) + { + m_effectProgress += event.rTime*5.0f; + m_effectOffset.y = sinf(m_effectProgress*Math::PI)*1.5f; + m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + } + + if ( m_effectType == CE_VIBRATION ) + { + m_effectProgress += event.rTime*0.1f; + m_effectOffset.y = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + } + + if ( m_effectType == CE_PET ) + { + m_effectProgress += event.rTime*5.0f; + m_effectOffset.x = (Math::Rand()-0.5f)*0.2f; + m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; + m_effectOffset.z = (Math::Rand()-0.5f)*0.2f; + } + + dist = Math::Distance(m_eyePt, m_effectPos); + dist = Math::Norm((dist-100.f)/100.0f); + + force *= 1.0f-dist; +#if _TEEN + force *= 2.0f; +#endif + m_effectOffset *= force; + + if ( m_effectProgress >= 1.0f ) + { + FlushEffect(); + } +} + + +// Removes the effect of superposition in the foreground. + +void CCamera::FlushOver() +{ + m_overType = OE_NULL; + m_overColorBase.r = 0.0f; // black + m_overColorBase.g = 0.0f; + m_overColorBase.b = 0.0f; + m_overColorBase.a = 0.0f; + m_engine->SetOverColor(); // nothing +} + +// Specifies the base color. + +void CCamera::SetOverBaseColor(D3DCOLORVALUE color) +{ + m_overColorBase = color; +} + +// Starts a layering effect in the foreground. + +void CCamera::StartOver(OverEffect effect, Math::Vector pos, float force) +{ + D3DCOLOR color; + float dist, decay; + + m_overType = effect; + m_overTime = 0.0f; + + if ( m_overType == OE_BLITZ ) decay = 400.0f; + else decay = 100.0f; + dist = Math::Distance(m_eyePt, pos); + dist = (dist-decay)/decay; + if ( dist < 0.0f ) dist = 0.0f; + if ( dist > 1.0f ) dist = 1.0f; + + m_overForce = force * (1.0f-dist); + + if ( m_overType == OE_BLOOD ) + { + m_overColor.r = 0.8f; + m_overColor.g = 0.1f; + m_overColor.b = 0.1f; // red + m_overMode = D3DSTATETCb; + + m_overFadeIn = 0.4f; + m_overFadeOut = 0.8f; + m_overForce = 1.0f; + } + + if ( m_overType == OE_FADEINw ) + { + m_overColor.r = 1.0f; + m_overColor.g = 1.0f; + m_overColor.b = 1.0f; // white + m_overMode = D3DSTATETCb; + + m_overFadeIn = 0.0f; + m_overFadeOut =20.0f; + m_overForce = 1.0f; + } + + if ( m_overType == OE_FADEOUTw ) + { + m_overColor.r = 1.0f; + m_overColor.g = 1.0f; + m_overColor.b = 1.0f; // white + m_overMode = D3DSTATETCb; + + m_overFadeIn = 6.0f; + m_overFadeOut = 100000.0f; + m_overForce = 1.0f; + } + + if ( m_overType == OE_FADEOUTb ) + { + color = m_engine->RetFogColor(1); // fog color underwater + m_overColor = RetColor(color); + m_overMode = D3DSTATETCw; + + m_overFadeIn = 4.0f; + m_overFadeOut = 100000.0f; + m_overForce = 1.0f; + } + + if ( m_overType == OE_BLITZ ) + { + m_overColor.r = 0.9f; + m_overColor.g = 1.0f; + m_overColor.b = 1.0f; // white-cyan + m_overMode = D3DSTATETCb; + + m_overFadeIn = 0.0f; + m_overFadeOut = 1.0f; + } +} + +// Advanced overlay effect in the foreground. + +void CCamera::OverFrame(const Event &event) +{ + D3DCOLORVALUE color; + float intensity; + + if ( m_type == CAMERA_INFO || + m_type == CAMERA_VISIT ) return; + + if ( m_overType == OE_NULL ) + { + return; + } + + m_overTime += event.rTime; + + if ( m_overType == OE_BLITZ ) + { + if ( rand()%2 == 0 ) + { + color.r = m_overColor.r*m_overForce; + color.g = m_overColor.g*m_overForce; + color.b = m_overColor.b*m_overForce; + } + else + { + color.r = 0.0f; + color.g = 0.0f; + color.b = 0.0f; + } + color.a = 0.0f; + m_engine->SetOverColor(RetColor(color), m_overMode); + } + else + { + if ( m_overFadeIn > 0.0f && m_overTime < m_overFadeIn ) + { + intensity = m_overTime/m_overFadeIn; + intensity *= m_overForce; + + if ( m_overMode == D3DSTATETCw ) + { + color.r = 1.0f-(1.0f-m_overColor.r)*intensity; + color.g = 1.0f-(1.0f-m_overColor.g)*intensity; + color.b = 1.0f-(1.0f-m_overColor.b)*intensity; + } + else + { + color.r = m_overColor.r*intensity; + color.g = m_overColor.g*intensity; + color.b = m_overColor.b*intensity; + + color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); + color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); + color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); + } + color.a = 0.0f; + m_engine->SetOverColor(RetColor(color), m_overMode); + } + else if ( m_overFadeOut > 0.0f && m_overTime-m_overFadeIn < m_overFadeOut ) + { + intensity = 1.0f-(m_overTime-m_overFadeIn)/m_overFadeOut; + intensity *= m_overForce; + + if ( m_overMode == D3DSTATETCw ) + { + color.r = 1.0f-(1.0f-m_overColor.r)*intensity; + color.g = 1.0f-(1.0f-m_overColor.g)*intensity; + color.b = 1.0f-(1.0f-m_overColor.b)*intensity; + } + else + { + color.r = m_overColor.r*intensity; + color.g = m_overColor.g*intensity; + color.b = m_overColor.b*intensity; + + color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); + color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); + color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); + } + color.a = 0.0f; + m_engine->SetOverColor(RetColor(color), m_overMode); + } + } + + if ( m_overTime >= m_overFadeIn+m_overFadeOut ) + { + FlushOver(); + return; + } +} + + + +// Sets the soft movement of the camera. + +void CCamera::FixCamera() +{ + m_initDelay = 0.0f; + m_actualEye = m_finalEye = m_scriptEye; + m_actualLookat = m_finalLookat = m_scriptLookat; + SetViewTime(m_scriptEye, m_scriptLookat, 0.0f); +} + +// Specifies the location and direction of view to the 3D engine. + +void CCamera::SetViewTime(const Math::Vector &vEyePt, + const Math::Vector &vLookatPt, + float rTime) +{ + Math::Vector vUpVec, eye, lookat; + float prog, dist, h; + + if ( m_type == CAMERA_INFO ) + { + eye = vEyePt; + lookat = vLookatPt; + } + else + { + if ( m_initDelay > 0.0f ) + { + m_initDelay -= rTime; + if ( m_initDelay < 0.0f ) m_initDelay = 0.0f; + rTime /= 1.0f+m_initDelay; + } + + eye = vEyePt; + lookat = vLookatPt; + if ( !IsCollision(eye, lookat) ) + { + m_finalEye = eye; + m_finalLookat = lookat; + } + + dist = Math::Distance(m_finalEye, m_actualEye); + if ( m_smooth == CS_NONE ) prog = dist; + if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*0.5f; + if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; + if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*0.05f; + if ( dist == 0.0f ) + { + m_actualEye = m_finalEye; + } + else + { + if ( prog > dist ) prog = dist; + m_actualEye = (m_finalEye-m_actualEye)/dist*prog + m_actualEye; + } + + dist = Math::Distance(m_finalLookat, m_actualLookat); + if ( m_smooth == CS_NONE ) prog = dist; + if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*2.0f; + if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; + if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*4.0f; + if ( dist == 0.0f ) + { + m_actualLookat = m_finalLookat; + } + else + { + if ( prog > dist ) prog = dist; + m_actualLookat = (m_finalLookat-m_actualLookat)/dist*prog + m_actualLookat; + } + + eye = m_effectOffset+m_actualEye; + m_water->AdjustEye(eye); + + h = m_terrain->RetFloorLevel(eye); + if ( eye.y < h+4.0f ) + { + eye.y = h+4.0f; + } + + lookat = m_effectOffset+m_actualLookat; + } + + vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); + SetViewParams(eye, lookat, vUpVec); +} + + +// Avoid the obstacles. + +bool CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) +{ + if ( m_type == CAMERA_BACK ) return IsCollisionBack(eye, lookat); + if ( m_type == CAMERA_FIX ) return IsCollisionFix(eye, lookat); + if ( m_type == CAMERA_PLANE ) return IsCollisionFix(eye, lookat); + return false; +} + +// Avoid the obstacles. + +bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) +{ +#if 0 + CObject *pObj; + Math::Vector oPos, min, max, proj; + ObjectType oType, iType; + float oRadius, dpp, dpl, del, dist, len, prox; + int i; + + if ( m_cameraObj == 0 ) + { + iType = OBJECT_NULL; + } + else + { + iType = m_cameraObj->RetType(); + } + + min.x = Math::Min(eye.x, lookat.x); + min.y = Math::Min(eye.y, lookat.y); + min.z = Math::Min(eye.z, lookat.z); + + max.x = Math::Max(eye.x, lookat.x); + max.y = Math::Max(eye.y, lookat.y); + max.z = Math::Max(eye.z, lookat.z); + + prox = 8.0f; // maximum proximity of the vehicle + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_cameraObj ) continue; + + oType = pObj->RetType(); + if ( oType == OBJECT_TOTO || + oType == OBJECT_FIX || + oType == OBJECT_FRET || + oType == OBJECT_STONE || + oType == OBJECT_URANIUM || + oType == OBJECT_METAL || + oType == OBJECT_POWER || + oType == OBJECT_ATOMIC || + oType == OBJECT_BULLET || + oType == OBJECT_BBOX || + oType == OBJECT_TNT || + oType == OBJECT_BOMB || + oType == OBJECT_WAYPOINTb || + oType == OBJECT_WAYPOINTr || + oType == OBJECT_WAYPOINTg || + oType == OBJECT_WAYPOINTy || + oType == OBJECT_WAYPOINTv || + oType == OBJECT_FLAGb || + oType == OBJECT_FLAGr || + oType == OBJECT_FLAGg || + oType == OBJECT_FLAGy || + oType == OBJECT_FLAGv || + oType == OBJECT_ANT || + oType == OBJECT_SPIDER || + oType == OBJECT_BEE || + oType == OBJECT_WORM ) continue; + + pObj->GetGlobalSphere(oPos, oRadius); + if ( oRadius <= 0.0f ) continue; + + if ( oPos.x+oRadius < min.x || + oPos.y+oRadius < min.y || + oPos.z+oRadius < min.z || + oPos.x-oRadius > max.x || + oPos.y-oRadius > max.y || + oPos.z-oRadius > max.z ) continue; + + if ( iType == OBJECT_FACTORY ) + { + dpl = Math::Distance(oPos, lookat); + if ( dpl < oRadius ) continue; + } + + proj = Projection(eye, lookat, oPos); + dpp = Math::Distance(proj, oPos); + if ( dpp > oRadius ) continue; + + del = Math::Distance(eye, lookat); + len = Math::Distance(eye, proj); + if ( len > del ) continue; + + dist = sqrtf(oRadius*oRadius + dpp*dpp)-3.0f; + if ( dist < 0.0f ) dist = 0.0f; + proj = (lookat-eye)*dist/del + proj; + len = Math::Distance(eye, proj); + + if ( len < del-prox ) + { + eye = proj; + eye.y += len/5.0f; + return false; + } + else + { + eye = (eye-lookat)*prox/del + lookat; + eye.y += (del-prox)/5.0f; + return false; + } + } + return false; +#else + CObject *pObj; + Math::Vector oPos, min, max, proj; + ObjectType oType, iType; + float oRadius, dpp, del, len, angle; + int i; + + if ( m_cameraObj == 0 ) + { + iType = OBJECT_NULL; + } + else + { + iType = m_cameraObj->RetType(); + } + + min.x = Math::Min(m_actualEye.x, m_actualLookat.x); + min.y = Math::Min(m_actualEye.y, m_actualLookat.y); + min.z = Math::Min(m_actualEye.z, m_actualLookat.z); + + max.x = Math::Max(m_actualEye.x, m_actualLookat.x); + max.y = Math::Max(m_actualEye.y, m_actualLookat.y); + max.z = Math::Max(m_actualEye.z, m_actualLookat.z); + + m_bTransparency = false; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj->RetTruck() ) continue; // battery or cargo? + + SetTransparency(pObj, 0.0f); // opaque object + + if ( pObj == m_cameraObj ) continue; + + if ( iType == OBJECT_BASE || // building? + iType == OBJECT_DERRICK || + iType == OBJECT_FACTORY || + iType == OBJECT_STATION || + iType == OBJECT_CONVERT || + iType == OBJECT_REPAIR || + iType == OBJECT_DESTROYER|| + iType == OBJECT_TOWER || + iType == OBJECT_RESEARCH || + iType == OBJECT_RADAR || + iType == OBJECT_ENERGY || + iType == OBJECT_LABO || + iType == OBJECT_NUCLEAR || + iType == OBJECT_PARA || + iType == OBJECT_SAFE || + iType == OBJECT_HUSTON ) continue; + + oType = pObj->RetType(); + if ( oType == OBJECT_HUMAN || + oType == OBJECT_TECH || + oType == OBJECT_TOTO || + oType == OBJECT_FIX || + oType == OBJECT_FRET || + oType == OBJECT_ANT || + oType == OBJECT_SPIDER || + oType == OBJECT_BEE || + oType == OBJECT_WORM ) continue; + + pObj->GetGlobalSphere(oPos, oRadius); + if ( oRadius <= 2.0f ) continue; // ignores small objects + + if ( oPos.x+oRadius < min.x || + oPos.y+oRadius < min.y || + oPos.z+oRadius < min.z || + oPos.x-oRadius > max.x || + oPos.y-oRadius > max.y || + oPos.z-oRadius > max.z ) continue; + + proj = Projection(m_actualEye, m_actualLookat, oPos); + dpp = Math::Distance(proj, oPos); + if ( dpp > oRadius ) continue; + + if ( oType == OBJECT_FACTORY ) + { + angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW ! + angle = Math::Direction(angle, pObj->RetAngleY(0)); + if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate? + } + + del = Math::Distance(m_actualEye, m_actualLookat); + if ( oType == OBJECT_FACTORY ) + { + del += oRadius; + } + + len = Math::Distance(m_actualEye, proj); + if ( len > del ) continue; + + SetTransparency(pObj, 1.0f); // transparent object + m_bTransparency = true; + } + return false; +#endif +} + +// Avoid the obstacles. + +bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) +{ + CObject *pObj; + Math::Vector oPos, proj; + ObjectType type; + float oRadius, dist; + int i; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( pObj == m_cameraObj ) continue; + + type = pObj->RetType(); + if ( type == OBJECT_TOTO || + type == OBJECT_FRET || + type == OBJECT_STONE || + type == OBJECT_URANIUM || + type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC || + type == OBJECT_BULLET || + type == OBJECT_BBOX || + type == OBJECT_KEYa || + type == OBJECT_KEYb || + type == OBJECT_KEYc || + type == OBJECT_KEYd || + type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM ) continue; + + pObj->GetGlobalSphere(oPos, oRadius); + if ( oRadius == 0.0f ) continue; + + dist = Math::Distance(eye, oPos); + if ( dist < oRadius ) + { + dist = Math::Distance(eye, lookat); + proj = Projection(eye, lookat, oPos); + eye = (lookat-eye)*oRadius/dist + proj; + return false; + } + } + return false; +} + + +// Management of an event. + +bool CCamera::EventProcess(const Event &event) +{ + switch( event.event ) + { + case EVENT_FRAME: + EventFrame(event); + break; + +#if 0 + case EVENT_RBUTTONDOWN: + m_bRightDown = true; + m_rightPosInit = event.pos; + m_rightPosCenter = Math::Point(0.5f, 0.5f); + m_engine->MoveMousePos(m_rightPosCenter); +//? m_engine->SetMouseHide(true); // cache la souris + break; + + case EVENT_RBUTTONUP: + m_bRightDown = false; + m_engine->MoveMousePos(m_rightPosInit); +//? m_engine->SetMouseHide(false); // remontre la souris + m_addDirectionH = 0.0f; + m_addDirectionV = -Math::PI*0.05f; + break; +#endif + + case EVENT_MOUSEMOVE: + EventMouseMove(event); + break; + + case EVENT_KEYDOWN: + if ( event.param == VK_WHEELUP ) EventMouseWheel(+1); + if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1); + break; + } + return true; +} + +// Changed the camera according to the mouse moved. + +bool CCamera::EventMouseMove(const Event &event) +{ + m_mousePos = event.pos; + return true; +} + +// Mouse wheel operated. + +void CCamera::EventMouseWheel(int dir) +{ + if ( m_type == CAMERA_BACK ) + { + if ( dir > 0 ) + { + m_backDist -= 8.0f; + if ( m_backDist < m_backMin ) m_backDist = m_backMin; + } + if ( dir < 0 ) + { + m_backDist += 8.0f; + if ( m_backDist > 200.0f ) m_backDist = 200.0f; + } + } + + if ( m_type == CAMERA_FIX || + m_type == CAMERA_PLANE ) + { + if ( dir > 0 ) + { + m_fixDist -= 8.0f; + if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; + } + if ( dir < 0 ) + { + m_fixDist += 8.0f; + if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; + } + } + + if ( m_type == CAMERA_VISIT ) + { + if ( dir > 0 ) + { + m_visitDist -= 8.0f; + if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; + } + if ( dir < 0 ) + { + m_visitDist += 8.0f; + if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; + } + } +} + +// Changed the camera according to the time elapsed. + +bool CCamera::EventFrame(const Event &event) +{ + EffectFrame(event); + OverFrame(event); + + if ( m_type == CAMERA_FREE ) + { + return EventFrameFree(event); + } + if ( m_type == CAMERA_EDIT ) + { + return EventFrameEdit(event); + } + if ( m_type == CAMERA_DIALOG ) + { + return EventFrameDialog(event); + } + if ( m_type == CAMERA_BACK ) + { + return EventFrameBack(event); + } + if ( m_type == CAMERA_FIX || + m_type == CAMERA_PLANE ) + { + return EventFrameFix(event); + } + if ( m_type == CAMERA_EXPLO ) + { + return EventFrameExplo(event); + } + if ( m_type == CAMERA_ONBOARD ) + { + return EventFrameOnBoard(event); + } + if ( m_type == CAMERA_SCRIPT ) + { + return EventFrameScript(event); + } + if ( m_type == CAMERA_INFO ) + { + return EventFrameInfo(event); + } + if ( m_type == CAMERA_VISIT ) + { + return EventFrameVisit(event); + } + + return true; +} + + +// Returns the default sprite to use for the mouse. + +D3DMouse CCamera::RetMouseDef(Math::Point pos) +{ + D3DMouse type; + + type = D3DMOUSENORM; + m_mousePos = pos; + + if ( m_type == CAMERA_INFO ) return type; + + if ( m_bRightDown ) // the right button pressed? + { + m_rightPosMove.x = pos.x - m_rightPosCenter.x; + m_rightPosMove.y = pos.y - m_rightPosCenter.y; + type = D3DMOUSEMOVE; + } + else + { + if ( !m_bCameraScroll ) return type; + + m_mouseDirH = 0.0f; + m_mouseDirV = 0.0f; + + if ( pos.x < m_mouseMarging ) + { + m_mouseDirH = pos.x/m_mouseMarging - 1.0f; + } + + if ( pos.x > 1.0f-m_mouseMarging ) + { + m_mouseDirH = 1.0f - (1.0f-pos.x)/m_mouseMarging; + } + + if ( pos.y < m_mouseMarging ) + { + m_mouseDirV = pos.y/m_mouseMarging - 1.0f; + } + + if ( pos.y > 1.0f-m_mouseMarging ) + { + m_mouseDirV = 1.0f - (1.0f-pos.y)/m_mouseMarging; + } + + if ( m_type == CAMERA_FREE || + m_type == CAMERA_EDIT || + m_type == CAMERA_BACK || + m_type == CAMERA_FIX || + m_type == CAMERA_PLANE || + m_type == CAMERA_EXPLO ) + { + if ( m_mouseDirH > 0.0f ) + { + type = D3DMOUSESCROLLR; + } + if ( m_mouseDirH < 0.0f ) + { + type = D3DMOUSESCROLLL; + } + } + + if ( m_type == CAMERA_FREE || + m_type == CAMERA_EDIT ) + { + if ( m_mouseDirV > 0.0f ) + { + type = D3DMOUSESCROLLU; + } + if ( m_mouseDirV < 0.0f ) + { + type = D3DMOUSESCROLLD; + } + } + + if ( m_bCameraInvertX ) + { + m_mouseDirH = -m_mouseDirH; + } + } + + return type; +} + + + +// Moves the point of view. + +bool CCamera::EventFrameFree(const Event &event) +{ + Math::Vector pos, vLookatPt; + float factor; + + factor = m_heightEye*0.5f+30.0f; + + if ( m_mouseDirH != 0.0f ) + { + m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; + } + if ( m_mouseDirV != 0.0f ) + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); + } + + // Up/Down. + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, event.axeY*event.rTime*factor*m_speed); + + // Left/Right. + if ( event.keyState & KS_CONTROL ) + { + if ( event.axeX < 0.0f ) + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH+Math::PI/2.0f, m_directionV, -event.axeX*event.rTime*factor*m_speed); + } + if ( event.axeX > 0.0f ) + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH-Math::PI/2.0f, m_directionV, event.axeX*event.rTime*factor*m_speed); + } + } + else + { + m_directionH -= event.axeX*event.rTime*0.7f*m_speed; + } + + // PageUp/PageDown. + if ( event.keyState & KS_NUMMINUS ) + { + if ( m_heightEye < 500.0f ) + { + m_heightEye += event.rTime*factor*m_speed; + } + } + if ( event.keyState & KS_NUMPLUS ) + { + if ( m_heightEye > -2.0f ) + { + m_heightEye -= event.rTime*factor*m_speed; + } + } + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if ( m_terrain->MoveOnFloor(m_eyePt, true) ) + { + m_eyePt.y += m_heightEye; + + pos = m_eyePt; + if ( m_terrain->MoveOnFloor(pos, true) ) + { + pos.y -= 2.0f; + if ( m_eyePt.y < pos.y ) + { + m_eyePt.y = pos.y; + } + } + + } + + vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); + + if ( m_terrain->MoveOnFloor(vLookatPt, true) ) + { + vLookatPt.y += m_heightLookat; + } + + SetViewTime(m_eyePt, vLookatPt, event.rTime); + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameEdit(const Event &event) +{ + Math::Vector pos, vLookatPt; + float factor; + + factor = m_editHeight*0.5f+30.0f; + + if ( m_mouseDirH != 0.0f ) + { + m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; + } + if ( m_mouseDirV != 0.0f ) + { + m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); + } + + if ( m_bCameraScroll ) + { + // Left/Right. + m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; + m_fixDirectionH = Math::NormAngle(m_fixDirectionH); + + // Up/Down. +//? m_fixDirectionV -= m_mouseDirV*event.rTime*0.5f*m_speed; +//? if ( m_fixDirectionV < -Math::PI*0.40f ) m_fixDirectionV = -Math::PI*0.40f; +//? if ( m_fixDirectionV > Math::PI*0.20f ) m_fixDirectionV = Math::PI*0.20f; + } + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if ( m_terrain->MoveOnFloor(m_eyePt, false) ) + { + m_eyePt.y += m_editHeight; + + pos = m_eyePt; + if ( m_terrain->MoveOnFloor(pos, false) ) + { + pos.y += 2.0f; + if ( m_eyePt.y < pos.y ) + { + m_eyePt.y = pos.y; + } + } + + } + + vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); + + if ( m_terrain->MoveOnFloor(vLookatPt, true) ) + { + vLookatPt.y += m_heightLookat; + } + + SetViewTime(m_eyePt, vLookatPt, event.rTime); + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameDialog(const Event &event) +{ + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameBack(const Event &event) +{ + CPhysics* physics; + ObjectType type; + Math::Vector pos, vLookatPt; + Math::Point mouse; + float centeringH, centeringV, centeringD, h, v, d, floor; + + if ( m_cameraObj == 0 ) + { + type = OBJECT_NULL; + } + else + { + type = m_cameraObj->RetType(); + } + + // +/-. + if ( event.keyState & KS_NUMPLUS ) + { + m_backDist -= event.rTime*30.0f*m_speed; + if ( m_backDist < m_backMin ) m_backDist = m_backMin; + } + if ( event.keyState & KS_NUMMINUS ) + { + m_backDist += event.rTime*30.0f*m_speed; + if ( m_backDist > 200.0f ) m_backDist = 200.0f; + } + + m_motorTurn = 0.0f; + + if ( m_bRightDown ) + { + m_addDirectionH = m_rightPosMove.x*6.0f; + m_addDirectionV = -m_rightPosMove.y*2.0f; + } + else + { + if ( m_bCameraScroll ) + { +#if 1 + // Left/Right. + m_addDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; + m_addDirectionH = Math::NormAngle(m_addDirectionH); + + // Up/Down. +//? m_backDist -= m_mouseDirV*event.rTime*30.0f*m_speed; +//? if ( m_backDist < 10.0f ) m_backDist = 10.0f; +//? if ( m_backDist > 200.0f ) m_backDist = 200.0f; +#else + if ( m_mousePos.y >= 0.18f && m_mousePos.y <= 0.93f ) + { +//? m_addDirectionH = -(m_mousePos.x-0.5f)*4.0f; + m_addDirectionV = (m_mousePos.y-0.5f)*2.0f; +//? if ( m_bCameraInvertX ) m_addDirectionH = -m_addDirectionH; + if ( m_bCameraInvertY ) m_addDirectionV = -m_addDirectionV; + + if ( m_mousePos.x < 0.5f ) m_motorTurn = -1.0f; + if ( m_mousePos.x > 0.5f ) m_motorTurn = 1.0f; + + mouse = m_mousePos; + mouse.x = 0.5f; + m_engine->MoveMousePos(mouse); + } + else + { + m_addDirectionH = 0.0f; + m_addDirectionV = 0.0f; + } +#endif + } + } + + if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) + { + AbortCentering(); // special stops framing + } + + // Increase the special framework. + centeringH = 0.0f; + centeringV = 0.0f; + centeringD = 0.0f; + + if ( m_centeringPhase == CP_START ) + { + m_centeringProgress += event.rTime/m_centeringTime; + if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; + centeringH = m_centeringProgress; + centeringV = m_centeringProgress; + centeringD = m_centeringProgress; + if ( m_centeringProgress >= 1.0f ) + { + m_centeringPhase = CP_WAIT; + } + } + + if ( m_centeringPhase == CP_WAIT ) + { + centeringH = 1.0f; + centeringV = 1.0f; + centeringD = 1.0f; + } + + if ( m_centeringPhase == CP_STOP ) + { + m_centeringProgress += event.rTime/m_centeringTime; + if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; + centeringH = 1.0f-m_centeringProgress; + centeringV = 1.0f-m_centeringProgress; + centeringD = 1.0f-m_centeringProgress; + if ( m_centeringProgress >= 1.0f ) + { + m_centeringPhase = CP_NULL; + } + } + + if ( m_centeringAngleH == 99.9f ) centeringH = 0.0f; + if ( m_centeringAngleV == 99.9f ) centeringV = 0.0f; + if ( m_centeringDist == 0.0f ) centeringD = 0.0f; + + if ( m_cameraObj != 0 ) + { + vLookatPt = m_cameraObj->RetPosition(0); + if ( type == OBJECT_BASE ) vLookatPt.y += 40.0f; + else if ( type == OBJECT_HUMAN ) vLookatPt.y += 1.0f; + else if ( type == OBJECT_TECH ) vLookatPt.y += 1.0f; + else vLookatPt.y += 4.0f; + + h = -m_cameraObj->RetAngleY(0); // angle vehicle / building + + if ( type == OBJECT_DERRICK || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_STATION || + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA || + type == OBJECT_SAFE || + type == OBJECT_HUSTON || + type == OBJECT_START || + type == OBJECT_END ) // building? + { + h += Math::PI*0.20f; // nearly face + } + else // vehicle? + { + h += Math::PI; // back + } + h = Math::NormAngle(h)+m_remotePan; + v = 0.0f; //? + + h += m_centeringCurrentH; + h += m_addDirectionH*(1.0f-centeringH); + h = Math::NormAngle(h); + + if ( type == OBJECT_MOBILEdr ) // designer? + { + v -= 0.3f; // Camera top + } + + v += m_centeringCurrentV; + v += m_addDirectionV*(1.0f-centeringV); + + d = m_backDist; + d += m_centeringDist*centeringD; + + m_centeringCurrentH = m_centeringAngleH*centeringH; + m_centeringCurrentV = m_centeringAngleV*centeringV; + + m_eyePt = RotateView(vLookatPt, h, v, d); + + physics = m_cameraObj->RetPhysics(); + if ( physics != 0 && physics->RetLand() ) // ground? + { + pos = vLookatPt+(vLookatPt-m_eyePt); + floor = m_terrain->RetFloorHeight(pos)-4.0f; + if ( floor > 0.0f ) + { + m_eyePt.y += floor; // shows the descent in front + } + } + + m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); + m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); + + SetViewTime(m_eyePt, vLookatPt, event.rTime); + + m_directionH = h+Math::PI/2.0f; + m_directionV = v; + } + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameFix(const Event &event) +{ + Math::Vector pos, vLookatPt; + float h, v, d; + + // +/-. + if ( event.keyState & KS_NUMPLUS ) + { + m_fixDist -= event.rTime*30.0f*m_speed; + if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; + } + if ( event.keyState & KS_NUMMINUS ) + { + m_fixDist += event.rTime*30.0f*m_speed; + if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; + } + + if ( m_bCameraScroll ) + { + // Left/Right. + m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; + m_fixDirectionH = Math::NormAngle(m_fixDirectionH); + + // Up/Down. +//? m_fixDist -= m_mouseDirV*event.rTime*30.0f*m_speed; +//? if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; +//? if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; + } + + if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) + { + AbortCentering(); // special stops framing + } + + if ( m_cameraObj != 0 ) + { + vLookatPt = m_cameraObj->RetPosition(0); + + h = m_fixDirectionH+m_remotePan; + v = m_fixDirectionV; + + d = m_fixDist; +//- if ( m_type == CAMERA_PLANE ) d += 20.0f; + m_eyePt = RotateView(vLookatPt, h, v, d); +//- if ( m_type == CAMERA_PLANE ) m_eyePt.y += 50.0f; + if ( m_type == CAMERA_PLANE ) m_eyePt.y += m_fixDist/2.0f; + m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); + m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); + + SetViewTime(m_eyePt, vLookatPt, event.rTime); + + m_directionH = h+Math::PI/2.0f; + m_directionV = v; + } + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameExplo(const Event &event) +{ + Math::Vector pos, vLookatPt; + float factor; + + factor = m_heightEye*0.5f+30.0f; + + if ( m_mouseDirH != 0.0f ) + { + m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; + } + + m_terrain->ValidPosition(m_eyePt, 10.0f); + + if ( m_terrain->MoveOnFloor(m_eyePt, false) ) + { + m_eyePt.y += m_heightEye; + + pos = m_eyePt; + if ( m_terrain->MoveOnFloor(pos, false) ) + { + pos.y += 2.0f; + if ( m_eyePt.y < pos.y ) + { + m_eyePt.y = pos.y; + } + } + + } + + vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); + + if ( m_terrain->MoveOnFloor(vLookatPt, true) ) + { + vLookatPt.y += m_heightLookat; + } + + SetViewTime(m_eyePt, vLookatPt, event.rTime); + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameOnBoard(const Event &event) +{ + Math::Vector vLookatPt, vUpVec, eye, lookat, pos; + + if ( m_cameraObj != 0 ) + { + m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV, + vLookatPt, vUpVec, m_type); + eye = m_effectOffset*0.3f+m_eyePt; + lookat = m_effectOffset*0.3f+vLookatPt; + + SetViewParams(eye, lookat, vUpVec); + m_actualEye = eye; + m_actualLookat = lookat; + } + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameInfo(const Event &event) +{ + SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f), + Math::Vector(0.0f, 0.0f, 1.0f), + event.rTime); + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameVisit(const Event &event) +{ + Math::Vector eye; + float angleH, angleV; + + m_visitTime += event.rTime; + + // +/-. + if ( event.keyState & KS_NUMPLUS ) + { + m_visitDist -= event.rTime*50.0f*m_speed; + if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; + } + if ( event.keyState & KS_NUMMINUS ) + { + m_visitDist += event.rTime*50.0f*m_speed; + if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; + } + + // PageUp/Down. + if ( event.keyState & KS_PAGEUP ) + { + m_visitDirectionV -= event.rTime*1.0f*m_speed; + if ( m_visitDirectionV < -Math::PI*0.40f ) m_visitDirectionV = -Math::PI*0.40f; + } + if ( event.keyState & KS_PAGEDOWN ) + { + m_visitDirectionV += event.rTime*1.0f*m_speed; + if ( m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f; + } + + if ( m_bCameraScroll ) + { + m_visitDist -= m_mouseDirV*event.rTime*30.0f*m_speed; + if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; + if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; + } + + angleH = (m_visitTime/10.0f)*(Math::PI*2.0f); + angleV = m_visitDirectionV; + eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist); + eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV); + eye = ExcludeObject(eye, m_visitGoal, angleH, angleV); + SetViewTime(eye, m_visitGoal, event.rTime); + + return true; +} + +// Moves the point of view. + +bool CCamera::EventFrameScript(const Event &event) +{ + SetViewTime(m_scriptEye+m_effectOffset, + m_scriptLookat+m_effectOffset, event.rTime); + return true; +} + +void CCamera::SetScriptEye(Math::Vector eye) +{ + m_scriptEye = eye; +} + +void CCamera::SetScriptLookat(Math::Vector lookat) +{ + m_scriptLookat = lookat; +} + + +// Specifies the location and direction of view. + +void CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, + const Math::Vector &up) +{ + bool bUnder; + + m_engine->SetViewParams(eye, lookat, up, m_eyeDistance); + + bUnder = (eye.y < m_water->RetLevel()); // Is it underwater? + if ( m_type == CAMERA_INFO ) bUnder = false; + m_engine->SetRankView(bUnder?1:0); +} + + +// Adjusts the camera not to enter the field. + +Math::Vector CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat, + float &angleH, float &angleV) +{ + Math::Vector pos; + float dist; + + pos = eye; + if ( m_terrain->MoveOnFloor(pos) ) + { + dist = Math::DistanceProjected(lookat, pos); + pos.y += 2.0f+dist*0.1f; + if ( pos.y > eye.y ) + { + angleV = -Math::RotateAngle(dist, pos.y-lookat.y); + eye = RotateView(lookat, angleH, angleV, dist); + } + } + return eye; +} + +// Adjusts the camera not to enter an object. + +Math::Vector CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat, + float &angleH, float &angleV) +{ + CObject* pObj; + Math::Vector oPos; + float oRad, dist; + int i, j; + +return eye; +//? + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRad) ) + { + dist = Math::Distance(oPos, eye); + if ( dist < oRad+2.0f ) + { + eye.y = oPos.y+oRad+2.0f; + } + } + } + + return eye; +} + + diff --git a/src/old/camera.h b/src/old/camera.h index f18f765..98e5420 100644 --- a/src/old/camera.h +++ b/src/old/camera.h @@ -1,269 +1,269 @@ -// * 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/. - -// camera.h - -#pragma once - - -#include "common/event.h" -#include "math/point.h" -#include "old/d3dengine.h" - - -class CInstanceManager; -class CD3DEngine; -class CTerrain; -class CWater; -class CObject; - - -enum CameraType -{ - CAMERA_NULL = 0, // camera undefined - CAMERA_FREE = 1, // camera free (never in principle) - CAMERA_EDIT = 2, // camera while editing a program - CAMERA_ONBOARD = 3, // camera on board a robot - CAMERA_BACK = 4, // camera behind a robot - CAMERA_FIX = 5, // static camera following robot - CAMERA_EXPLO = 6, // camera steady after explosion - CAMERA_SCRIPT = 7, // camera during a film script - CAMERA_INFO = 8, // camera for displaying information - CAMERA_VISIT = 9, // visit instead of an error - CAMERA_DIALOG = 10, // camera for dialogue - CAMERA_PLANE = 11, // static camera height -}; - -enum CameraSmooth -{ - CS_NONE = 0, // sharp - CS_NORM = 1, // normal - CS_HARD = 2, // hard - CS_SPEC = 3, // special -}; - -enum CenteringPhase -{ - CP_NULL = 0, - CP_START = 1, - CP_WAIT = 2, - CP_STOP = 3, -}; - -enum CameraEffect -{ - CE_NULL = 0, // no effect - CE_TERRAFORM = 1, // digging in - CE_CRASH = 2, // Vehicle driving is severely - CE_EXPLO = 3, // explosion - CE_SHOT = 4, // not mortal shot - CE_VIBRATION = 5, // vibration during construction - CE_PET = 6, // spleen reactor -}; - -enum OverEffect -{ - OE_NULL = 0, // no effect - OE_BLOOD = 1, // flash red - OE_FADEINw = 2, // white -> nothing - OE_FADEOUTw = 3, // nothing -> white - OE_FADEOUTb = 4, // nothing -> blue - OE_BLITZ = 5, // lightning -}; - - - -class CCamera -{ -public: - CCamera(CInstanceManager* iMan); - ~CCamera(); - - bool EventProcess(const Event &event); - - void Init(Math::Vector eye, Math::Vector lookat, float delay); - - void SetObject(CObject* object); - CObject* RetObject(); - - void SetType(CameraType type); - CameraType RetType(); - - void SetSmooth(CameraSmooth type); - CameraSmooth RetSmoth(); - - void SetDist(float dist); - float RetDist(); - - void SetFixDirection(float angle); - float RetFixDirection(); - - void SetRemotePan(float value); - float RetRemotePan(); - - void SetRemoteZoom(float value); - float RetRemoteZoom(); - - void StartVisit(Math::Vector goal, float dist); - void StopVisit(); - - void RetCamera(Math::Vector &eye, Math::Vector &lookat); - - bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time); - bool StopCentering(CObject *object, float time); - void AbortCentering(); - - void FlushEffect(); - void StartEffect(CameraEffect effect, Math::Vector pos, float force); - - void FlushOver(); - void SetOverBaseColor(D3DCOLORVALUE color); - void StartOver(OverEffect effect, Math::Vector pos, float force); - - void FixCamera(); - void SetScriptEye(Math::Vector eye); - void SetScriptLookat(Math::Vector lookat); - - void SetEffect(bool bEnable); - void SetCameraScroll(bool bScroll); - void SetCameraInvertX(bool bInvert); - void SetCameraInvertY(bool bInvert); - - float RetMotorTurn(); - D3DMouse RetMouseDef(Math::Point pos); - -protected: - bool EventMouseMove(const Event &event); - void EventMouseWheel(int dir); - bool EventFrame(const Event &event); - bool EventFrameFree(const Event &event); - bool EventFrameEdit(const Event &event); - bool EventFrameDialog(const Event &event); - bool EventFrameBack(const Event &event); - bool EventFrameFix(const Event &event); - bool EventFrameExplo(const Event &event); - bool EventFrameOnBoard(const Event &event); - bool EventFrameInfo(const Event &event); - bool EventFrameVisit(const Event &event); - bool EventFrameScript(const Event &event); - - void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime); - bool IsCollision(Math::Vector &eye, Math::Vector lookat); - bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat); - bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat); - - Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); - Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); - - void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up); - void EffectFrame(const Event &event); - void OverFrame(const Event &event); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - CTerrain* m_terrain; - CWater* m_water; - - CameraType m_type; // the type of camera (CAMERA *) - CameraSmooth m_smooth; // type of smoothing - CObject* m_cameraObj; // object linked to the camera - - float m_eyeDistance; // distance between the eyes - float m_initDelay; // time of initial centering - - Math::Vector m_actualEye; // current eye - Math::Vector m_actualLookat; // aim current - Math::Vector m_finalEye; // final eye - Math::Vector m_finalLookat; // aim final - Math::Vector m_normEye; // normal eye - Math::Vector m_normLookat; // aim normal - float m_focus; - - bool m_bRightDown; - Math::Point m_rightPosInit; - Math::Point m_rightPosCenter; - Math::Point m_rightPosMove; - - Math::Vector m_eyePt; // CAMERA_FREE: eye - float m_directionH; // CAMERA_FREE: horizontal direction - float m_directionV; // CAMERA_FREE: vertical direction - float m_heightEye; // CAMERA_FREE: height above the ground - float m_heightLookat; // CAMERA_FREE: height above the ground - float m_speed; // CAMERA_FREE: speed of movement - - float m_backDist; // CAMERA_BACK: distance - float m_backMin; // CAMERA_BACK: distance minimal - float m_addDirectionH; // CAMERA_BACK: additional direction - float m_addDirectionV; // CAMERA_BACK: additional direction - bool m_bTransparency; - - float m_fixDist; // CAMERA_FIX: distance - float m_fixDirectionH; // CAMERA_FIX: direction - float m_fixDirectionV; // CAMERA_FIX: direction - - Math::Vector m_visitGoal; // CAMERA_VISIT: target position - float m_visitDist; // CAMERA_VISIT: distance - float m_visitTime; // CAMERA_VISIT: relative time - CameraType m_visitType; // CAMERA_VISIT: initial type - float m_visitDirectionH; // CAMERA_VISIT: direction - float m_visitDirectionV; // CAMERA_VISIT: direction - - float m_editHeight; // CAMERA_EDIT: height - - float m_remotePan; - float m_remoteZoom; - - Math::Point m_mousePos; - float m_mouseDirH; - float m_mouseDirV; - float m_mouseMarging; - - float m_motorTurn; - - CenteringPhase m_centeringPhase; - float m_centeringAngleH; - float m_centeringAngleV; - float m_centeringDist; - float m_centeringCurrentH; - float m_centeringCurrentV; - float m_centeringTime; - float m_centeringProgress; - - CameraEffect m_effectType; - Math::Vector m_effectPos; - float m_effectForce; - float m_effectProgress; - Math::Vector m_effectOffset; - - OverEffect m_overType; - float m_overForce; - float m_overTime; - D3DCOLORVALUE m_overColorBase; - D3DCOLORVALUE m_overColor; - int m_overMode; - float m_overFadeIn; - float m_overFadeOut; - - Math::Vector m_scriptEye; - Math::Vector m_scriptLookat; - - bool m_bEffect; // shocks if explosion? - bool m_bCameraScroll; // scroll in the edges? - bool m_bCameraInvertX; // X inversion in the edges? - bool m_bCameraInvertY; // Y inversion in the edges? -}; - +// * 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/. + +// camera.h + +#pragma once + + +#include "common/event.h" +#include "math/point.h" +#include "old/d3dengine.h" + + +class CInstanceManager; +class CD3DEngine; +class CTerrain; +class CWater; +class CObject; + + +enum CameraType +{ + CAMERA_NULL = 0, // camera undefined + CAMERA_FREE = 1, // camera free (never in principle) + CAMERA_EDIT = 2, // camera while editing a program + CAMERA_ONBOARD = 3, // camera on board a robot + CAMERA_BACK = 4, // camera behind a robot + CAMERA_FIX = 5, // static camera following robot + CAMERA_EXPLO = 6, // camera steady after explosion + CAMERA_SCRIPT = 7, // camera during a film script + CAMERA_INFO = 8, // camera for displaying information + CAMERA_VISIT = 9, // visit instead of an error + CAMERA_DIALOG = 10, // camera for dialogue + CAMERA_PLANE = 11, // static camera height +}; + +enum CameraSmooth +{ + CS_NONE = 0, // sharp + CS_NORM = 1, // normal + CS_HARD = 2, // hard + CS_SPEC = 3, // special +}; + +enum CenteringPhase +{ + CP_NULL = 0, + CP_START = 1, + CP_WAIT = 2, + CP_STOP = 3, +}; + +enum CameraEffect +{ + CE_NULL = 0, // no effect + CE_TERRAFORM = 1, // digging in + CE_CRASH = 2, // Vehicle driving is severely + CE_EXPLO = 3, // explosion + CE_SHOT = 4, // not mortal shot + CE_VIBRATION = 5, // vibration during construction + CE_PET = 6, // spleen reactor +}; + +enum OverEffect +{ + OE_NULL = 0, // no effect + OE_BLOOD = 1, // flash red + OE_FADEINw = 2, // white -> nothing + OE_FADEOUTw = 3, // nothing -> white + OE_FADEOUTb = 4, // nothing -> blue + OE_BLITZ = 5, // lightning +}; + + + +class CCamera +{ +public: + CCamera(CInstanceManager* iMan); + ~CCamera(); + + bool EventProcess(const Event &event); + + void Init(Math::Vector eye, Math::Vector lookat, float delay); + + void SetObject(CObject* object); + CObject* RetObject(); + + void SetType(CameraType type); + CameraType RetType(); + + void SetSmooth(CameraSmooth type); + CameraSmooth RetSmoth(); + + void SetDist(float dist); + float RetDist(); + + void SetFixDirection(float angle); + float RetFixDirection(); + + void SetRemotePan(float value); + float RetRemotePan(); + + void SetRemoteZoom(float value); + float RetRemoteZoom(); + + void StartVisit(Math::Vector goal, float dist); + void StopVisit(); + + void RetCamera(Math::Vector &eye, Math::Vector &lookat); + + bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time); + bool StopCentering(CObject *object, float time); + void AbortCentering(); + + void FlushEffect(); + void StartEffect(CameraEffect effect, Math::Vector pos, float force); + + void FlushOver(); + void SetOverBaseColor(D3DCOLORVALUE color); + void StartOver(OverEffect effect, Math::Vector pos, float force); + + void FixCamera(); + void SetScriptEye(Math::Vector eye); + void SetScriptLookat(Math::Vector lookat); + + void SetEffect(bool bEnable); + void SetCameraScroll(bool bScroll); + void SetCameraInvertX(bool bInvert); + void SetCameraInvertY(bool bInvert); + + float RetMotorTurn(); + D3DMouse RetMouseDef(Math::Point pos); + +protected: + bool EventMouseMove(const Event &event); + void EventMouseWheel(int dir); + bool EventFrame(const Event &event); + bool EventFrameFree(const Event &event); + bool EventFrameEdit(const Event &event); + bool EventFrameDialog(const Event &event); + bool EventFrameBack(const Event &event); + bool EventFrameFix(const Event &event); + bool EventFrameExplo(const Event &event); + bool EventFrameOnBoard(const Event &event); + bool EventFrameInfo(const Event &event); + bool EventFrameVisit(const Event &event); + bool EventFrameScript(const Event &event); + + void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime); + bool IsCollision(Math::Vector &eye, Math::Vector lookat); + bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat); + bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat); + + Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); + Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV); + + void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up); + void EffectFrame(const Event &event); + void OverFrame(const Event &event); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + CTerrain* m_terrain; + CWater* m_water; + + CameraType m_type; // the type of camera (CAMERA *) + CameraSmooth m_smooth; // type of smoothing + CObject* m_cameraObj; // object linked to the camera + + float m_eyeDistance; // distance between the eyes + float m_initDelay; // time of initial centering + + Math::Vector m_actualEye; // current eye + Math::Vector m_actualLookat; // aim current + Math::Vector m_finalEye; // final eye + Math::Vector m_finalLookat; // aim final + Math::Vector m_normEye; // normal eye + Math::Vector m_normLookat; // aim normal + float m_focus; + + bool m_bRightDown; + Math::Point m_rightPosInit; + Math::Point m_rightPosCenter; + Math::Point m_rightPosMove; + + Math::Vector m_eyePt; // CAMERA_FREE: eye + float m_directionH; // CAMERA_FREE: horizontal direction + float m_directionV; // CAMERA_FREE: vertical direction + float m_heightEye; // CAMERA_FREE: height above the ground + float m_heightLookat; // CAMERA_FREE: height above the ground + float m_speed; // CAMERA_FREE: speed of movement + + float m_backDist; // CAMERA_BACK: distance + float m_backMin; // CAMERA_BACK: distance minimal + float m_addDirectionH; // CAMERA_BACK: additional direction + float m_addDirectionV; // CAMERA_BACK: additional direction + bool m_bTransparency; + + float m_fixDist; // CAMERA_FIX: distance + float m_fixDirectionH; // CAMERA_FIX: direction + float m_fixDirectionV; // CAMERA_FIX: direction + + Math::Vector m_visitGoal; // CAMERA_VISIT: target position + float m_visitDist; // CAMERA_VISIT: distance + float m_visitTime; // CAMERA_VISIT: relative time + CameraType m_visitType; // CAMERA_VISIT: initial type + float m_visitDirectionH; // CAMERA_VISIT: direction + float m_visitDirectionV; // CAMERA_VISIT: direction + + float m_editHeight; // CAMERA_EDIT: height + + float m_remotePan; + float m_remoteZoom; + + Math::Point m_mousePos; + float m_mouseDirH; + float m_mouseDirV; + float m_mouseMarging; + + float m_motorTurn; + + CenteringPhase m_centeringPhase; + float m_centeringAngleH; + float m_centeringAngleV; + float m_centeringDist; + float m_centeringCurrentH; + float m_centeringCurrentV; + float m_centeringTime; + float m_centeringProgress; + + CameraEffect m_effectType; + Math::Vector m_effectPos; + float m_effectForce; + float m_effectProgress; + Math::Vector m_effectOffset; + + OverEffect m_overType; + float m_overForce; + float m_overTime; + D3DCOLORVALUE m_overColorBase; + D3DCOLORVALUE m_overColor; + int m_overMode; + float m_overFadeIn; + float m_overFadeOut; + + Math::Vector m_scriptEye; + Math::Vector m_scriptLookat; + + bool m_bEffect; // shocks if explosion? + bool m_bCameraScroll; // scroll in the edges? + bool m_bCameraInvertX; // X inversion in the edges? + bool m_bCameraInvertY; // Y inversion in the edges? +}; + diff --git a/src/old/cloud.cpp b/src/old/cloud.cpp index 7c1518c..8661cbd 100644 --- a/src/old/cloud.cpp +++ b/src/old/cloud.cpp @@ -1,338 +1,338 @@ -// * 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/. - - -#include -#include -#include - -#include "common/struct.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/terrain.h" -#include "object/object.h" -#include "old/cloud.h" - - - -const int DIMEXPAND = 4; // extension of the dimensions - - - -// Constructor of clouds. - -CCloud::CCloud(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_CLOUD, this); - - m_engine = engine; - m_terrain = 0; - - m_level = 0.0f; - m_wind = Math::Vector(0.0f, 0.0f, 0.0f); - m_subdiv = 8; - m_filename[0] = 0; - m_bEnable = true; -} - -// Destructor of clouds. - -CCloud::~CCloud() -{ -} - - -bool CCloud::EventProcess(const Event &event) -{ - if ( event.event == EVENT_FRAME ) - { - return EventFrame(event); - } - - return true; -} - -// Makes the clouds evolve. - -bool CCloud::EventFrame(const Event &event) -{ - if ( m_engine->RetPause() ) return true; - - m_time += event.rTime; - - if ( m_level == 0.0f ) return true; - - if ( m_time-m_lastTest < 0.2f ) return true; - m_lastTest = m_time; - - return true; -} - - -// Adjusts the position to normal, to imitate the clouds -// at movement. - -void CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, - Math::Point &uv1, Math::Point &uv2) -{ - float dist, factor; - - uv1.x = (pos.x+20000.0f)/1280.0f; - uv1.y = (pos.z+20000.0f)/1280.0f; - uv1.x -= m_time*(m_wind.x/100.0f); - uv1.y -= m_time*(m_wind.z/100.0f); - - uv2.x = 0.0f; - uv2.y = 0.0f; - - dist = Math::DistanceProjected(pos, eye); - factor = powf(dist/deep, 2.0f); - pos.y -= m_level*factor*10.0f; -} - -inline DWORD F2DW( FLOAT f ) -{ - return *((DWORD*)&f); -} - -// Draw the clouds. - -void CCloud::Draw() -{ - LPDIRECT3DDEVICE7 device; - D3DVERTEX2* vertex; - Math::Matrix* matView; - D3DMATERIAL7 material; - Math::Matrix matrix; - Math::Vector n, pos, p, eye; - Math::Point uv1, uv2; - float iDeep, deep, size, fogStart, fogEnd; - int i, j, u; - - if ( !m_bEnable ) return; - if ( m_level == 0.0f ) return; - if ( m_lineUsed == 0 ) return; - - vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); - - iDeep = m_engine->RetDeepView(); - deep = (m_brick*m_size)/2.0f; - m_engine->SetDeepView(deep); - m_engine->SetFocus(m_engine->RetFocus()); - m_engine->UpdateMatProj(); // increases the depth of view - -//? fogStart = deep*0.10f; -//? fogEnd = deep*0.16f; - fogStart = deep*0.15f; - fogEnd = deep*0.24f; - - device = m_engine->RetD3DDevice(); - device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x00000000); - device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); - device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); -//? device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); - device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true); - device->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(fogStart)); - device->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(fogEnd)); - - matView = m_engine->RetMatView(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(*matView); - device->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - - ZeroMemory( &material, sizeof(D3DMATERIAL7) ); - material.diffuse = m_diffuse; - material.ambient = m_ambient; - m_engine->SetMaterial(material); - - m_engine->SetTexture(m_filename, 0); - m_engine->SetTexture(m_filename, 1); - -//? m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP); - m_engine->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP); -//? m_engine->SetState(D3DSTATEWRAP); - - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - size = m_size/2.0f; - eye = m_engine->RetEyePt(); - n = Math::Vector(0.0f, -1.0f, 0.0f); - - // Draws all the lines. - for ( i=0 ; iDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); - m_engine->AddStatisticTriangle(u-2); - } - - m_engine->SetDeepView(iDeep); - m_engine->SetFocus(m_engine->RetFocus()); - m_engine->UpdateMatProj(); // gives depth to initial - - free(vertex); -} - - -// Updates the positions, relative to the ground. - -bool CCloud::CreateLine(int x, int y, int len) -{ - float offset; - - m_line[m_lineUsed].x = x; - m_line[m_lineUsed].y = y; - m_line[m_lineUsed].len = len; - - offset = m_brick*m_size/2.0f - m_size/2.0f; - - m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; - m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; - m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; - - m_lineUsed ++; - - return ( m_lineUsed < MAXCLOUDLINE ); -} - -// Creates all areas of cloud. - -bool CCloud::Create(const char *filename, - D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, - float level) -{ - int y; - - m_diffuse = diffuse; - m_ambient = ambient; - m_level = level; - m_time = 0.0f; - m_lastTest = 0.0f; - strcpy(m_filename, filename); - - if ( m_filename[0] != 0 ) - { - m_engine->LoadTexture(m_filename, 0); - m_engine->LoadTexture(m_filename, 1); - } - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - - m_wind = m_terrain->RetWind(); - - m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic()*DIMEXPAND; - m_size = m_terrain->RetSize(); - - m_brick /= m_subdiv*DIMEXPAND; - m_size *= m_subdiv*DIMEXPAND; - - if ( m_level == 0.0f ) return true; - - m_lineUsed = 0; - for ( y=0 ; y +#include +#include + +#include "common/struct.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/terrain.h" +#include "object/object.h" +#include "old/cloud.h" + + + +const int DIMEXPAND = 4; // extension of the dimensions + + + +// Constructor of clouds. + +CCloud::CCloud(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_CLOUD, this); + + m_engine = engine; + m_terrain = 0; + + m_level = 0.0f; + m_wind = Math::Vector(0.0f, 0.0f, 0.0f); + m_subdiv = 8; + m_filename[0] = 0; + m_bEnable = true; +} + +// Destructor of clouds. + +CCloud::~CCloud() +{ +} + + +bool CCloud::EventProcess(const Event &event) +{ + if ( event.event == EVENT_FRAME ) + { + return EventFrame(event); + } + + return true; +} + +// Makes the clouds evolve. + +bool CCloud::EventFrame(const Event &event) +{ + if ( m_engine->RetPause() ) return true; + + m_time += event.rTime; + + if ( m_level == 0.0f ) return true; + + if ( m_time-m_lastTest < 0.2f ) return true; + m_lastTest = m_time; + + return true; +} + + +// Adjusts the position to normal, to imitate the clouds +// at movement. + +void CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep, + Math::Point &uv1, Math::Point &uv2) +{ + float dist, factor; + + uv1.x = (pos.x+20000.0f)/1280.0f; + uv1.y = (pos.z+20000.0f)/1280.0f; + uv1.x -= m_time*(m_wind.x/100.0f); + uv1.y -= m_time*(m_wind.z/100.0f); + + uv2.x = 0.0f; + uv2.y = 0.0f; + + dist = Math::DistanceProjected(pos, eye); + factor = powf(dist/deep, 2.0f); + pos.y -= m_level*factor*10.0f; +} + +inline DWORD F2DW( FLOAT f ) +{ + return *((DWORD*)&f); +} + +// Draw the clouds. + +void CCloud::Draw() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2* vertex; + Math::Matrix* matView; + D3DMATERIAL7 material; + Math::Matrix matrix; + Math::Vector n, pos, p, eye; + Math::Point uv1, uv2; + float iDeep, deep, size, fogStart, fogEnd; + int i, j, u; + + if ( !m_bEnable ) return; + if ( m_level == 0.0f ) return; + if ( m_lineUsed == 0 ) return; + + vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); + + iDeep = m_engine->RetDeepView(); + deep = (m_brick*m_size)/2.0f; + m_engine->SetDeepView(deep); + m_engine->SetFocus(m_engine->RetFocus()); + m_engine->UpdateMatProj(); // increases the depth of view + +//? fogStart = deep*0.10f; +//? fogEnd = deep*0.16f; + fogStart = deep*0.15f; + fogEnd = deep*0.24f; + + device = m_engine->RetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x00000000); + device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); +//? device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); + device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true); + device->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(fogStart)); + device->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(fogEnd)); + + matView = m_engine->RetMatView(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(*matView); + device->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + m_engine->SetTexture(m_filename, 0); + m_engine->SetTexture(m_filename, 1); + +//? m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP); + m_engine->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP); +//? m_engine->SetState(D3DSTATEWRAP); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + size = m_size/2.0f; + eye = m_engine->RetEyePt(); + n = Math::Vector(0.0f, -1.0f, 0.0f); + + // Draws all the lines. + for ( i=0 ; iDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); + m_engine->AddStatisticTriangle(u-2); + } + + m_engine->SetDeepView(iDeep); + m_engine->SetFocus(m_engine->RetFocus()); + m_engine->UpdateMatProj(); // gives depth to initial + + free(vertex); +} + + +// Updates the positions, relative to the ground. + +bool CCloud::CreateLine(int x, int y, int len) +{ + float offset; + + m_line[m_lineUsed].x = x; + m_line[m_lineUsed].y = y; + m_line[m_lineUsed].len = len; + + offset = m_brick*m_size/2.0f - m_size/2.0f; + + m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; + m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; + m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; + + m_lineUsed ++; + + return ( m_lineUsed < MAXCLOUDLINE ); +} + +// Creates all areas of cloud. + +bool CCloud::Create(const char *filename, + D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, + float level) +{ + int y; + + m_diffuse = diffuse; + m_ambient = ambient; + m_level = level; + m_time = 0.0f; + m_lastTest = 0.0f; + strcpy(m_filename, filename); + + if ( m_filename[0] != 0 ) + { + m_engine->LoadTexture(m_filename, 0); + m_engine->LoadTexture(m_filename, 1); + } + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + + m_wind = m_terrain->RetWind(); + + m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic()*DIMEXPAND; + m_size = m_terrain->RetSize(); + + m_brick /= m_subdiv*DIMEXPAND; + m_size *= m_subdiv*DIMEXPAND; + + if ( m_level == 0.0f ) return true; + + m_lineUsed = 0; + for ( y=0 ; y -#include -#include -#include -#include -#include -#include -#include - -#include "common/struct.h" -#include "old/d3dtextr.h" -#include "old/d3dengine.h" -#include "common/language.h" -#include "common/event.h" -#include "common/profile.h" -#include "common/iman.h" -#include "common/restext.h" -#include "old/math3d.h" -#include "old/joystick.h" -#include "object/robotmain.h" -#include "old/sound.h" -#include "old/d3dapp.h" - -// fix for "MSH_MOUSEWHEEL undefined" error -#ifdef UNICODE -#define MSH_MOUSEWHEEL L"MSWHEEL_ROLLMSG" -#else -#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" -#endif - - -const int AUDIO_TRACK = 13; // total number of audio tracks on the CD -const float MAX_STEP = 0.2f; // maximum time for a step - -const int WINDOW_DX = (640+6); // dimensions in windowed mode -const int WINDOW_DY = (480+25); - -#define USE_THREAD false // true does not work! -const float TIME_THREAD = 0.02f; - - - - -// Limit the use of the controls keyboard & joystick. - -float AxeLimit(float value) -{ - if ( value < -1.0f ) value = -1.0f; - if ( value > 1.0f ) value = 1.0f; - return value; -} - - -// Entry point to the program. Initializes everything, and goes into a -// message-processing loop. Idle time is used to render the scene. - -INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) -{ - Error err; - char string[100]; - - CD3DApplication d3dApp; // single instance of the application - - err = d3dApp.CheckMistery(strCmdLine); - if ( err != ERR_OK ) - { - GetResource(RES_ERR, err, string); -#if _NEWLOOK - MessageBox( NULL, string, _T("CeeBot"), MB_ICONERROR|MB_OK ); -#else - MessageBox( NULL, string, _T("COLOBOT"), MB_ICONERROR|MB_OK ); -#endif - return 0; - } - - if ( FAILED(d3dApp.Create(hInst, strCmdLine)) ) - { - return 0; - } - - return d3dApp.Run(); // execution of all -} - - -// Internal variables and function prototypes. - -enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHEDTOSOFTWARE }; - -static INT CALLBACK AboutProc( HWND, UINT, WPARAM, LPARAM ); -static LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); - -static CD3DApplication* g_pD3DApp; - - - -// Constructor. - -CD3DApplication::CD3DApplication() -{ - int i; - - m_iMan = new(CInstanceManager); - m_event = new CEvent(m_iMan); - - m_pD3DEngine = 0; - m_pRobotMain = 0; - m_pSound = 0; - m_pFramework = 0; - m_instance = 0; - m_hWnd = 0; - m_pDD = 0; - m_pD3D = 0; - m_pD3DDevice = 0; - - m_CDpath[0] = 0; - - m_pddsRenderTarget = 0; - m_pddsDepthBuffer = 0; - - m_keyState = 0; - m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); - m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); - - m_vidMemTotal = 0; - m_bActive = false; - m_bActivateApp = false; - m_bReady = false; - m_bJoystick = false; - m_aTime = 0.0f; - - for ( i=0 ; i<32 ; i++ ) - { - m_bJoyButton[i] = false; - } - -#if _NEWLOOK - m_strWindowTitle = _T("CeeBot"); -#else - m_strWindowTitle = _T("COLOBOT"); -#endif - m_bAppUseZBuffer = true; - m_bAppUseStereo = true; - m_bShowStats = false; - m_bDebugMode = false; - m_bAudioState = true; - m_bAudioTrack = true; - m_bNiceMouse = false; - m_bSetupMode = true; - m_fnConfirmDevice = 0; - - ResetKey(); - - g_pD3DApp = this; - - // Request event sent by Logitech. - m_mshMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); - - _mkdir("files\\"); -} - - -// Destructor. - -CD3DApplication::~CD3DApplication() -{ - delete m_iMan; -} - - - -// Returns the path of the CD. - -char* CD3DApplication::RetCDpath() -{ - return m_CDpath; -} - -// Reads the information in the registry. - -Error CD3DApplication::RegQuery() -{ - FILE* file = NULL; - HKEY key; - LONG i; - DWORD type, len; - char filename[100]; - -#if _NEWLOOK - #if _TEEN - i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-Teen\\Setup", - #else - i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-A\\Setup", - #endif -#else - i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\Colobot\\Setup", -#endif - 0, KEY_READ, &key); - if ( i != ERROR_SUCCESS ) return ERR_INSTALL; - - type = REG_SZ; - len = sizeof(m_CDpath); - i = RegQueryValueEx(key, "CDpath", NULL, &type, (LPBYTE)m_CDpath, &len); - if ( i != ERROR_SUCCESS || type != REG_SZ ) return ERR_INSTALL; - - filename[0] = m_CDpath[0]; - filename[1] = ':'; - filename[2] = '\\'; - filename[3] = 0; - i = GetDriveType(filename); - if ( i != DRIVE_CDROM ) return ERR_NOCD; - - strcat(filename, "install.ini"); - file = fopen(filename, "rb"); // install.ini file exist? - if ( file == NULL ) return ERR_NOCD; - fclose(file); - - return ERR_OK; -} - -// Checks for audio tracks on the CD. - -Error CD3DApplication::AudioQuery() -{ - MCI_OPEN_PARMS mciOpenParms; - MCI_STATUS_PARMS mciStatusParms; - DWORD dwReturn; - UINT deviceID; - char device[10]; - - // Open the device by specifying the device and filename. - // MCI will attempt to choose the MIDI mapper as the output port. - memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS)); - mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; - if ( m_CDpath[0] == 0 ) - { - dwReturn = mciSendCommand(NULL, - MCI_OPEN, - MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, - (DWORD)(LPVOID)&mciOpenParms); - } - else - { - device[0] = m_CDpath[0]; - device[1] = ':'; - device[2] = 0; - mciOpenParms.lpstrElementName = device; - dwReturn = mciSendCommand(NULL, - MCI_OPEN, - MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT, - (DWORD)(LPVOID)&mciOpenParms); - } - if ( dwReturn != 0 ) - { - return ERR_NOCD; - } - - // The device opened successfully; get the device ID. - deviceID = mciOpenParms.wDeviceID; - - memset(&mciStatusParms, 0, sizeof(MCI_STATUS_PARMS)); - mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; - dwReturn = mciSendCommand(deviceID, - MCI_STATUS, - MCI_WAIT|MCI_STATUS_ITEM, - (DWORD)&mciStatusParms); - if ( dwReturn != 0 ) - { - mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); - return ERR_NOCD; - } - - if ( mciStatusParms.dwReturn != AUDIO_TRACK ) - { - mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); - return ERR_NOCD; - } - - mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); - return ERR_OK; -} - -// Checks for the key. - -Error CD3DApplication::CheckMistery(char *strCmdLine) -{ - if ( strstr(strCmdLine, "-debug") != 0 ) - { - m_bShowStats = true; - SetDebugMode(true); - } - - if ( strstr(strCmdLine, "-audiostate") != 0 ) - { - m_bAudioState = false; - } - - if ( strstr(strCmdLine, "-audiotrack") != 0 ) - { - m_bAudioTrack = false; - } - - m_CDpath[0] = 0; -#if _FULL - if ( strstr(strCmdLine, "-nocd") == 0 && !m_bDebugMode ) - { - Error err; - - err = RegQuery(); - if ( err != ERR_OK ) return err; - - //?err = AudioQuery(); - //?if ( err != ERR_OK ) return err; - } -#endif -#if _SCHOOL & _EDU - if ( strstr(strCmdLine, "-nosetup") != 0 ) - { - m_bSetupMode = false; - } - m_bAudioTrack = false; -#endif -#if _SCHOOL & _PERSO - Error err = RegQuery(); - if ( err != ERR_OK ) return err; - m_bAudioTrack = false; -#endif -#if _SCHOOL & _CEEBOTDEMO - m_bAudioTrack = false; -#endif -#if _NET - m_bAudioTrack = false; -#endif -#if _DEMO - m_bAudioTrack = false; -#endif - - return ERR_OK; -} - - -// Returns the total amount of video memory for textures. - -int CD3DApplication::GetVidMemTotal() -{ - return m_vidMemTotal; -} - -bool CD3DApplication::IsVideo8MB() -{ - if ( m_vidMemTotal == 0 ) return false; - return (m_vidMemTotal <= 8388608L); // 8 Mb or less (2 ^ 23)? -} - -bool CD3DApplication::IsVideo32MB() -{ - if ( m_vidMemTotal == 0 ) return false; - return (m_vidMemTotal > 16777216L); // more than 16 Mb (2 ^ 24)? -} - - -void CD3DApplication::SetShowStat(bool bShow) -{ - m_bShowStats = bShow; -} - -bool CD3DApplication::RetShowStat() -{ - return m_bShowStats; -} - - -void CD3DApplication::SetDebugMode(bool bMode) -{ - m_bDebugMode = bMode; - D3DTextr_SetDebugMode(m_bDebugMode); -} - -bool CD3DApplication::RetDebugMode() -{ - return m_bDebugMode; -} - -bool CD3DApplication::RetSetupMode() -{ - return m_bSetupMode; -} - - - - -// Son process of time management. - -DWORD WINAPI ThreadRoutine(LPVOID) -{ - Event event; - float time; - int ms, start, end, delay; - - ms = (int)(TIME_THREAD*1000.0f); - time = 0.0f; - while ( true ) - { - start = timeGetTime(); - - g_pD3DApp->m_pD3DEngine->FrameMove(TIME_THREAD); - - ZeroMemory(&event, sizeof(Event)); - event.event = EVENT_FRAME; - event.rTime = TIME_THREAD; - event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x); - event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y); - event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z); - event.keyState = g_pD3DApp->m_keyState; - - if ( g_pD3DApp->m_pRobotMain != 0 ) - { - g_pD3DApp->m_pRobotMain->EventProcess(event); - } - - end = timeGetTime(); - - delay = ms-(end-start); - if ( delay > 0 ) - { - Sleep(delay); // waiting 20ms-used - } - time += TIME_THREAD; - } - return 0; -} - - -// Called during device intialization, this code checks the device -// for some minimum set of capabilities. - -HRESULT CD3DApplication::ConfirmDevice( DDCAPS* pddDriverCaps, - D3DDEVICEDESC7* pd3dDeviceDesc ) -{ -//? if( pd3dDeviceDesc->wMaxVertexBlendMatrices < 2 ) -//? return E_FAIL; - - return S_OK; -} - -// Create the application. - -HRESULT CD3DApplication::Create( HINSTANCE hInst, TCHAR* strCmdLine ) -{ - HRESULT hr; - char deviceName[100]; - char modeName[100]; - int iValue; - DWORD style; - bool bFull, b3D; - - m_instance = hInst; - - InitCurrentDirectory(); - - // Enumerate available D3D devices. The callback is used so the app can - // confirm/reject each enumerated device depending on its capabilities. - if( FAILED( hr = D3DEnum_EnumerateDevices( m_fnConfirmDevice ) ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - return hr; - } - - if( FAILED( hr = D3DEnum_SelectDefaultDevice( &m_pDeviceInfo ) ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - return hr; - } - - if ( !m_bDebugMode ) - { - m_pDeviceInfo->bWindowed = false; // full screen - } - if ( GetProfileInt("Device", "FullScreen", bFull) ) - { - m_pDeviceInfo->bWindowed = !bFull; - } - m_pDeviceInfo->bWindowed = true; - - // Create the 3D engine. - if( (m_pD3DEngine = new CD3DEngine(m_iMan, this)) == NULL ) - { - DisplayFrameworkError( D3DENUMERR_ENGINE, MSGERR_APPMUSTEXIT ); - return E_OUTOFMEMORY; - } - SetEngine(m_pD3DEngine); - - // Initialize the app's custom scene stuff - if( FAILED( hr = m_pD3DEngine->OneTimeSceneInit() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - return hr; - } - - // Create a new CD3DFramework class. This class does all of our D3D - // initialization and manages the common D3D objects. - if( (m_pFramework = new CD3DFramework7()) == NULL ) - { - DisplayFrameworkError( E_OUTOFMEMORY, MSGERR_APPMUSTEXIT ); - return E_OUTOFMEMORY; - } - - // Create the sound instance. - if( (m_pSound = new CSound(m_iMan)) == NULL ) - { - DisplayFrameworkError( D3DENUMERR_SOUND, MSGERR_APPMUSTEXIT ); - return E_OUTOFMEMORY; - } - - // Create the robot application. - if( (m_pRobotMain = new CRobotMain(m_iMan)) == NULL ) - { - DisplayFrameworkError( D3DENUMERR_ROBOT, MSGERR_APPMUSTEXIT ); - return E_OUTOFMEMORY; - } - - // Register the window class - WNDCLASS wndClass = { 0, WndProc, 0, 0, hInst, - LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON) ), - LoadCursor( NULL, IDC_ARROW ), - (HBRUSH)GetStockObject(WHITE_BRUSH), - NULL, _T("D3D Window") }; - RegisterClass( &wndClass ); - - // Create the render window - style = WS_CAPTION|WS_VISIBLE; - if ( m_bDebugMode ) style |= WS_SYSMENU; // close box - m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, -//? WS_OVERLAPPEDWINDOW|WS_VISIBLE, - style, CW_USEDEFAULT, CW_USEDEFAULT, - WINDOW_DX, WINDOW_DY, 0L, -//? LoadMenu( hInst, MAKEINTRESOURCE(IDR_MENU) ), - NULL, - hInst, 0L ); - UpdateWindow( m_hWnd ); - - if ( !GetProfileInt("Setup", "Sound3D", b3D) ) - { - b3D = true; - } - m_pSound->SetDebugMode(m_bDebugMode); - m_pSound->Create(m_hWnd, b3D); - m_pSound->CacheAll(); - m_pSound->SetState(m_bAudioState); - m_pSound->SetAudioTrack(m_bAudioTrack); - m_pSound->SetCDpath(m_CDpath); - - // Initialize the 3D environment for the app - if( FAILED( hr = Initialize3DEnvironment() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - Cleanup3DEnvironment(); - return E_FAIL; - } - - // Change the display device driver. - GetProfileString("Device", "Name", deviceName, 100); - GetProfileString("Device", "Mode", modeName, 100); - GetProfileInt("Device", "FullScreen", bFull); - if ( deviceName[0] != 0 && modeName[0] != 0 && bFull ) - { - ChangeDevice(deviceName, modeName, bFull); - } - - // First execution? - if ( !GetProfileInt("Setup", "ObjectDirty", iValue) ) - { - m_pD3DEngine->FirstExecuteAdapt(true); - } - - // Creates the file colobot.ini at the first execution. - m_pRobotMain->CreateIni(); - -#if _DEMO - m_pRobotMain->ChangePhase(PHASE_NAME); -#else -#if _NET | _SCHOOL - m_pRobotMain->ChangePhase(PHASE_WELCOME2); -#else -#if _FRENCH - m_pRobotMain->ChangePhase(PHASE_WELCOME2); -#endif -#if _ENGLISH - m_pRobotMain->ChangePhase(PHASE_WELCOME2); -#endif -#if _GERMAN - m_pRobotMain->ChangePhase(PHASE_WELCOME2); -#endif -#if _WG - m_pRobotMain->ChangePhase(PHASE_WELCOME1); -#endif -#if _POLISH - m_pRobotMain->ChangePhase(PHASE_WELCOME1); -#endif -#endif -#endif - m_pD3DEngine->TimeInit(); - -#if USE_THREAD - m_thread = CreateThread(NULL, 0, ThreadRoutine, this, 0, &m_threadId); - SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL); -#endif - - // The app is ready to go - m_bReady = true; - - return S_OK; -} - - -// Message-processing loop. Idle time is used to render the scene. - -INT CD3DApplication::Run() -{ - // Load keyboard accelerators - HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) ); - - // Now we're ready to recieve and process Windows messages. - bool bGotMsg; - MSG msg; - PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ); - - while( WM_QUIT != msg.message ) - { - // Use PeekMessage() if the app is active, so we can use idle time to - // render the scene. Else, use GetMessage() to avoid eating CPU time. - if( m_bActive ) - bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); - else - bGotMsg = GetMessage( &msg, NULL, 0U, 0U ); - - if( bGotMsg ) - { - // Translate and dispatch the message - if( TranslateAccelerator( m_hWnd, hAccel, &msg ) == 0 ) - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - } - else - { - // Render a frame during idle time (no messages are waiting) - if( m_bActive && m_bReady ) - { - Event event; - - while ( m_event->GetEvent(event) ) - { - if ( event.event == EVENT_QUIT ) - { -//? SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); - m_pSound->StopMusic(); - Cleanup3DEnvironment(); - PostQuitMessage(0); - return msg.wParam; - } - m_pRobotMain->EventProcess(event); - } - - if ( !RetNiceMouse() ) - { - SetMouseType(m_pD3DEngine->RetMouseType()); - } - - if( FAILED( Render3DEnvironment() ) ) - DestroyWindow( m_hWnd ); - } - } - } - - return msg.wParam; -} - - - -// Conversion of the position of the mouse. -// x: 0=left, 1=right -// y: 0=down, 1=up - -Math::Point CD3DApplication::ConvPosToInterface(HWND hWnd, LPARAM lParam) -{ - POINT cpos; - Math::Point pos; - float px, py, w, h; - - cpos.x = (short)LOWORD(lParam); - cpos.y = (short)HIWORD(lParam); - - if ( !m_pDeviceInfo->bWindowed ) - { - ClientToScreen(hWnd, &cpos); - } - - px = (float)cpos.x; - py = (float)cpos.y; - w = (float)m_ddsdRenderTarget.dwWidth; - h = (float)m_ddsdRenderTarget.dwHeight; - - pos.x = px/w; - pos.y = 1.0f-py/h; - - return pos; -} - -// Physically moves the mouse. - -void CD3DApplication::SetMousePos(Math::Point pos) -{ - POINT p; - - pos.y = 1.0f-pos.y; - - pos.x *= m_ddsdRenderTarget.dwWidth; - pos.y *= m_ddsdRenderTarget.dwHeight; - - p.x = (int)pos.x; - p.y = (int)pos.y; - ClientToScreen(m_hWnd, &p); - - SetCursorPos(p.x, p.y); -} - -// Choosing the type of cursor for the mouse. - -void CD3DApplication::SetMouseType(D3DMouse type) -{ - HCURSOR hc; - - if ( type == D3DMOUSEHAND ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORHAND)); - } - else if ( type == D3DMOUSECROSS ) - { - hc = LoadCursor(NULL, IDC_CROSS); - } - else if ( type == D3DMOUSEEDIT ) - { - hc = LoadCursor(NULL, IDC_IBEAM); - } - else if ( type == D3DMOUSENO ) - { - hc = LoadCursor(NULL, IDC_NO); - } - else if ( type == D3DMOUSEMOVE ) - { - hc = LoadCursor(NULL, IDC_SIZEALL); - } - else if ( type == D3DMOUSEMOVEH ) - { - hc = LoadCursor(NULL, IDC_SIZEWE); - } - else if ( type == D3DMOUSEMOVEV ) - { - hc = LoadCursor(NULL, IDC_SIZENS); - } - else if ( type == D3DMOUSEMOVED ) - { - hc = LoadCursor(NULL, IDC_SIZENESW); - } - else if ( type == D3DMOUSEMOVEI ) - { - hc = LoadCursor(NULL, IDC_SIZENWSE); - } - else if ( type == D3DMOUSEWAIT ) - { - hc = LoadCursor(NULL, IDC_WAIT); - } - else if ( type == D3DMOUSESCROLLL ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLL)); - } - else if ( type == D3DMOUSESCROLLR ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLR)); - } - else if ( type == D3DMOUSESCROLLU ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLU)); - } - else if ( type == D3DMOUSESCROLLD ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLD)); - } - else if ( type == D3DMOUSETARGET ) - { - hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORTARGET)); - } - else - { - hc = LoadCursor(NULL, IDC_ARROW); - } - - if ( hc != NULL ) - { - SetCursor(hc); - } -} - -// Choice of mode for the mouse. - -void CD3DApplication::SetNiceMouse(bool bNice) -{ - if ( bNice == m_bNiceMouse ) return; - m_bNiceMouse = bNice; - - if ( m_bNiceMouse ) - { - ShowCursor(false); // hides the ugly windows mouse - SetCursor(NULL); - } - else - { - ShowCursor(true); // shows the ugly windows mouse - SetCursor(LoadCursor(NULL, IDC_ARROW)); - } -} - -// Whether to use the mouse pretty shaded. - -bool CD3DApplication::RetNiceMouse() -{ - if ( m_pDeviceInfo->bWindowed ) return false; - if ( !m_pDeviceInfo->bHardware ) return false; - - return m_bNiceMouse; -} - -// Indicates whether it is possible to use the mouse pretty shaded. - -bool CD3DApplication::RetNiceMouseCap() -{ - if ( m_pDeviceInfo->bWindowed ) return false; - if ( !m_pDeviceInfo->bHardware ) return false; - - return true; -} - - -// Static msg handler which passes messages to the application class. - -LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) -{ - if ( g_pD3DApp != 0 ) - { - Event event; - short move; - - ZeroMemory(&event, sizeof(Event)); - -#if 0 - if ( uMsg == WM_KEYDOWN || - uMsg == WM_CHAR || - uMsg == WM_XBUTTONDOWN || - uMsg == WM_XBUTTONUP ) - { - char s[100]; - sprintf(s, "event: %d %d %d\n", uMsg, wParam, lParam); - OutputDebugString(s); - } -#endif - - if ( uMsg == WM_LBUTTONDOWN ) event.event = EVENT_LBUTTONDOWN; - if ( uMsg == WM_RBUTTONDOWN ) event.event = EVENT_RBUTTONDOWN; - if ( uMsg == WM_LBUTTONUP ) event.event = EVENT_LBUTTONUP; - if ( uMsg == WM_RBUTTONUP ) event.event = EVENT_RBUTTONUP; - if ( uMsg == WM_MOUSEMOVE ) event.event = EVENT_MOUSEMOVE; - if ( uMsg == WM_KEYDOWN ) event.event = EVENT_KEYDOWN; - if ( uMsg == WM_KEYUP ) event.event = EVENT_KEYUP; - if ( uMsg == WM_CHAR ) event.event = EVENT_CHAR; - - if ( uMsg == WM_XBUTTONUP ) - { - if ( (wParam>>16) == XBUTTON1 ) event.event = EVENT_HYPER_PREV; - if ( (wParam>>16) == XBUTTON2 ) event.event = EVENT_HYPER_NEXT; - } - - event.param = wParam; - event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x); - event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y); - event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z); - event.keyState = g_pD3DApp->m_keyState; - - if ( uMsg == WM_LBUTTONDOWN || - uMsg == WM_RBUTTONDOWN || - uMsg == WM_LBUTTONUP || - uMsg == WM_RBUTTONUP || - uMsg == WM_MOUSEMOVE ) // mouse event? - { - event.pos = g_pD3DApp->ConvPosToInterface(hWnd, lParam); - g_pD3DApp->m_mousePos = event.pos; - g_pD3DApp->m_pD3DEngine->SetMousePos(event.pos); - } - - if ( uMsg == WM_MOUSEWHEEL ) // mouse wheel? - { - event.event = EVENT_KEYDOWN; - event.pos = g_pD3DApp->m_mousePos; - move = HIWORD(wParam); - if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP; - if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN; - } - if ( g_pD3DApp->m_mshMouseWheel != 0 && - uMsg == g_pD3DApp->m_mshMouseWheel ) // Logitech mouse wheel? - { - event.event = EVENT_KEYDOWN; - event.pos = g_pD3DApp->m_mousePos; - move = LOWORD(wParam); - if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP; - if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN; - } - - if ( event.event == EVENT_KEYDOWN || - event.event == EVENT_KEYUP || - event.event == EVENT_CHAR ) - { - if ( event.param == 0 ) - { - event.event = EVENT_NULL; - } - } - - if ( g_pD3DApp->m_pRobotMain != 0 && event.event != 0 ) - { - g_pD3DApp->m_pRobotMain->EventProcess(event); -//? if ( !g_pD3DApp->RetNiceMouse() ) -//? { -//? g_pD3DApp->SetMouseType(g_pD3DApp->m_pD3DEngine->RetMouseType()); -//? } - } - if ( g_pD3DApp->m_pD3DEngine != 0 ) - { - g_pD3DApp->m_pD3DEngine->MsgProc( hWnd, uMsg, wParam, lParam ); - } - return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam ); - } - - return DefWindowProc( hWnd, uMsg, wParam, lParam ); -} - - -// Minimal message proc function for the about box. - -BOOL CALLBACK AboutProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM ) -{ - if( WM_COMMAND == uMsg ) - if( IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam) ) - EndDialog( hWnd, TRUE ); - - return WM_INITDIALOG == uMsg ? TRUE : FALSE; -} - - - -// Ignore keypresses. - -void CD3DApplication::FlushPressKey() -{ - m_keyState = 0; - m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); - m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); -} - -// Resets the default keys. - -void CD3DApplication::ResetKey() -{ - int i; - - for ( i=0 ; i<50 ; i++ ) - { - m_key[i][0] = 0; - m_key[i][1] = 0; - } - m_key[KEYRANK_LEFT ][0] = VK_LEFT; - m_key[KEYRANK_RIGHT ][0] = VK_RIGHT; - m_key[KEYRANK_UP ][0] = VK_UP; - m_key[KEYRANK_DOWN ][0] = VK_DOWN; - m_key[KEYRANK_GUP ][0] = VK_SHIFT; - m_key[KEYRANK_GDOWN ][0] = VK_CONTROL; - m_key[KEYRANK_CAMERA ][0] = VK_SPACE; - m_key[KEYRANK_CAMERA ][1] = VK_BUTTON2; - m_key[KEYRANK_DESEL ][0] = VK_NUMPAD0; - m_key[KEYRANK_DESEL ][1] = VK_BUTTON6; - m_key[KEYRANK_ACTION ][0] = VK_RETURN; - m_key[KEYRANK_ACTION ][1] = VK_BUTTON1; - m_key[KEYRANK_NEAR ][0] = VK_ADD; - m_key[KEYRANK_NEAR ][1] = VK_BUTTON5; - m_key[KEYRANK_AWAY ][0] = VK_SUBTRACT; - m_key[KEYRANK_AWAY ][1] = VK_BUTTON4; - m_key[KEYRANK_NEXT ][0] = VK_TAB; - m_key[KEYRANK_NEXT ][1] = VK_BUTTON3; - m_key[KEYRANK_HUMAN ][0] = VK_HOME; - m_key[KEYRANK_HUMAN ][1] = VK_BUTTON7; - m_key[KEYRANK_QUIT ][0] = VK_ESCAPE; - m_key[KEYRANK_HELP ][0] = VK_F1; - m_key[KEYRANK_PROG ][0] = VK_F2; - m_key[KEYRANK_CBOT ][0] = VK_F3; - m_key[KEYRANK_VISIT ][0] = VK_DECIMAL; - m_key[KEYRANK_SPEED10][0] = VK_F4; - m_key[KEYRANK_SPEED15][0] = VK_F5; - m_key[KEYRANK_SPEED20][0] = VK_F6; -// m_key[KEYRANK_SPEED30][0] = VK_F7; -} - -// Modifies a button. - -void CD3DApplication::SetKey(int keyRank, int option, int key) -{ - if ( keyRank < 0 || - keyRank >= 50 ) return; - - if ( option < 0 || - option >= 2 ) return; - - m_key[keyRank][option] = key; -} - -// Gives a hint. - -int CD3DApplication::RetKey(int keyRank, int option) -{ - if ( keyRank < 0 || - keyRank >= 50 ) return 0; - - if ( option < 0 || - option >= 2 ) return 0; - - return m_key[keyRank][option]; -} - - - -// Use the joystick or keyboard. - -void CD3DApplication::SetJoystick(bool bEnable) -{ - m_bJoystick = bEnable; - - if ( m_bJoystick ) // joystick ? - { - if ( !InitDirectInput(m_instance, m_hWnd) ) // initialise joystick - { - m_bJoystick = false; - } - else - { - SetAcquire(true); - SetTimer(m_hWnd, 0, 1000/30, NULL); - } - } - else // keyboard? - { - KillTimer(m_hWnd, 0); - SetAcquire(false); - FreeDirectInput(); - } -} - -bool CD3DApplication::RetJoystick() -{ - return m_bJoystick; -} - - -// Message handling function. - -LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, - LPARAM lParam ) -{ - HRESULT hr; - DIJOYSTATE js; - int i; - - // The F10 key sends another message to activate - // menu in standard Windows applications! - if ( uMsg == WM_SYSKEYDOWN && wParam == VK_F10 ) - { - uMsg = WM_KEYDOWN; - } - if ( uMsg == WM_SYSKEYUP && wParam == VK_F10 ) - { - uMsg = WM_KEYUP; - } - - // Mange event "menu" sent by Alt or F10. - if ( uMsg == WM_SYSCOMMAND && wParam == SC_KEYMENU ) - { - return 0; - } - - if ( uMsg == WM_KEYDOWN || uMsg == WM_KEYUP ) - { - if ( GetKeyState(VK_SHIFT) & 0x8000 ) - { - m_keyState |= KS_SHIFT; - } - else - { - m_keyState &= ~KS_SHIFT; - } - - if ( GetKeyState(VK_CONTROL) & 0x8000 ) - { - m_keyState |= KS_CONTROL; - } - else - { - m_keyState &= ~KS_CONTROL; - } - } - - switch( uMsg ) - { - case WM_KEYDOWN: - if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 1.0f; - if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 1.0f; - if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = -1.0f; - if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = -1.0f; - if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = -1.0f; - if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = -1.0f; - if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 1.0f; - if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 1.0f; - if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 1.0f; - if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 1.0f; - if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = -1.0f; - if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = -1.0f; - if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState |= KS_NUMPLUS; - if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState |= KS_NUMPLUS; - if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState |= KS_NUMMINUS; - if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState |= KS_NUMMINUS; - if ( wParam == VK_PRIOR ) m_keyState |= KS_PAGEUP; - if ( wParam == VK_NEXT ) m_keyState |= KS_PAGEDOWN; -//? if ( wParam == VK_SHIFT ) m_keyState |= KS_SHIFT; -//? if ( wParam == VK_CONTROL ) m_keyState |= KS_CONTROL; - if ( wParam == VK_NUMPAD8 ) m_keyState |= KS_NUMUP; - if ( wParam == VK_NUMPAD2 ) m_keyState |= KS_NUMDOWN; - if ( wParam == VK_NUMPAD4 ) m_keyState |= KS_NUMLEFT; - if ( wParam == VK_NUMPAD6 ) m_keyState |= KS_NUMRIGHT; - break; - - case WM_KEYUP: - if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 0.0f; - if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 0.0f; - if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = 0.0f; - if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = 0.0f; - if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = 0.0f; - if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = 0.0f; - if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 0.0f; - if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 0.0f; - if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 0.0f; - if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 0.0f; - if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = 0.0f; - if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = 0.0f; - if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState &= ~KS_NUMPLUS; - if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState &= ~KS_NUMPLUS; - if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState &= ~KS_NUMMINUS; - if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState &= ~KS_NUMMINUS; - if ( wParam == VK_PRIOR ) m_keyState &= ~KS_PAGEUP; - if ( wParam == VK_NEXT ) m_keyState &= ~KS_PAGEDOWN; -//? if ( wParam == VK_SHIFT ) m_keyState &= ~KS_SHIFT; -//? if ( wParam == VK_CONTROL ) m_keyState &= ~KS_CONTROL; - if ( wParam == VK_NUMPAD8 ) m_keyState &= ~KS_NUMUP; - if ( wParam == VK_NUMPAD2 ) m_keyState &= ~KS_NUMDOWN; - if ( wParam == VK_NUMPAD4 ) m_keyState &= ~KS_NUMLEFT; - if ( wParam == VK_NUMPAD6 ) m_keyState &= ~KS_NUMRIGHT; - break; - - case WM_LBUTTONDOWN: - m_keyState |= KS_MLEFT; - break; - - case WM_RBUTTONDOWN: - m_keyState |= KS_MRIGHT; - break; - - case WM_LBUTTONUP: - m_keyState &= ~KS_MLEFT; - break; - - case WM_RBUTTONUP: - m_keyState &= ~KS_MRIGHT; - break; - - case WM_PAINT: - // Handle paint messages when the app is not ready - if( m_pFramework && !m_bReady ) - { - if( m_pDeviceInfo->bWindowed ) - m_pFramework->ShowFrame(); - else - m_pFramework->FlipToGDISurface( true ); - } - break; - - case WM_MOVE: - // If in windowed mode, move the Framework's window - if( m_pFramework && m_bActive && m_bReady && m_pDeviceInfo->bWindowed ) - m_pFramework->Move( (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) ); - break; - - case WM_SIZE: - // Check to see if we are losing our window... - if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam ) - { - m_bActive = false; - } - else - { - m_bActive = true; - } -//? char s[100]; -//? sprintf(s, "WM_SIZE %d %d %d\n", m_bActive, m_bReady, m_pDeviceInfo->bWindowed); -//? OutputDebugString(s); - - // A new window size will require a new backbuffer - // size, so the 3D structures must be changed accordingly. - if( m_bActive && m_bReady && m_pDeviceInfo->bWindowed ) - { - m_bReady = false; - -//? OutputDebugString("WM_SIZE Change3DEnvironment\n"); - if( FAILED( hr = Change3DEnvironment() ) ) - return 0; - - m_bReady = true; - } - break; - - case WM_TIMER: - if ( m_bActivateApp && m_bJoystick ) - { - if ( UpdateInputState(js) ) - { - m_axeJoy.x = js.lX/1000.0f+js.lRz/1000.0f; // tourner - m_axeJoy.y = -js.lY/1000.0f; // avancer - m_axeJoy.z = -js.rglSlider[0]/1000.0f; // monter - - m_axeJoy.x = Math::Neutral(m_axeJoy.x, 0.2f); - m_axeJoy.y = Math::Neutral(m_axeJoy.y, 0.2f); - m_axeJoy.z = Math::Neutral(m_axeJoy.z, 0.2f); - -//? char s[100]; -//? sprintf(s, "x=%d y=%d z=% x=%d y=%d z=%d\n", js.lX,js.lY,js.lZ,js.lRx,js.lRy,js.lRz); -//? OutputDebugString(s); - - for ( i=0 ; i<32 ; i++ ) - { - if ( js.rgbButtons[i] != 0 && !m_bJoyButton[i] ) - { - m_bJoyButton[i] = true; - PostMessage(m_hWnd, WM_KEYDOWN, VK_BUTTON1+i, 0); - } - if ( js.rgbButtons[i] == 0 && m_bJoyButton[i] ) - { - m_bJoyButton[i] = false; - PostMessage(m_hWnd, WM_KEYUP, VK_BUTTON1+i, 0); - } - } - } - else - { - OutputDebugString("UpdateInputState error\n"); - } - } - break; - - case WM_ACTIVATE: - if( LOWORD(wParam) == WA_INACTIVE ) - { - m_bActivateApp = false; - } - else - { - m_bActivateApp = true; - } - - if ( m_bActivateApp && m_bJoystick ) - { - SetAcquire(true); // re-enables the joystick - } - break; - - case MM_MCINOTIFY: - if ( wParam == MCI_NOTIFY_SUCCESSFUL ) - { - OutputDebugString("Event MM_MCINOTIFY\n"); - m_pSound->SuspendMusic(); - m_pSound->RestartMusic(); - } - break; - - case WM_SETCURSOR: - // Prevent a cursor in fullscreen mode - if( m_bActive && m_bReady && !m_pDeviceInfo->bWindowed ) - { -//? SetCursor(NULL); - return 1; - } - break; - - case WM_ENTERMENULOOP: - // Pause the app when menus are displayed - Pause(true); - break; - case WM_EXITMENULOOP: - Pause(false); - break; - - case WM_ENTERSIZEMOVE: - // Halt frame movement while the app is sizing or moving - m_pD3DEngine->TimeEnterGel(); - break; - case WM_EXITSIZEMOVE: - m_pD3DEngine->TimeExitGel(); - break; - - case WM_NCHITTEST: - // Prevent the user from selecting the menu in fullscreen mode - if( !m_pDeviceInfo->bWindowed ) - return HTCLIENT; - - break; - - case WM_POWERBROADCAST: - switch( wParam ) - { - case PBT_APMQUERYSUSPEND: - // At this point, the app should save any data for open - // network connections, files, etc.., and prepare to go into - // a suspended mode. - return OnQuerySuspend( (DWORD)lParam ); - - case PBT_APMRESUMESUSPEND: - // At this point, the app should recover any data, network - // connections, files, etc.., and resume running from when - // the app was suspended. - return OnResumeSuspend( (DWORD)lParam ); - } - break; - - case WM_SYSCOMMAND: - // Prevent moving/sizing and power loss in fullscreen mode - switch( wParam ) - { - case SC_MOVE: - case SC_SIZE: - case SC_MAXIMIZE: - case SC_MONITORPOWER: - if( false == m_pDeviceInfo->bWindowed ) - return 1; - break; - } - break; - - case WM_COMMAND: - switch( LOWORD(wParam) ) - { - case IDM_CHANGEDEVICE: - // Display the device-selection dialog box. - if( m_bActive && m_bReady ) - { - Pause(true); - - if( SUCCEEDED( D3DEnum_UserChangeDevice( &m_pDeviceInfo ) ) ) - { - if( FAILED( hr = Change3DEnvironment() ) ) - return 0; - } - Pause(false); - } - return 0; - - case IDM_ABOUT: - // Display the About box - Pause(true); - DialogBox( (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ), - MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutProc ); - Pause(false); - return 0; - - case IDM_EXIT: - // Recieved key/menu command to exit app - SendMessage( hWnd, WM_CLOSE, 0, 0 ); - return 0; - } - break; - - case WM_GETMINMAXINFO: - ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; - ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; - break; - - case WM_CLOSE: - DestroyWindow( hWnd ); - return 0; - - case WM_DESTROY: - Cleanup3DEnvironment(); - PostQuitMessage(0); - return 0; - } - - return DefWindowProc( hWnd, uMsg, wParam, lParam ); -} - - -// Enumeration function to report valid pixel formats for z-buffers. - -HRESULT WINAPI EnumZBufferFormatsCallback(DDPIXELFORMAT* pddpf, - VOID* pContext) -{ - DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext; - - char s[100]; - sprintf(s, "EnumZBufferFormatsCallback %d\n", pddpf->dwRGBBitCount); - OutputDebugString(s); - - if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount ) - { - (*pddpfOut) = (*pddpf); - return D3DENUMRET_CANCEL; - } - - return D3DENUMRET_OK; -} - -// Internal function called by Create() to make and attach a zbuffer -// to the renderer. - -HRESULT CD3DApplication::CreateZBuffer(GUID* pDeviceGUID) -{ - HRESULT hr; - - // Check if the device supports z-bufferless hidden surface removal. If so, - // we don't really need a z-buffer - D3DDEVICEDESC7 ddDesc; - m_pD3DDevice->GetCaps( &ddDesc ); - if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) - return S_OK; - - // Get z-buffer dimensions from the render target - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - m_pddsRenderTarget->GetSurfaceDesc( &ddsd ); - - // Setup the surface desc for the z-buffer. - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; - ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; - ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized - - // Get an appropiate pixel format from enumeration of the formats. On the - // first pass, we look for a zbuffer dpeth which is equal to the frame - // buffer depth (as some cards unfornately require this). - m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, - (VOID*)&ddsd.ddpfPixelFormat ); - if( 0 == ddsd.ddpfPixelFormat.dwSize ) - { - // Try again, just accepting any 16-bit zbuffer - ddsd.ddpfPixelFormat.dwRGBBitCount = 16; - m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, - (VOID*)&ddsd.ddpfPixelFormat ); - - if( 0 == ddsd.ddpfPixelFormat.dwSize ) - { - DEBUG_MSG( _T("Device doesn't support requested zbuffer format") ); - return D3DFWERR_NOZBUFFER; - } - } - - // Create and attach a z-buffer - if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsDepthBuffer, NULL ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") ); - if( hr != DDERR_OUTOFVIDEOMEMORY ) - return D3DFWERR_NOZBUFFER; - DEBUG_MSG( _T("Error: Out of video memory") ); - return DDERR_OUTOFVIDEOMEMORY; - } - - if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsDepthBuffer ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") ); - return D3DFWERR_NOZBUFFER; - } - - // Finally, this call rebuilds internal structures - if( FAILED( m_pD3DDevice->SetRenderTarget( m_pddsRenderTarget, 0L ) ) ) - { - DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") ); - return D3DFWERR_NOZBUFFER; - } - - return S_OK; -} - -// Initializes the sample framework, then calls the app-specific function -// to initialize device specific objects. This code is structured to -// handled any errors that may occur duing initialization. - -HRESULT CD3DApplication::Initialize3DEnvironment() -{ - HRESULT hr; - DDSCAPS2 ddsCaps2; - DWORD dwFrameworkFlags = 0L; - DWORD dwTotal; - DWORD dwFree; - - dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L ); - dwFrameworkFlags |= ( m_pDeviceInfo->bStereo ? D3DFW_STEREO : 0L ); - dwFrameworkFlags |= ( m_bAppUseZBuffer ? D3DFW_ZBUFFER : 0L ); - - // Initialize the D3D framework - if( SUCCEEDED( hr = m_pFramework->Initialize( m_hWnd, - m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID, - &m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) ) - { - m_pDD = m_pFramework->GetDirectDraw(); - m_pD3D = m_pFramework->GetDirect3D(); - m_pD3DDevice = m_pFramework->GetD3DDevice(); - - m_pD3DEngine->SetD3DDevice(m_pD3DDevice); - - m_pddsRenderTarget = m_pFramework->GetRenderSurface(); - - m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget); - m_pddsRenderTarget->GetSurfaceDesc( &m_ddsdRenderTarget ); - - // Request the amount of video memory. - ZeroMemory(&ddsCaps2, sizeof(ddsCaps2)); - ddsCaps2.dwCaps = DDSCAPS_TEXTURE; - dwTotal = 0; - hr = m_pDD->GetAvailableVidMem(&ddsCaps2, &dwTotal, &dwFree); - m_vidMemTotal = dwTotal; - - // Let the app run its startup code which creates the 3d scene. - if( SUCCEEDED( hr = m_pD3DEngine->InitDeviceObjects() ) ) - { -//? CreateZBuffer(m_pDeviceInfo->pDeviceGUID); - return S_OK; - } - else - { - DeleteDeviceObjects(); - m_pFramework->DestroyObjects(); - } - } - - // If we get here, the first initialization passed failed. If that was with a - // hardware device, try again using a software rasterizer instead. - if( m_pDeviceInfo->bHardware ) - { - // Try again with a software rasterizer - DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE ); - D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY ); - return Initialize3DEnvironment(); - } - - return hr; -} - - -// Handles driver, device, and/or mode changes for the app. - -HRESULT CD3DApplication::Change3DEnvironment() -{ -#if 0 - HRESULT hr; - static bool bOldWindowedState = true; - static DWORD dwSavedStyle; - static RECT rcSaved; - - // Release all scene objects that will be re-created for the new device - DeleteDeviceObjects(); - - // Release framework objects, so a new device can be created - if( FAILED( hr = m_pFramework->DestroyObjects() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); - return hr; - } - - // Check if going from fullscreen to windowed mode, or vice versa. - if( bOldWindowedState != m_pDeviceInfo->bWindowed ) - { - if( m_pDeviceInfo->bWindowed ) - { - // Coming from fullscreen mode, so restore window properties - SetWindowLong( m_hWnd, GWL_STYLE, dwSavedStyle ); - SetWindowPos( m_hWnd, HWND_NOTOPMOST, rcSaved.left, rcSaved.top, - ( rcSaved.right - rcSaved.left ), - ( rcSaved.bottom - rcSaved.top ), SWP_SHOWWINDOW ); - } - else - { - // Going to fullscreen mode, save/set window properties as needed - dwSavedStyle = GetWindowLong( m_hWnd, GWL_STYLE ); - GetWindowRect( m_hWnd, &rcSaved ); - SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE ); - } - - bOldWindowedState = m_pDeviceInfo->bWindowed; - } - - // Inform the framework class of the driver change. It will internally - // re-create valid surfaces, a d3ddevice, etc. - if( FAILED( hr = Initialize3DEnvironment() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); - return hr; - } - - return S_OK; -#else - HRESULT hr; - - // Release all scene objects that will be re-created for the new device - DeleteDeviceObjects(); - - // Release framework objects, so a new device can be created - if( FAILED( hr = m_pFramework->DestroyObjects() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); - return hr; - } - - if( m_pDeviceInfo->bWindowed ) - { - SetWindowPos(m_hWnd, HWND_NOTOPMOST, 10, 10, WINDOW_DX, WINDOW_DY, SWP_SHOWWINDOW); - } - - // Inform the framework class of the driver change. It will internally - // re-create valid surfaces, a d3ddevice, etc. - if( FAILED( hr = Initialize3DEnvironment() ) ) - { - DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); - SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); - return hr; - } - - m_pD3DEngine->ChangeLOD(); - - if( m_pDeviceInfo->bWindowed ) - { - SetNiceMouse(false); // hides the ugly windows mouse - } - - return S_OK; -#endif -} - - - -// Evolved throughout the game - -void CD3DApplication::StepSimul(float rTime) -{ - Event event; - - if ( m_pRobotMain == 0 ) return; - - ZeroMemory(&event, sizeof(Event)); - event.event = EVENT_FRAME; // funny bug release "Maximize speed"! - event.rTime = rTime; - event.axeX = AxeLimit(m_axeKey.x + m_axeJoy.x); - event.axeY = AxeLimit(m_axeKey.y + m_axeJoy.y); - event.axeZ = AxeLimit(m_axeKey.z + m_axeJoy.z); - event.keyState = m_keyState; - -//?char s[100]; -//?sprintf(s, "StepSimul %.3f\n", event.rTime); -//?OutputDebugString(s); - m_pRobotMain->EventProcess(event); -} - - -// Draws the scene. - -HRESULT CD3DApplication::Render3DEnvironment() -{ - HRESULT hr; - float rTime; - - // Check the cooperative level before rendering - if( FAILED( hr = m_pDD->TestCooperativeLevel() ) ) - { - switch( hr ) - { - case DDERR_EXCLUSIVEMODEALREADYSET: - case DDERR_NOEXCLUSIVEMODE: - OutputDebugString("DDERR_EXCLUSIVEMODEALREADYSET\n"); - // Do nothing because some other app has exclusive mode - return S_OK; - - case DDERR_WRONGMODE: - OutputDebugString("DDERR_WRONGMODE\n"); - // The display mode changed on us. Resize accordingly - if( m_pDeviceInfo->bWindowed ) - return Change3DEnvironment(); - break; - } - return hr; - } - - // Get the relative time, in seconds - rTime = m_pD3DEngine->TimeGet(); - if ( rTime > MAX_STEP ) rTime = MAX_STEP; // never more than 0.5s! - m_aTime += rTime; - -#if !USE_THREAD - if( FAILED( hr = m_pD3DEngine->FrameMove(rTime) ) ) - return hr; - - // FrameMove (animate) the scene - StepSimul(rTime); -#endif - - // Render the scene. - if( FAILED( hr = m_pD3DEngine->Render() ) ) - return hr; - - DrawSuppl(); - - // Show the frame rate, etc. - if( m_bShowStats ) - ShowStats(); - - // Show the frame on the primary surface. - if( FAILED( hr = m_pFramework->ShowFrame() ) ) - { - if( DDERR_SURFACELOST != hr ) - return hr; - - m_pFramework->RestoreSurfaces(); - m_pD3DEngine->RestoreSurfaces(); - } - - return S_OK; -} - - -// Cleanup scene objects - -VOID CD3DApplication::Cleanup3DEnvironment() -{ - m_bActive = false; - m_bReady = false; - - if( m_pFramework ) - { - DeleteDeviceObjects(); - SAFE_DELETE( m_pFramework ); - - m_pD3DEngine->FinalCleanup(); - } - - D3DEnum_FreeResources(); -//? FreeDirectInput(); -} - -// Called when the app is exitting, or the device is being changed, -// this function deletes any device dependant objects. - -VOID CD3DApplication::DeleteDeviceObjects() -{ - if( m_pFramework ) - { - m_pD3DEngine->DeleteDeviceObjects(); - SAFE_RELEASE( m_pddsDepthBuffer ); - } -} - - - -// Called in to toggle the pause state of the app. This function -// brings the GDI surface to the front of the display, so drawing -// output like message boxes and menus may be displayed. - -VOID CD3DApplication::Pause( bool bPause ) -{ - static DWORD dwAppPausedCount = 0L; - - dwAppPausedCount += ( bPause ? +1 : -1 ); - m_bReady = ( dwAppPausedCount ? false : true ); - - // Handle the first pause request (of many, nestable pause requests) - if( bPause && ( 1 == dwAppPausedCount ) ) - { - // Get a surface for the GDI - if( m_pFramework ) - m_pFramework->FlipToGDISurface( true ); - - // Stop the scene from animating - m_pD3DEngine->TimeEnterGel(); - } - - if( 0 == dwAppPausedCount ) - { - // Restart the scene - m_pD3DEngine->TimeExitGel(); - } -} - - -// Called when the app receives a PBT_APMQUERYSUSPEND message, meaning -// the computer is about to be suspended. At this point, the app should -// save any data for open network connections, files, etc.., and prepare -// to go into a suspended mode. - -LRESULT CD3DApplication::OnQuerySuspend( DWORD dwFlags ) -{ - OutputDebugString("OnQuerySuspend\n"); - Pause(true); - return true; -} - - -// Called when the app receives a PBT_APMRESUMESUSPEND message, meaning -// the computer has just resumed from a suspended state. At this point, -// the app should recover any data, network connections, files, etc.., -// and resume running from when the app was suspended. - -LRESULT CD3DApplication::OnResumeSuspend( DWORD dwData ) -{ - OutputDebugString("OnResumeSuspend\n"); - Pause(false); - return true; -} - - -// Draw all the additional graphic elements. - -void CD3DApplication::DrawSuppl() -{ - HDC hDC; - Math::Point p1, p2; - POINT list[3]; - RECT rect; - HPEN hPen; - HGDIOBJ old; - Math::Point pos; - float d; - int nbOut; - - if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return; - - // Displays the selection rectangle. - if ( m_pD3DEngine->GetHilite(p1, p2) ) - { - nbOut = 0; - if ( p1.x < 0.0f || p1.x > 1.0f ) nbOut ++; - if ( p1.y < 0.0f || p1.y > 1.0f ) nbOut ++; - if ( p2.x < 0.0f || p2.x > 1.0f ) nbOut ++; - if ( p2.y < 0.0f || p2.y > 1.0f ) nbOut ++; - if ( nbOut <= 2 ) - { -#if 0 - time = Math::Mod(m_aTime, 0.5f); - if ( time < 0.25f ) d = time*4.0f; - else d = (2.0f-time*4.0f); -#endif -#if 0 - time = Math::Mod(m_aTime, 0.5f); - if ( time < 0.4f ) d = time/0.4f; - else d = 1.0f-(time-0.4f)/0.1f; -#endif -#if 1 - d = 0.5f+sinf(m_aTime*6.0f)*0.5f; -#endif - d *= (p2.x-p1.x)*0.1f; - p1.x += d; - p1.y += d; - p2.x -= d; - p2.y -= d; - - hPen = CreatePen(PS_SOLID, 1, RGB(255,255,0)); // yellow - old = SelectObject(hDC, hPen); - - rect.left = (int)(p1.x*m_ddsdRenderTarget.dwWidth); - rect.right = (int)(p2.x*m_ddsdRenderTarget.dwWidth); - rect.top = (int)((1.0f-p2.y)*m_ddsdRenderTarget.dwHeight); - rect.bottom = (int)((1.0f-p1.y)*m_ddsdRenderTarget.dwHeight); - - list[0].x = rect.left; - list[0].y = rect.top+(rect.bottom-rect.top)/5; - list[1].x = rect.left; - list[1].y = rect.top; - list[2].x = rect.left+(rect.right-rect.left)/5; - list[2].y = rect.top; - Polyline(hDC, list, 3); - - list[0].x = rect.right; - list[0].y = rect.top+(rect.bottom-rect.top)/5; - list[1].x = rect.right; - list[1].y = rect.top; - list[2].x = rect.right+(rect.left-rect.right)/5; - list[2].y = rect.top; - Polyline(hDC, list, 3); - - list[0].x = rect.left; - list[0].y = rect.bottom+(rect.top-rect.bottom)/5; - list[1].x = rect.left; - list[1].y = rect.bottom; - list[2].x = rect.left+(rect.right-rect.left)/5; - list[2].y = rect.bottom; - Polyline(hDC, list, 3); - - list[0].x = rect.right; - list[0].y = rect.bottom+(rect.top-rect.bottom)/5; - list[1].x = rect.right; - list[1].y = rect.bottom; - list[2].x = rect.right+(rect.left-rect.right)/5; - list[2].y = rect.bottom; - Polyline(hDC, list, 3); - - if ( old != 0 ) SelectObject(hDC, old); - DeleteObject(hPen); - } - } - - m_pddsRenderTarget->ReleaseDC(hDC); -} - -// Shows frame rate and dimensions of the rendering device. - -VOID CD3DApplication::ShowStats() -{ - static FLOAT fFPS = 0.0f; - static FLOAT fLastTime = 0.0f; - static DWORD dwFrames = 0L; - - // Keep track of the time lapse and frame count - FLOAT fTime = timeGetTime() * 0.001f; // Get current time in seconds - ++dwFrames; - - // Update the frame rate once per second - if( fTime - fLastTime > 1.0f ) - { - fFPS = dwFrames / (fTime - fLastTime); - fLastTime = fTime; - dwFrames = 0L; - } - - int t = m_pD3DEngine->RetStatisticTriangle(); - - // Setup the text buffer to write out dimensions - TCHAR buffer[100]; - sprintf( buffer, _T("%7.02f fps T=%d (%dx%dx%d)"), fFPS, t, - m_ddsdRenderTarget.dwWidth, m_ddsdRenderTarget.dwHeight, - m_ddsdRenderTarget.ddpfPixelFormat.dwRGBBitCount ); - OutputText( 400, 2, buffer ); - - int x, y, i; - if ( m_pD3DEngine->GetSpriteCoord(x, y) ) - { - OutputText( x, y, "+" ); - } - - for ( i=0 ; i<10 ; i++ ) - { - char* info = m_pD3DEngine->RetInfoText(i); - x = 50; - y = m_ddsdRenderTarget.dwHeight-20-i*20; - OutputText( x, y, info ); - } -} - - -// Draws text on the window. - -VOID CD3DApplication::OutputText( DWORD x, DWORD y, TCHAR* str ) -{ - HDC hDC; - - // Get a DC for the surface. Then, write out the buffer - if( m_pddsRenderTarget ) - { - if( SUCCEEDED( m_pddsRenderTarget->GetDC(&hDC) ) ) - { - SetTextColor( hDC, RGB(255,255,0) ); - SetBkMode( hDC, TRANSPARENT ); - ExtTextOut( hDC, x, y, 0, NULL, str, lstrlen(str), NULL ); - m_pddsRenderTarget->ReleaseDC(hDC); - } - } -} - - - - -// Defines a function that allocates memory for and initializes -// members within a BITMAPINFOHEADER structure - -PBITMAPINFO CD3DApplication::CreateBitmapInfoStruct(HBITMAP hBmp) -{ - BITMAP bmp; - PBITMAPINFO pbmi; - WORD cClrBits; - - // Retrieve the bitmap's color format, width, and height. - if ( !GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp) ) - return 0; - - // Convert the color format to a count of bits. - cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); - - if ( cClrBits == 1 ) cClrBits = 1; - else if ( cClrBits <= 4 ) cClrBits = 4; - else if ( cClrBits <= 8 ) cClrBits = 8; - else if ( cClrBits <= 16 ) cClrBits = 16; - else if ( cClrBits <= 24 ) cClrBits = 24; - else cClrBits = 32; - - // Allocate memory for the BITMAPINFO structure. (This structure - // contains a BITMAPINFOHEADER structure and an array of RGBQUAD data - // structures.) - if ( cClrBits != 24 ) - { - pbmi = (PBITMAPINFO)LocalAlloc(LPTR, - sizeof(BITMAPINFOHEADER) + - sizeof(RGBQUAD) * (2^cClrBits)); - } - // There is no RGBQUAD array for the 24-bit-per-pixel format. - else - { - pbmi = (PBITMAPINFO)LocalAlloc(LPTR, - sizeof(BITMAPINFOHEADER)); - } - - // Initialize the fields in the BITMAPINFO structure. - pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - pbmi->bmiHeader.biWidth = bmp.bmWidth; - pbmi->bmiHeader.biHeight = bmp.bmHeight; - pbmi->bmiHeader.biPlanes = bmp.bmPlanes; - pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; - if ( cClrBits < 24 ) - pbmi->bmiHeader.biClrUsed = 2^cClrBits; - - // If the bitmap is not compressed, set the BI_RGB flag. - pbmi->bmiHeader.biCompression = BI_RGB; - - // Compute the number of bytes in the array of color - // indices and store the result in biSizeImage. - pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 - * pbmi->bmiHeader.biHeight - * cClrBits; - - // Set biClrImportant to 0, indicating that all of the - // device colors are important. - pbmi->bmiHeader.biClrImportant = 0; - - return pbmi; -} - -// Defines a function that initializes the remaining structures, -// retrieves the array of palette indices, opens the file, copies -// the data, and closes the file. - -bool CD3DApplication::CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) -{ - FILE* file; // file handle - BITMAPFILEHEADER hdr; // bitmap file-header - PBITMAPINFOHEADER pbih; // bitmap info-header - LPBYTE lpBits; // memory pointer - DWORD dwTotal; // total count of bytes - - pbih = (PBITMAPINFOHEADER)pbi; - lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); - if ( !lpBits ) return false; - - // Retrieve the color table (RGBQUAD array) and the bits - // (array of palette indices) from the DIB. - if ( !GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight, - lpBits, pbi, DIB_RGB_COLORS) ) - return false; - - // Create the .BMP file. - file = fopen(pszFile, "wb"); - if ( file == NULL ) return false; - - hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" - - // Compute the size of the entire file. - hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + - pbih->biSize + pbih->biClrUsed - * sizeof(RGBQUAD) + pbih->biSizeImage); - - hdr.bfReserved1 = 0; - hdr.bfReserved2 = 0; - - // Compute the offset to the array of color indices. - hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + - pbih->biSize + pbih->biClrUsed - * sizeof (RGBQUAD); - - // Copy the BITMAPFILEHEADER into the .BMP file. - fwrite(&hdr, sizeof(BITMAPFILEHEADER), 1, file); - - // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. - fwrite(pbih, sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD), 1, file); - - // Copy the array of color indices into the .BMP file. - dwTotal = pbih->biSizeImage; - fwrite(lpBits, dwTotal, 1, file); - - // Close the .BMP file. - fclose(file); - - // Free memory. - GlobalFree((HGLOBAL)lpBits); - return true; -} - -// Write a file. BMP screenshot. - -bool CD3DApplication::WriteScreenShot(char *filename, int width, int height) -{ - D3DVIEWPORT7 vp; - HDC hDC; - HDC hDCImage; - HBITMAP hb; - PBITMAPINFO info; - int dx, dy; - - m_pD3DDevice->GetViewport(&vp); - dx = vp.dwWidth; - dy = vp.dwHeight; - - if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return false; - - hDCImage = CreateCompatibleDC(hDC); - if ( hDCImage == 0 ) - { - m_pddsRenderTarget->ReleaseDC(hDC); - return false; - } - - hb = CreateCompatibleBitmap(hDC, width, height); - if ( hb == 0 ) - { - DeleteDC(hDCImage); - m_pddsRenderTarget->ReleaseDC(hDC); - return false; - } - - SelectObject(hDCImage, hb); - StretchBlt(hDCImage, 0, 0, width, height, hDC, 0, 0, dx, dy, SRCCOPY); - - info = CreateBitmapInfoStruct(hb); - if ( info == 0 ) - { - DeleteObject(hb); - DeleteDC(hDCImage); - m_pddsRenderTarget->ReleaseDC(hDC); - return false; - } - - CreateBMPFile(filename, info, hb, hDCImage); - - DeleteObject(hb); - DeleteDC(hDCImage); - m_pddsRenderTarget->ReleaseDC(hDC); - return true; -} - - -// Initializes an hDC on the rendering surface. - -bool CD3DApplication::GetRenderDC(HDC &hDC) -{ - if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return false; - return true; -} - -// Frees the hDC of the rendering surface. - -bool CD3DApplication::ReleaseRenderDC(HDC &hDC) -{ - m_pddsRenderTarget->ReleaseDC(hDC); - return true; -} - - - - -// Perform the list of all graphics devices available. -// For the device selected, lists the full screen modes -// possible. -// buf* --> nom1<0> nom2<0> <0> - -bool CD3DApplication::EnumDevices(char *bufDevices, int lenDevices, - char *bufModes, int lenModes, - int &totalDevices, int &selectDevices, - int &totalModes, int &selectModes) -{ - D3DEnum_DeviceInfo* pDeviceList; - D3DEnum_DeviceInfo* pDevice; - DDSURFACEDESC2* pddsdMode; - DWORD numDevices, device, mode; - int len; - char text[100]; - - D3DEnum_GetDevices(&pDeviceList, &numDevices); - - selectDevices = -1; - selectModes = -1; - totalModes = 0; - for( device=0 ; devicestrDesc)+1; - if ( len >= lenDevices ) break; // bufDevices full! - strcpy(bufDevices, pDevice->strDesc); - bufDevices += len; - lenDevices -= len; - - if ( pDevice == m_pDeviceInfo ) // select device ? - { - selectDevices = device; - - for( mode=0 ; modedwNumModes ; mode++ ) - { - pddsdMode = &pDevice->pddsdModes[mode]; - - sprintf(text, "%ld x %ld x %ld", - pddsdMode->dwWidth, - pddsdMode->dwHeight, - pddsdMode->ddpfPixelFormat.dwRGBBitCount); - - len = strlen(text)+1; - if ( len >= lenModes ) break; // bufModes full ! - strcpy(bufModes, text); - bufModes += len; - lenModes -= len; - - if ( mode == m_pDeviceInfo->dwCurrentMode ) // select mode ? - { - selectModes = mode; - } - } - bufModes[0] = 0; - totalModes = pDevice->dwNumModes; - } - } - bufDevices[0] = 0; - totalDevices = numDevices; - - return true; -} - -// Indicates whether it is in full screen mode. - -bool CD3DApplication::RetFullScreen() -{ - return !m_pDeviceInfo->bWindowed; -} - -// Change the graphics mode. - -bool CD3DApplication::ChangeDevice(char *deviceName, char *modeName, - bool bFull) -{ - D3DEnum_DeviceInfo* pDeviceList; - D3DEnum_DeviceInfo* pDevice; - DDSURFACEDESC2* pddsdMode; - DWORD numDevices, device, mode; - HRESULT hr; - char text[100]; - - D3DEnum_GetDevices(&pDeviceList, &numDevices); - - for( device=0 ; devicestrDesc, deviceName) == 0 ) // device found ? - { - for( mode=0 ; modedwNumModes ; mode++ ) - { - pddsdMode = &pDevice->pddsdModes[mode]; - - sprintf(text, "%ld x %ld x %ld", - pddsdMode->dwWidth, - pddsdMode->dwHeight, - pddsdMode->ddpfPixelFormat.dwRGBBitCount); - - if ( strcmp(text, modeName) == 0 ) // mode found ? - { - m_pDeviceInfo = pDevice; - pDevice->bWindowed = !bFull; - pDevice->dwCurrentMode = mode; - pDevice->ddsdFullscreenMode = pDevice->pddsdModes[mode]; - - m_bReady = false; - - if ( FAILED( hr = Change3DEnvironment() ) ) - { - return false; - } - - SetProfileString("Device", "Name", deviceName); - SetProfileString("Device", "Mode", modeName); - SetProfileInt("Device", "FullScreen", bFull); - m_bReady = true; - return true; - } - } - } - } - - return false; -} - - - -// Displays error messages in a message box. - -VOID CD3DApplication::DisplayFrameworkError( HRESULT hr, DWORD dwType ) -{ - TCHAR strMsg[512]; - - switch( hr ) - { - case D3DENUMERR_ENGINE: - lstrcpy( strMsg, _T("Could not create 3D Engine application!") ); - break; - case D3DENUMERR_ROBOT: - lstrcpy( strMsg, _T("Could not create Robot application!") ); - break; - case D3DENUMERR_NODIRECTDRAW: - lstrcpy( strMsg, _T("Could not create DirectDraw!") ); - break; - case D3DENUMERR_NOCOMPATIBLEDEVICES: - lstrcpy( strMsg, _T("Could not find any compatible Direct3D\n" - "devices.") ); - break; - case D3DENUMERR_SUGGESTREFRAST: - lstrcpy( strMsg, _T("Could not find any compatible devices.\n\n" - "Try enabling the reference rasterizer using\n" - "EnableRefRast.reg.") ); - break; - case D3DENUMERR_ENUMERATIONFAILED: - lstrcpy( strMsg, _T("Enumeration failed. Your system may be in an\n" - "unstable state and need to be rebooted") ); - break; - case D3DFWERR_INITIALIZATIONFAILED: - lstrcpy( strMsg, _T("Generic initialization error.\n\nEnable " - "debug output for detailed information.") ); - break; - case D3DFWERR_NODIRECTDRAW: - lstrcpy( strMsg, _T("No DirectDraw") ); - break; - case D3DFWERR_NODIRECT3D: - lstrcpy( strMsg, _T("No Direct3D") ); - break; - case D3DFWERR_INVALIDMODE: - lstrcpy( strMsg, _T("COLOBOT requires a 16-bit (or higher) " - "display mode\nto run in a window.\n\nPlease " - "switch your desktop settings accordingly.") ); - break; - case D3DFWERR_COULDNTSETCOOPLEVEL: - lstrcpy( strMsg, _T("Could not set Cooperative Level") ); - break; - case D3DFWERR_NO3DDEVICE: - lstrcpy( strMsg, _T("Could not create the Direct3DDevice object.") ); - - if( MSGWARN_SWITCHEDTOSOFTWARE == dwType ) - lstrcat( strMsg, _T("\nThe 3D hardware chipset may not support" - "\nrendering in the current display mode.") ); - break; - case D3DFWERR_NOZBUFFER: - lstrcpy( strMsg, _T("No ZBuffer") ); - break; - case D3DFWERR_INVALIDZBUFFERDEPTH: - lstrcpy( strMsg, _T("Invalid Z-buffer depth. Try switching modes\n" - "from 16- to 32-bit (or vice versa)") ); - break; - case D3DFWERR_NOVIEWPORT: - lstrcpy( strMsg, _T("No Viewport") ); - break; - case D3DFWERR_NOPRIMARY: - lstrcpy( strMsg, _T("No primary") ); - break; - case D3DFWERR_NOCLIPPER: - lstrcpy( strMsg, _T("No Clipper") ); - break; - case D3DFWERR_BADDISPLAYMODE: - lstrcpy( strMsg, _T("Bad display mode") ); - break; - case D3DFWERR_NOBACKBUFFER: - lstrcpy( strMsg, _T("No backbuffer") ); - break; - case D3DFWERR_NONZEROREFCOUNT: - lstrcpy( strMsg, _T("A DDraw object has a non-zero reference\n" - "count (meaning it was not properly cleaned up)." ) ); - break; - case D3DFWERR_NORENDERTARGET: - lstrcpy( strMsg, _T("No render target") ); - break; - case E_OUTOFMEMORY: - lstrcpy( strMsg, _T("Not enough memory!") ); - break; - case DDERR_OUTOFVIDEOMEMORY: - lstrcpy( strMsg, _T("There was insufficient video memory " - "to use the\nhardware device.") ); - break; - default: - lstrcpy( strMsg, _T("Generic application error.\n\nEnable " - "debug output for detailed information.") ); - } - - if( MSGERR_APPMUSTEXIT == dwType ) - { - lstrcat( strMsg, _T("\n\nCOLOBOT will now exit.") ); - MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK ); - } - else - { - if( MSGWARN_SWITCHEDTOSOFTWARE == dwType ) - lstrcat( strMsg, _T("\n\nSwitching to software rasterizer.") ); - MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK ); - } -} - - +// * 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/. + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/struct.h" +#include "old/d3dtextr.h" +#include "old/d3dengine.h" +#include "common/language.h" +#include "common/event.h" +#include "common/profile.h" +#include "common/iman.h" +#include "common/restext.h" +#include "old/math3d.h" +#include "old/joystick.h" +#include "object/robotmain.h" +#include "old/sound.h" +#include "old/d3dapp.h" + +// fix for "MSH_MOUSEWHEEL undefined" error +#ifdef UNICODE +#define MSH_MOUSEWHEEL L"MSWHEEL_ROLLMSG" +#else +#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" +#endif + + +const int AUDIO_TRACK = 13; // total number of audio tracks on the CD +const float MAX_STEP = 0.2f; // maximum time for a step + +const int WINDOW_DX = (640+6); // dimensions in windowed mode +const int WINDOW_DY = (480+25); + +#define USE_THREAD false // true does not work! +const float TIME_THREAD = 0.02f; + + + + +// Limit the use of the controls keyboard & joystick. + +float AxeLimit(float value) +{ + if ( value < -1.0f ) value = -1.0f; + if ( value > 1.0f ) value = 1.0f; + return value; +} + + +// Entry point to the program. Initializes everything, and goes into a +// message-processing loop. Idle time is used to render the scene. + +INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) +{ + Error err; + char string[100]; + + CD3DApplication d3dApp; // single instance of the application + + err = d3dApp.CheckMistery(strCmdLine); + if ( err != ERR_OK ) + { + GetResource(RES_ERR, err, string); +#if _NEWLOOK + MessageBox( NULL, string, _T("CeeBot"), MB_ICONERROR|MB_OK ); +#else + MessageBox( NULL, string, _T("COLOBOT"), MB_ICONERROR|MB_OK ); +#endif + return 0; + } + + if ( FAILED(d3dApp.Create(hInst, strCmdLine)) ) + { + return 0; + } + + return d3dApp.Run(); // execution of all +} + + +// Internal variables and function prototypes. + +enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHEDTOSOFTWARE }; + +static INT CALLBACK AboutProc( HWND, UINT, WPARAM, LPARAM ); +static LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); + +static CD3DApplication* g_pD3DApp; + + + +// Constructor. + +CD3DApplication::CD3DApplication() +{ + int i; + + m_iMan = new(CInstanceManager); + m_event = new CEvent(m_iMan); + + m_pD3DEngine = 0; + m_pRobotMain = 0; + m_pSound = 0; + m_pFramework = 0; + m_instance = 0; + m_hWnd = 0; + m_pDD = 0; + m_pD3D = 0; + m_pD3DDevice = 0; + + m_CDpath[0] = 0; + + m_pddsRenderTarget = 0; + m_pddsDepthBuffer = 0; + + m_keyState = 0; + m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); + m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); + + m_vidMemTotal = 0; + m_bActive = false; + m_bActivateApp = false; + m_bReady = false; + m_bJoystick = false; + m_aTime = 0.0f; + + for ( i=0 ; i<32 ; i++ ) + { + m_bJoyButton[i] = false; + } + +#if _NEWLOOK + m_strWindowTitle = _T("CeeBot"); +#else + m_strWindowTitle = _T("COLOBOT"); +#endif + m_bAppUseZBuffer = true; + m_bAppUseStereo = true; + m_bShowStats = false; + m_bDebugMode = false; + m_bAudioState = true; + m_bAudioTrack = true; + m_bNiceMouse = false; + m_bSetupMode = true; + m_fnConfirmDevice = 0; + + ResetKey(); + + g_pD3DApp = this; + + // Request event sent by Logitech. + m_mshMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); + + _mkdir("files\\"); +} + + +// Destructor. + +CD3DApplication::~CD3DApplication() +{ + delete m_iMan; +} + + + +// Returns the path of the CD. + +char* CD3DApplication::RetCDpath() +{ + return m_CDpath; +} + +// Reads the information in the registry. + +Error CD3DApplication::RegQuery() +{ + FILE* file = NULL; + HKEY key; + LONG i; + DWORD type, len; + char filename[100]; + +#if _NEWLOOK + #if _TEEN + i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-Teen\\Setup", + #else + i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-A\\Setup", + #endif +#else + i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\Colobot\\Setup", +#endif + 0, KEY_READ, &key); + if ( i != ERROR_SUCCESS ) return ERR_INSTALL; + + type = REG_SZ; + len = sizeof(m_CDpath); + i = RegQueryValueEx(key, "CDpath", NULL, &type, (LPBYTE)m_CDpath, &len); + if ( i != ERROR_SUCCESS || type != REG_SZ ) return ERR_INSTALL; + + filename[0] = m_CDpath[0]; + filename[1] = ':'; + filename[2] = '\\'; + filename[3] = 0; + i = GetDriveType(filename); + if ( i != DRIVE_CDROM ) return ERR_NOCD; + + strcat(filename, "install.ini"); + file = fopen(filename, "rb"); // install.ini file exist? + if ( file == NULL ) return ERR_NOCD; + fclose(file); + + return ERR_OK; +} + +// Checks for audio tracks on the CD. + +Error CD3DApplication::AudioQuery() +{ + MCI_OPEN_PARMS mciOpenParms; + MCI_STATUS_PARMS mciStatusParms; + DWORD dwReturn; + UINT deviceID; + char device[10]; + + // Open the device by specifying the device and filename. + // MCI will attempt to choose the MIDI mapper as the output port. + memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS)); + mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; + if ( m_CDpath[0] == 0 ) + { + dwReturn = mciSendCommand(NULL, + MCI_OPEN, + MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, + (DWORD)(LPVOID)&mciOpenParms); + } + else + { + device[0] = m_CDpath[0]; + device[1] = ':'; + device[2] = 0; + mciOpenParms.lpstrElementName = device; + dwReturn = mciSendCommand(NULL, + MCI_OPEN, + MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT, + (DWORD)(LPVOID)&mciOpenParms); + } + if ( dwReturn != 0 ) + { + return ERR_NOCD; + } + + // The device opened successfully; get the device ID. + deviceID = mciOpenParms.wDeviceID; + + memset(&mciStatusParms, 0, sizeof(MCI_STATUS_PARMS)); + mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; + dwReturn = mciSendCommand(deviceID, + MCI_STATUS, + MCI_WAIT|MCI_STATUS_ITEM, + (DWORD)&mciStatusParms); + if ( dwReturn != 0 ) + { + mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); + return ERR_NOCD; + } + + if ( mciStatusParms.dwReturn != AUDIO_TRACK ) + { + mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); + return ERR_NOCD; + } + + mciSendCommand(deviceID, MCI_CLOSE, 0, NULL); + return ERR_OK; +} + +// Checks for the key. + +Error CD3DApplication::CheckMistery(char *strCmdLine) +{ + if ( strstr(strCmdLine, "-debug") != 0 ) + { + m_bShowStats = true; + SetDebugMode(true); + } + + if ( strstr(strCmdLine, "-audiostate") != 0 ) + { + m_bAudioState = false; + } + + if ( strstr(strCmdLine, "-audiotrack") != 0 ) + { + m_bAudioTrack = false; + } + + m_CDpath[0] = 0; +#if _FULL + if ( strstr(strCmdLine, "-nocd") == 0 && !m_bDebugMode ) + { + Error err; + + err = RegQuery(); + if ( err != ERR_OK ) return err; + + //?err = AudioQuery(); + //?if ( err != ERR_OK ) return err; + } +#endif +#if _SCHOOL & _EDU + if ( strstr(strCmdLine, "-nosetup") != 0 ) + { + m_bSetupMode = false; + } + m_bAudioTrack = false; +#endif +#if _SCHOOL & _PERSO + Error err = RegQuery(); + if ( err != ERR_OK ) return err; + m_bAudioTrack = false; +#endif +#if _SCHOOL & _CEEBOTDEMO + m_bAudioTrack = false; +#endif +#if _NET + m_bAudioTrack = false; +#endif +#if _DEMO + m_bAudioTrack = false; +#endif + + return ERR_OK; +} + + +// Returns the total amount of video memory for textures. + +int CD3DApplication::GetVidMemTotal() +{ + return m_vidMemTotal; +} + +bool CD3DApplication::IsVideo8MB() +{ + if ( m_vidMemTotal == 0 ) return false; + return (m_vidMemTotal <= 8388608L); // 8 Mb or less (2 ^ 23)? +} + +bool CD3DApplication::IsVideo32MB() +{ + if ( m_vidMemTotal == 0 ) return false; + return (m_vidMemTotal > 16777216L); // more than 16 Mb (2 ^ 24)? +} + + +void CD3DApplication::SetShowStat(bool bShow) +{ + m_bShowStats = bShow; +} + +bool CD3DApplication::RetShowStat() +{ + return m_bShowStats; +} + + +void CD3DApplication::SetDebugMode(bool bMode) +{ + m_bDebugMode = bMode; + D3DTextr_SetDebugMode(m_bDebugMode); +} + +bool CD3DApplication::RetDebugMode() +{ + return m_bDebugMode; +} + +bool CD3DApplication::RetSetupMode() +{ + return m_bSetupMode; +} + + + + +// Son process of time management. + +DWORD WINAPI ThreadRoutine(LPVOID) +{ + Event event; + float time; + int ms, start, end, delay; + + ms = (int)(TIME_THREAD*1000.0f); + time = 0.0f; + while ( true ) + { + start = timeGetTime(); + + g_pD3DApp->m_pD3DEngine->FrameMove(TIME_THREAD); + + ZeroMemory(&event, sizeof(Event)); + event.event = EVENT_FRAME; + event.rTime = TIME_THREAD; + event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x); + event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y); + event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z); + event.keyState = g_pD3DApp->m_keyState; + + if ( g_pD3DApp->m_pRobotMain != 0 ) + { + g_pD3DApp->m_pRobotMain->EventProcess(event); + } + + end = timeGetTime(); + + delay = ms-(end-start); + if ( delay > 0 ) + { + Sleep(delay); // waiting 20ms-used + } + time += TIME_THREAD; + } + return 0; +} + + +// Called during device intialization, this code checks the device +// for some minimum set of capabilities. + +HRESULT CD3DApplication::ConfirmDevice( DDCAPS* pddDriverCaps, + D3DDEVICEDESC7* pd3dDeviceDesc ) +{ +//? if( pd3dDeviceDesc->wMaxVertexBlendMatrices < 2 ) +//? return E_FAIL; + + return S_OK; +} + +// Create the application. + +HRESULT CD3DApplication::Create( HINSTANCE hInst, TCHAR* strCmdLine ) +{ + HRESULT hr; + char deviceName[100]; + char modeName[100]; + int iValue; + DWORD style; + bool bFull, b3D; + + m_instance = hInst; + + InitCurrentDirectory(); + + // Enumerate available D3D devices. The callback is used so the app can + // confirm/reject each enumerated device depending on its capabilities. + if( FAILED( hr = D3DEnum_EnumerateDevices( m_fnConfirmDevice ) ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + return hr; + } + + if( FAILED( hr = D3DEnum_SelectDefaultDevice( &m_pDeviceInfo ) ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + return hr; + } + + if ( !m_bDebugMode ) + { + m_pDeviceInfo->bWindowed = false; // full screen + } + if ( GetProfileInt("Device", "FullScreen", bFull) ) + { + m_pDeviceInfo->bWindowed = !bFull; + } + m_pDeviceInfo->bWindowed = true; + + // Create the 3D engine. + if( (m_pD3DEngine = new CD3DEngine(m_iMan, this)) == NULL ) + { + DisplayFrameworkError( D3DENUMERR_ENGINE, MSGERR_APPMUSTEXIT ); + return E_OUTOFMEMORY; + } + SetEngine(m_pD3DEngine); + + // Initialize the app's custom scene stuff + if( FAILED( hr = m_pD3DEngine->OneTimeSceneInit() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + return hr; + } + + // Create a new CD3DFramework class. This class does all of our D3D + // initialization and manages the common D3D objects. + if( (m_pFramework = new CD3DFramework7()) == NULL ) + { + DisplayFrameworkError( E_OUTOFMEMORY, MSGERR_APPMUSTEXIT ); + return E_OUTOFMEMORY; + } + + // Create the sound instance. + if( (m_pSound = new CSound(m_iMan)) == NULL ) + { + DisplayFrameworkError( D3DENUMERR_SOUND, MSGERR_APPMUSTEXIT ); + return E_OUTOFMEMORY; + } + + // Create the robot application. + if( (m_pRobotMain = new CRobotMain(m_iMan)) == NULL ) + { + DisplayFrameworkError( D3DENUMERR_ROBOT, MSGERR_APPMUSTEXIT ); + return E_OUTOFMEMORY; + } + + // Register the window class + WNDCLASS wndClass = { 0, WndProc, 0, 0, hInst, + LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON) ), + LoadCursor( NULL, IDC_ARROW ), + (HBRUSH)GetStockObject(WHITE_BRUSH), + NULL, _T("D3D Window") }; + RegisterClass( &wndClass ); + + // Create the render window + style = WS_CAPTION|WS_VISIBLE; + if ( m_bDebugMode ) style |= WS_SYSMENU; // close box + m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, +//? WS_OVERLAPPEDWINDOW|WS_VISIBLE, + style, CW_USEDEFAULT, CW_USEDEFAULT, + WINDOW_DX, WINDOW_DY, 0L, +//? LoadMenu( hInst, MAKEINTRESOURCE(IDR_MENU) ), + NULL, + hInst, 0L ); + UpdateWindow( m_hWnd ); + + if ( !GetProfileInt("Setup", "Sound3D", b3D) ) + { + b3D = true; + } + m_pSound->SetDebugMode(m_bDebugMode); + m_pSound->Create(m_hWnd, b3D); + m_pSound->CacheAll(); + m_pSound->SetState(m_bAudioState); + m_pSound->SetAudioTrack(m_bAudioTrack); + m_pSound->SetCDpath(m_CDpath); + + // Initialize the 3D environment for the app + if( FAILED( hr = Initialize3DEnvironment() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + Cleanup3DEnvironment(); + return E_FAIL; + } + + // Change the display device driver. + GetProfileString("Device", "Name", deviceName, 100); + GetProfileString("Device", "Mode", modeName, 100); + GetProfileInt("Device", "FullScreen", bFull); + if ( deviceName[0] != 0 && modeName[0] != 0 && bFull ) + { + ChangeDevice(deviceName, modeName, bFull); + } + + // First execution? + if ( !GetProfileInt("Setup", "ObjectDirty", iValue) ) + { + m_pD3DEngine->FirstExecuteAdapt(true); + } + + // Creates the file colobot.ini at the first execution. + m_pRobotMain->CreateIni(); + +#if _DEMO + m_pRobotMain->ChangePhase(PHASE_NAME); +#else +#if _NET | _SCHOOL + m_pRobotMain->ChangePhase(PHASE_WELCOME2); +#else +#if _FRENCH + m_pRobotMain->ChangePhase(PHASE_WELCOME2); +#endif +#if _ENGLISH + m_pRobotMain->ChangePhase(PHASE_WELCOME2); +#endif +#if _GERMAN + m_pRobotMain->ChangePhase(PHASE_WELCOME2); +#endif +#if _WG + m_pRobotMain->ChangePhase(PHASE_WELCOME1); +#endif +#if _POLISH + m_pRobotMain->ChangePhase(PHASE_WELCOME1); +#endif +#endif +#endif + m_pD3DEngine->TimeInit(); + +#if USE_THREAD + m_thread = CreateThread(NULL, 0, ThreadRoutine, this, 0, &m_threadId); + SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL); +#endif + + // The app is ready to go + m_bReady = true; + + return S_OK; +} + + +// Message-processing loop. Idle time is used to render the scene. + +INT CD3DApplication::Run() +{ + // Load keyboard accelerators + HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) ); + + // Now we're ready to recieve and process Windows messages. + bool bGotMsg; + MSG msg; + PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ); + + while( WM_QUIT != msg.message ) + { + // Use PeekMessage() if the app is active, so we can use idle time to + // render the scene. Else, use GetMessage() to avoid eating CPU time. + if( m_bActive ) + bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ); + else + bGotMsg = GetMessage( &msg, NULL, 0U, 0U ); + + if( bGotMsg ) + { + // Translate and dispatch the message + if( TranslateAccelerator( m_hWnd, hAccel, &msg ) == 0 ) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + else + { + // Render a frame during idle time (no messages are waiting) + if( m_bActive && m_bReady ) + { + Event event; + + while ( m_event->GetEvent(event) ) + { + if ( event.event == EVENT_QUIT ) + { +//? SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + m_pSound->StopMusic(); + Cleanup3DEnvironment(); + PostQuitMessage(0); + return msg.wParam; + } + m_pRobotMain->EventProcess(event); + } + + if ( !RetNiceMouse() ) + { + SetMouseType(m_pD3DEngine->RetMouseType()); + } + + if( FAILED( Render3DEnvironment() ) ) + DestroyWindow( m_hWnd ); + } + } + } + + return msg.wParam; +} + + + +// Conversion of the position of the mouse. +// x: 0=left, 1=right +// y: 0=down, 1=up + +Math::Point CD3DApplication::ConvPosToInterface(HWND hWnd, LPARAM lParam) +{ + POINT cpos; + Math::Point pos; + float px, py, w, h; + + cpos.x = (short)LOWORD(lParam); + cpos.y = (short)HIWORD(lParam); + + if ( !m_pDeviceInfo->bWindowed ) + { + ClientToScreen(hWnd, &cpos); + } + + px = (float)cpos.x; + py = (float)cpos.y; + w = (float)m_ddsdRenderTarget.dwWidth; + h = (float)m_ddsdRenderTarget.dwHeight; + + pos.x = px/w; + pos.y = 1.0f-py/h; + + return pos; +} + +// Physically moves the mouse. + +void CD3DApplication::SetMousePos(Math::Point pos) +{ + POINT p; + + pos.y = 1.0f-pos.y; + + pos.x *= m_ddsdRenderTarget.dwWidth; + pos.y *= m_ddsdRenderTarget.dwHeight; + + p.x = (int)pos.x; + p.y = (int)pos.y; + ClientToScreen(m_hWnd, &p); + + SetCursorPos(p.x, p.y); +} + +// Choosing the type of cursor for the mouse. + +void CD3DApplication::SetMouseType(D3DMouse type) +{ + HCURSOR hc; + + if ( type == D3DMOUSEHAND ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORHAND)); + } + else if ( type == D3DMOUSECROSS ) + { + hc = LoadCursor(NULL, IDC_CROSS); + } + else if ( type == D3DMOUSEEDIT ) + { + hc = LoadCursor(NULL, IDC_IBEAM); + } + else if ( type == D3DMOUSENO ) + { + hc = LoadCursor(NULL, IDC_NO); + } + else if ( type == D3DMOUSEMOVE ) + { + hc = LoadCursor(NULL, IDC_SIZEALL); + } + else if ( type == D3DMOUSEMOVEH ) + { + hc = LoadCursor(NULL, IDC_SIZEWE); + } + else if ( type == D3DMOUSEMOVEV ) + { + hc = LoadCursor(NULL, IDC_SIZENS); + } + else if ( type == D3DMOUSEMOVED ) + { + hc = LoadCursor(NULL, IDC_SIZENESW); + } + else if ( type == D3DMOUSEMOVEI ) + { + hc = LoadCursor(NULL, IDC_SIZENWSE); + } + else if ( type == D3DMOUSEWAIT ) + { + hc = LoadCursor(NULL, IDC_WAIT); + } + else if ( type == D3DMOUSESCROLLL ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLL)); + } + else if ( type == D3DMOUSESCROLLR ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLR)); + } + else if ( type == D3DMOUSESCROLLU ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLU)); + } + else if ( type == D3DMOUSESCROLLD ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLD)); + } + else if ( type == D3DMOUSETARGET ) + { + hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORTARGET)); + } + else + { + hc = LoadCursor(NULL, IDC_ARROW); + } + + if ( hc != NULL ) + { + SetCursor(hc); + } +} + +// Choice of mode for the mouse. + +void CD3DApplication::SetNiceMouse(bool bNice) +{ + if ( bNice == m_bNiceMouse ) return; + m_bNiceMouse = bNice; + + if ( m_bNiceMouse ) + { + ShowCursor(false); // hides the ugly windows mouse + SetCursor(NULL); + } + else + { + ShowCursor(true); // shows the ugly windows mouse + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } +} + +// Whether to use the mouse pretty shaded. + +bool CD3DApplication::RetNiceMouse() +{ + if ( m_pDeviceInfo->bWindowed ) return false; + if ( !m_pDeviceInfo->bHardware ) return false; + + return m_bNiceMouse; +} + +// Indicates whether it is possible to use the mouse pretty shaded. + +bool CD3DApplication::RetNiceMouseCap() +{ + if ( m_pDeviceInfo->bWindowed ) return false; + if ( !m_pDeviceInfo->bHardware ) return false; + + return true; +} + + +// Static msg handler which passes messages to the application class. + +LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if ( g_pD3DApp != 0 ) + { + Event event; + short move; + + ZeroMemory(&event, sizeof(Event)); + +#if 0 + if ( uMsg == WM_KEYDOWN || + uMsg == WM_CHAR || + uMsg == WM_XBUTTONDOWN || + uMsg == WM_XBUTTONUP ) + { + char s[100]; + sprintf(s, "event: %d %d %d\n", uMsg, wParam, lParam); + OutputDebugString(s); + } +#endif + + if ( uMsg == WM_LBUTTONDOWN ) event.event = EVENT_LBUTTONDOWN; + if ( uMsg == WM_RBUTTONDOWN ) event.event = EVENT_RBUTTONDOWN; + if ( uMsg == WM_LBUTTONUP ) event.event = EVENT_LBUTTONUP; + if ( uMsg == WM_RBUTTONUP ) event.event = EVENT_RBUTTONUP; + if ( uMsg == WM_MOUSEMOVE ) event.event = EVENT_MOUSEMOVE; + if ( uMsg == WM_KEYDOWN ) event.event = EVENT_KEYDOWN; + if ( uMsg == WM_KEYUP ) event.event = EVENT_KEYUP; + if ( uMsg == WM_CHAR ) event.event = EVENT_CHAR; + + if ( uMsg == WM_XBUTTONUP ) + { + if ( (wParam>>16) == XBUTTON1 ) event.event = EVENT_HYPER_PREV; + if ( (wParam>>16) == XBUTTON2 ) event.event = EVENT_HYPER_NEXT; + } + + event.param = wParam; + event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x); + event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y); + event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z); + event.keyState = g_pD3DApp->m_keyState; + + if ( uMsg == WM_LBUTTONDOWN || + uMsg == WM_RBUTTONDOWN || + uMsg == WM_LBUTTONUP || + uMsg == WM_RBUTTONUP || + uMsg == WM_MOUSEMOVE ) // mouse event? + { + event.pos = g_pD3DApp->ConvPosToInterface(hWnd, lParam); + g_pD3DApp->m_mousePos = event.pos; + g_pD3DApp->m_pD3DEngine->SetMousePos(event.pos); + } + + if ( uMsg == WM_MOUSEWHEEL ) // mouse wheel? + { + event.event = EVENT_KEYDOWN; + event.pos = g_pD3DApp->m_mousePos; + move = HIWORD(wParam); + if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP; + if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN; + } + if ( g_pD3DApp->m_mshMouseWheel != 0 && + uMsg == g_pD3DApp->m_mshMouseWheel ) // Logitech mouse wheel? + { + event.event = EVENT_KEYDOWN; + event.pos = g_pD3DApp->m_mousePos; + move = LOWORD(wParam); + if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP; + if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN; + } + + if ( event.event == EVENT_KEYDOWN || + event.event == EVENT_KEYUP || + event.event == EVENT_CHAR ) + { + if ( event.param == 0 ) + { + event.event = EVENT_NULL; + } + } + + if ( g_pD3DApp->m_pRobotMain != 0 && event.event != 0 ) + { + g_pD3DApp->m_pRobotMain->EventProcess(event); +//? if ( !g_pD3DApp->RetNiceMouse() ) +//? { +//? g_pD3DApp->SetMouseType(g_pD3DApp->m_pD3DEngine->RetMouseType()); +//? } + } + if ( g_pD3DApp->m_pD3DEngine != 0 ) + { + g_pD3DApp->m_pD3DEngine->MsgProc( hWnd, uMsg, wParam, lParam ); + } + return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam ); + } + + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + + +// Minimal message proc function for the about box. + +BOOL CALLBACK AboutProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM ) +{ + if( WM_COMMAND == uMsg ) + if( IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam) ) + EndDialog( hWnd, TRUE ); + + return WM_INITDIALOG == uMsg ? TRUE : FALSE; +} + + + +// Ignore keypresses. + +void CD3DApplication::FlushPressKey() +{ + m_keyState = 0; + m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f); + m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f); +} + +// Resets the default keys. + +void CD3DApplication::ResetKey() +{ + int i; + + for ( i=0 ; i<50 ; i++ ) + { + m_key[i][0] = 0; + m_key[i][1] = 0; + } + m_key[KEYRANK_LEFT ][0] = VK_LEFT; + m_key[KEYRANK_RIGHT ][0] = VK_RIGHT; + m_key[KEYRANK_UP ][0] = VK_UP; + m_key[KEYRANK_DOWN ][0] = VK_DOWN; + m_key[KEYRANK_GUP ][0] = VK_SHIFT; + m_key[KEYRANK_GDOWN ][0] = VK_CONTROL; + m_key[KEYRANK_CAMERA ][0] = VK_SPACE; + m_key[KEYRANK_CAMERA ][1] = VK_BUTTON2; + m_key[KEYRANK_DESEL ][0] = VK_NUMPAD0; + m_key[KEYRANK_DESEL ][1] = VK_BUTTON6; + m_key[KEYRANK_ACTION ][0] = VK_RETURN; + m_key[KEYRANK_ACTION ][1] = VK_BUTTON1; + m_key[KEYRANK_NEAR ][0] = VK_ADD; + m_key[KEYRANK_NEAR ][1] = VK_BUTTON5; + m_key[KEYRANK_AWAY ][0] = VK_SUBTRACT; + m_key[KEYRANK_AWAY ][1] = VK_BUTTON4; + m_key[KEYRANK_NEXT ][0] = VK_TAB; + m_key[KEYRANK_NEXT ][1] = VK_BUTTON3; + m_key[KEYRANK_HUMAN ][0] = VK_HOME; + m_key[KEYRANK_HUMAN ][1] = VK_BUTTON7; + m_key[KEYRANK_QUIT ][0] = VK_ESCAPE; + m_key[KEYRANK_HELP ][0] = VK_F1; + m_key[KEYRANK_PROG ][0] = VK_F2; + m_key[KEYRANK_CBOT ][0] = VK_F3; + m_key[KEYRANK_VISIT ][0] = VK_DECIMAL; + m_key[KEYRANK_SPEED10][0] = VK_F4; + m_key[KEYRANK_SPEED15][0] = VK_F5; + m_key[KEYRANK_SPEED20][0] = VK_F6; +// m_key[KEYRANK_SPEED30][0] = VK_F7; +} + +// Modifies a button. + +void CD3DApplication::SetKey(int keyRank, int option, int key) +{ + if ( keyRank < 0 || + keyRank >= 50 ) return; + + if ( option < 0 || + option >= 2 ) return; + + m_key[keyRank][option] = key; +} + +// Gives a hint. + +int CD3DApplication::RetKey(int keyRank, int option) +{ + if ( keyRank < 0 || + keyRank >= 50 ) return 0; + + if ( option < 0 || + option >= 2 ) return 0; + + return m_key[keyRank][option]; +} + + + +// Use the joystick or keyboard. + +void CD3DApplication::SetJoystick(bool bEnable) +{ + m_bJoystick = bEnable; + + if ( m_bJoystick ) // joystick ? + { + if ( !InitDirectInput(m_instance, m_hWnd) ) // initialise joystick + { + m_bJoystick = false; + } + else + { + SetAcquire(true); + SetTimer(m_hWnd, 0, 1000/30, NULL); + } + } + else // keyboard? + { + KillTimer(m_hWnd, 0); + SetAcquire(false); + FreeDirectInput(); + } +} + +bool CD3DApplication::RetJoystick() +{ + return m_bJoystick; +} + + +// Message handling function. + +LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + HRESULT hr; + DIJOYSTATE js; + int i; + + // The F10 key sends another message to activate + // menu in standard Windows applications! + if ( uMsg == WM_SYSKEYDOWN && wParam == VK_F10 ) + { + uMsg = WM_KEYDOWN; + } + if ( uMsg == WM_SYSKEYUP && wParam == VK_F10 ) + { + uMsg = WM_KEYUP; + } + + // Mange event "menu" sent by Alt or F10. + if ( uMsg == WM_SYSCOMMAND && wParam == SC_KEYMENU ) + { + return 0; + } + + if ( uMsg == WM_KEYDOWN || uMsg == WM_KEYUP ) + { + if ( GetKeyState(VK_SHIFT) & 0x8000 ) + { + m_keyState |= KS_SHIFT; + } + else + { + m_keyState &= ~KS_SHIFT; + } + + if ( GetKeyState(VK_CONTROL) & 0x8000 ) + { + m_keyState |= KS_CONTROL; + } + else + { + m_keyState &= ~KS_CONTROL; + } + } + + switch( uMsg ) + { + case WM_KEYDOWN: + if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 1.0f; + if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 1.0f; + if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = -1.0f; + if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = -1.0f; + if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = -1.0f; + if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = -1.0f; + if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 1.0f; + if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 1.0f; + if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 1.0f; + if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 1.0f; + if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = -1.0f; + if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = -1.0f; + if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState |= KS_NUMPLUS; + if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState |= KS_NUMPLUS; + if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState |= KS_NUMMINUS; + if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState |= KS_NUMMINUS; + if ( wParam == VK_PRIOR ) m_keyState |= KS_PAGEUP; + if ( wParam == VK_NEXT ) m_keyState |= KS_PAGEDOWN; +//? if ( wParam == VK_SHIFT ) m_keyState |= KS_SHIFT; +//? if ( wParam == VK_CONTROL ) m_keyState |= KS_CONTROL; + if ( wParam == VK_NUMPAD8 ) m_keyState |= KS_NUMUP; + if ( wParam == VK_NUMPAD2 ) m_keyState |= KS_NUMDOWN; + if ( wParam == VK_NUMPAD4 ) m_keyState |= KS_NUMLEFT; + if ( wParam == VK_NUMPAD6 ) m_keyState |= KS_NUMRIGHT; + break; + + case WM_KEYUP: + if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 0.0f; + if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 0.0f; + if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = 0.0f; + if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = 0.0f; + if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = 0.0f; + if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = 0.0f; + if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 0.0f; + if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 0.0f; + if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 0.0f; + if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 0.0f; + if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = 0.0f; + if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = 0.0f; + if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState &= ~KS_NUMPLUS; + if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState &= ~KS_NUMPLUS; + if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState &= ~KS_NUMMINUS; + if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState &= ~KS_NUMMINUS; + if ( wParam == VK_PRIOR ) m_keyState &= ~KS_PAGEUP; + if ( wParam == VK_NEXT ) m_keyState &= ~KS_PAGEDOWN; +//? if ( wParam == VK_SHIFT ) m_keyState &= ~KS_SHIFT; +//? if ( wParam == VK_CONTROL ) m_keyState &= ~KS_CONTROL; + if ( wParam == VK_NUMPAD8 ) m_keyState &= ~KS_NUMUP; + if ( wParam == VK_NUMPAD2 ) m_keyState &= ~KS_NUMDOWN; + if ( wParam == VK_NUMPAD4 ) m_keyState &= ~KS_NUMLEFT; + if ( wParam == VK_NUMPAD6 ) m_keyState &= ~KS_NUMRIGHT; + break; + + case WM_LBUTTONDOWN: + m_keyState |= KS_MLEFT; + break; + + case WM_RBUTTONDOWN: + m_keyState |= KS_MRIGHT; + break; + + case WM_LBUTTONUP: + m_keyState &= ~KS_MLEFT; + break; + + case WM_RBUTTONUP: + m_keyState &= ~KS_MRIGHT; + break; + + case WM_PAINT: + // Handle paint messages when the app is not ready + if( m_pFramework && !m_bReady ) + { + if( m_pDeviceInfo->bWindowed ) + m_pFramework->ShowFrame(); + else + m_pFramework->FlipToGDISurface( true ); + } + break; + + case WM_MOVE: + // If in windowed mode, move the Framework's window + if( m_pFramework && m_bActive && m_bReady && m_pDeviceInfo->bWindowed ) + m_pFramework->Move( (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) ); + break; + + case WM_SIZE: + // Check to see if we are losing our window... + if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam ) + { + m_bActive = false; + } + else + { + m_bActive = true; + } +//? char s[100]; +//? sprintf(s, "WM_SIZE %d %d %d\n", m_bActive, m_bReady, m_pDeviceInfo->bWindowed); +//? OutputDebugString(s); + + // A new window size will require a new backbuffer + // size, so the 3D structures must be changed accordingly. + if( m_bActive && m_bReady && m_pDeviceInfo->bWindowed ) + { + m_bReady = false; + +//? OutputDebugString("WM_SIZE Change3DEnvironment\n"); + if( FAILED( hr = Change3DEnvironment() ) ) + return 0; + + m_bReady = true; + } + break; + + case WM_TIMER: + if ( m_bActivateApp && m_bJoystick ) + { + if ( UpdateInputState(js) ) + { + m_axeJoy.x = js.lX/1000.0f+js.lRz/1000.0f; // tourner + m_axeJoy.y = -js.lY/1000.0f; // avancer + m_axeJoy.z = -js.rglSlider[0]/1000.0f; // monter + + m_axeJoy.x = Math::Neutral(m_axeJoy.x, 0.2f); + m_axeJoy.y = Math::Neutral(m_axeJoy.y, 0.2f); + m_axeJoy.z = Math::Neutral(m_axeJoy.z, 0.2f); + +//? char s[100]; +//? sprintf(s, "x=%d y=%d z=% x=%d y=%d z=%d\n", js.lX,js.lY,js.lZ,js.lRx,js.lRy,js.lRz); +//? OutputDebugString(s); + + for ( i=0 ; i<32 ; i++ ) + { + if ( js.rgbButtons[i] != 0 && !m_bJoyButton[i] ) + { + m_bJoyButton[i] = true; + PostMessage(m_hWnd, WM_KEYDOWN, VK_BUTTON1+i, 0); + } + if ( js.rgbButtons[i] == 0 && m_bJoyButton[i] ) + { + m_bJoyButton[i] = false; + PostMessage(m_hWnd, WM_KEYUP, VK_BUTTON1+i, 0); + } + } + } + else + { + OutputDebugString("UpdateInputState error\n"); + } + } + break; + + case WM_ACTIVATE: + if( LOWORD(wParam) == WA_INACTIVE ) + { + m_bActivateApp = false; + } + else + { + m_bActivateApp = true; + } + + if ( m_bActivateApp && m_bJoystick ) + { + SetAcquire(true); // re-enables the joystick + } + break; + + case MM_MCINOTIFY: + if ( wParam == MCI_NOTIFY_SUCCESSFUL ) + { + OutputDebugString("Event MM_MCINOTIFY\n"); + m_pSound->SuspendMusic(); + m_pSound->RestartMusic(); + } + break; + + case WM_SETCURSOR: + // Prevent a cursor in fullscreen mode + if( m_bActive && m_bReady && !m_pDeviceInfo->bWindowed ) + { +//? SetCursor(NULL); + return 1; + } + break; + + case WM_ENTERMENULOOP: + // Pause the app when menus are displayed + Pause(true); + break; + case WM_EXITMENULOOP: + Pause(false); + break; + + case WM_ENTERSIZEMOVE: + // Halt frame movement while the app is sizing or moving + m_pD3DEngine->TimeEnterGel(); + break; + case WM_EXITSIZEMOVE: + m_pD3DEngine->TimeExitGel(); + break; + + case WM_NCHITTEST: + // Prevent the user from selecting the menu in fullscreen mode + if( !m_pDeviceInfo->bWindowed ) + return HTCLIENT; + + break; + + case WM_POWERBROADCAST: + switch( wParam ) + { + case PBT_APMQUERYSUSPEND: + // At this point, the app should save any data for open + // network connections, files, etc.., and prepare to go into + // a suspended mode. + return OnQuerySuspend( (DWORD)lParam ); + + case PBT_APMRESUMESUSPEND: + // At this point, the app should recover any data, network + // connections, files, etc.., and resume running from when + // the app was suspended. + return OnResumeSuspend( (DWORD)lParam ); + } + break; + + case WM_SYSCOMMAND: + // Prevent moving/sizing and power loss in fullscreen mode + switch( wParam ) + { + case SC_MOVE: + case SC_SIZE: + case SC_MAXIMIZE: + case SC_MONITORPOWER: + if( false == m_pDeviceInfo->bWindowed ) + return 1; + break; + } + break; + + case WM_COMMAND: + switch( LOWORD(wParam) ) + { + case IDM_CHANGEDEVICE: + // Display the device-selection dialog box. + if( m_bActive && m_bReady ) + { + Pause(true); + + if( SUCCEEDED( D3DEnum_UserChangeDevice( &m_pDeviceInfo ) ) ) + { + if( FAILED( hr = Change3DEnvironment() ) ) + return 0; + } + Pause(false); + } + return 0; + + case IDM_ABOUT: + // Display the About box + Pause(true); + DialogBox( (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ), + MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutProc ); + Pause(false); + return 0; + + case IDM_EXIT: + // Recieved key/menu command to exit app + SendMessage( hWnd, WM_CLOSE, 0, 0 ); + return 0; + } + break; + + case WM_GETMINMAXINFO: + ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; + ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; + break; + + case WM_CLOSE: + DestroyWindow( hWnd ); + return 0; + + case WM_DESTROY: + Cleanup3DEnvironment(); + PostQuitMessage(0); + return 0; + } + + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + + +// Enumeration function to report valid pixel formats for z-buffers. + +HRESULT WINAPI EnumZBufferFormatsCallback(DDPIXELFORMAT* pddpf, + VOID* pContext) +{ + DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext; + + char s[100]; + sprintf(s, "EnumZBufferFormatsCallback %d\n", pddpf->dwRGBBitCount); + OutputDebugString(s); + + if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount ) + { + (*pddpfOut) = (*pddpf); + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + +// Internal function called by Create() to make and attach a zbuffer +// to the renderer. + +HRESULT CD3DApplication::CreateZBuffer(GUID* pDeviceGUID) +{ + HRESULT hr; + + // Check if the device supports z-bufferless hidden surface removal. If so, + // we don't really need a z-buffer + D3DDEVICEDESC7 ddDesc; + m_pD3DDevice->GetCaps( &ddDesc ); + if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) + return S_OK; + + // Get z-buffer dimensions from the render target + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + m_pddsRenderTarget->GetSurfaceDesc( &ddsd ); + + // Setup the surface desc for the z-buffer. + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY; + ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized + + // Get an appropiate pixel format from enumeration of the formats. On the + // first pass, we look for a zbuffer dpeth which is equal to the frame + // buffer depth (as some cards unfornately require this). + m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat ); + if( 0 == ddsd.ddpfPixelFormat.dwSize ) + { + // Try again, just accepting any 16-bit zbuffer + ddsd.ddpfPixelFormat.dwRGBBitCount = 16; + m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat ); + + if( 0 == ddsd.ddpfPixelFormat.dwSize ) + { + DEBUG_MSG( _T("Device doesn't support requested zbuffer format") ); + return D3DFWERR_NOZBUFFER; + } + } + + // Create and attach a z-buffer + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsDepthBuffer, NULL ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOZBUFFER; + DEBUG_MSG( _T("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsDepthBuffer ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") ); + return D3DFWERR_NOZBUFFER; + } + + // Finally, this call rebuilds internal structures + if( FAILED( m_pD3DDevice->SetRenderTarget( m_pddsRenderTarget, 0L ) ) ) + { + DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") ); + return D3DFWERR_NOZBUFFER; + } + + return S_OK; +} + +// Initializes the sample framework, then calls the app-specific function +// to initialize device specific objects. This code is structured to +// handled any errors that may occur duing initialization. + +HRESULT CD3DApplication::Initialize3DEnvironment() +{ + HRESULT hr; + DDSCAPS2 ddsCaps2; + DWORD dwFrameworkFlags = 0L; + DWORD dwTotal; + DWORD dwFree; + + dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L ); + dwFrameworkFlags |= ( m_pDeviceInfo->bStereo ? D3DFW_STEREO : 0L ); + dwFrameworkFlags |= ( m_bAppUseZBuffer ? D3DFW_ZBUFFER : 0L ); + + // Initialize the D3D framework + if( SUCCEEDED( hr = m_pFramework->Initialize( m_hWnd, + m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID, + &m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) ) + { + m_pDD = m_pFramework->GetDirectDraw(); + m_pD3D = m_pFramework->GetDirect3D(); + m_pD3DDevice = m_pFramework->GetD3DDevice(); + + m_pD3DEngine->SetD3DDevice(m_pD3DDevice); + + m_pddsRenderTarget = m_pFramework->GetRenderSurface(); + + m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget); + m_pddsRenderTarget->GetSurfaceDesc( &m_ddsdRenderTarget ); + + // Request the amount of video memory. + ZeroMemory(&ddsCaps2, sizeof(ddsCaps2)); + ddsCaps2.dwCaps = DDSCAPS_TEXTURE; + dwTotal = 0; + hr = m_pDD->GetAvailableVidMem(&ddsCaps2, &dwTotal, &dwFree); + m_vidMemTotal = dwTotal; + + // Let the app run its startup code which creates the 3d scene. + if( SUCCEEDED( hr = m_pD3DEngine->InitDeviceObjects() ) ) + { +//? CreateZBuffer(m_pDeviceInfo->pDeviceGUID); + return S_OK; + } + else + { + DeleteDeviceObjects(); + m_pFramework->DestroyObjects(); + } + } + + // If we get here, the first initialization passed failed. If that was with a + // hardware device, try again using a software rasterizer instead. + if( m_pDeviceInfo->bHardware ) + { + // Try again with a software rasterizer + DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE ); + D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY ); + return Initialize3DEnvironment(); + } + + return hr; +} + + +// Handles driver, device, and/or mode changes for the app. + +HRESULT CD3DApplication::Change3DEnvironment() +{ +#if 0 + HRESULT hr; + static bool bOldWindowedState = true; + static DWORD dwSavedStyle; + static RECT rcSaved; + + // Release all scene objects that will be re-created for the new device + DeleteDeviceObjects(); + + // Release framework objects, so a new device can be created + if( FAILED( hr = m_pFramework->DestroyObjects() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + return hr; + } + + // Check if going from fullscreen to windowed mode, or vice versa. + if( bOldWindowedState != m_pDeviceInfo->bWindowed ) + { + if( m_pDeviceInfo->bWindowed ) + { + // Coming from fullscreen mode, so restore window properties + SetWindowLong( m_hWnd, GWL_STYLE, dwSavedStyle ); + SetWindowPos( m_hWnd, HWND_NOTOPMOST, rcSaved.left, rcSaved.top, + ( rcSaved.right - rcSaved.left ), + ( rcSaved.bottom - rcSaved.top ), SWP_SHOWWINDOW ); + } + else + { + // Going to fullscreen mode, save/set window properties as needed + dwSavedStyle = GetWindowLong( m_hWnd, GWL_STYLE ); + GetWindowRect( m_hWnd, &rcSaved ); + SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE ); + } + + bOldWindowedState = m_pDeviceInfo->bWindowed; + } + + // Inform the framework class of the driver change. It will internally + // re-create valid surfaces, a d3ddevice, etc. + if( FAILED( hr = Initialize3DEnvironment() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + return hr; + } + + return S_OK; +#else + HRESULT hr; + + // Release all scene objects that will be re-created for the new device + DeleteDeviceObjects(); + + // Release framework objects, so a new device can be created + if( FAILED( hr = m_pFramework->DestroyObjects() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + return hr; + } + + if( m_pDeviceInfo->bWindowed ) + { + SetWindowPos(m_hWnd, HWND_NOTOPMOST, 10, 10, WINDOW_DX, WINDOW_DY, SWP_SHOWWINDOW); + } + + // Inform the framework class of the driver change. It will internally + // re-create valid surfaces, a d3ddevice, etc. + if( FAILED( hr = Initialize3DEnvironment() ) ) + { + DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT ); + SendMessage( m_hWnd, WM_CLOSE, 0, 0 ); + return hr; + } + + m_pD3DEngine->ChangeLOD(); + + if( m_pDeviceInfo->bWindowed ) + { + SetNiceMouse(false); // hides the ugly windows mouse + } + + return S_OK; +#endif +} + + + +// Evolved throughout the game + +void CD3DApplication::StepSimul(float rTime) +{ + Event event; + + if ( m_pRobotMain == 0 ) return; + + ZeroMemory(&event, sizeof(Event)); + event.event = EVENT_FRAME; // funny bug release "Maximize speed"! + event.rTime = rTime; + event.axeX = AxeLimit(m_axeKey.x + m_axeJoy.x); + event.axeY = AxeLimit(m_axeKey.y + m_axeJoy.y); + event.axeZ = AxeLimit(m_axeKey.z + m_axeJoy.z); + event.keyState = m_keyState; + +//?char s[100]; +//?sprintf(s, "StepSimul %.3f\n", event.rTime); +//?OutputDebugString(s); + m_pRobotMain->EventProcess(event); +} + + +// Draws the scene. + +HRESULT CD3DApplication::Render3DEnvironment() +{ + HRESULT hr; + float rTime; + + // Check the cooperative level before rendering + if( FAILED( hr = m_pDD->TestCooperativeLevel() ) ) + { + switch( hr ) + { + case DDERR_EXCLUSIVEMODEALREADYSET: + case DDERR_NOEXCLUSIVEMODE: + OutputDebugString("DDERR_EXCLUSIVEMODEALREADYSET\n"); + // Do nothing because some other app has exclusive mode + return S_OK; + + case DDERR_WRONGMODE: + OutputDebugString("DDERR_WRONGMODE\n"); + // The display mode changed on us. Resize accordingly + if( m_pDeviceInfo->bWindowed ) + return Change3DEnvironment(); + break; + } + return hr; + } + + // Get the relative time, in seconds + rTime = m_pD3DEngine->TimeGet(); + if ( rTime > MAX_STEP ) rTime = MAX_STEP; // never more than 0.5s! + m_aTime += rTime; + +#if !USE_THREAD + if( FAILED( hr = m_pD3DEngine->FrameMove(rTime) ) ) + return hr; + + // FrameMove (animate) the scene + StepSimul(rTime); +#endif + + // Render the scene. + if( FAILED( hr = m_pD3DEngine->Render() ) ) + return hr; + + DrawSuppl(); + + // Show the frame rate, etc. + if( m_bShowStats ) + ShowStats(); + + // Show the frame on the primary surface. + if( FAILED( hr = m_pFramework->ShowFrame() ) ) + { + if( DDERR_SURFACELOST != hr ) + return hr; + + m_pFramework->RestoreSurfaces(); + m_pD3DEngine->RestoreSurfaces(); + } + + return S_OK; +} + + +// Cleanup scene objects + +VOID CD3DApplication::Cleanup3DEnvironment() +{ + m_bActive = false; + m_bReady = false; + + if( m_pFramework ) + { + DeleteDeviceObjects(); + SAFE_DELETE( m_pFramework ); + + m_pD3DEngine->FinalCleanup(); + } + + D3DEnum_FreeResources(); +//? FreeDirectInput(); +} + +// Called when the app is exitting, or the device is being changed, +// this function deletes any device dependant objects. + +VOID CD3DApplication::DeleteDeviceObjects() +{ + if( m_pFramework ) + { + m_pD3DEngine->DeleteDeviceObjects(); + SAFE_RELEASE( m_pddsDepthBuffer ); + } +} + + + +// Called in to toggle the pause state of the app. This function +// brings the GDI surface to the front of the display, so drawing +// output like message boxes and menus may be displayed. + +VOID CD3DApplication::Pause( bool bPause ) +{ + static DWORD dwAppPausedCount = 0L; + + dwAppPausedCount += ( bPause ? +1 : -1 ); + m_bReady = ( dwAppPausedCount ? false : true ); + + // Handle the first pause request (of many, nestable pause requests) + if( bPause && ( 1 == dwAppPausedCount ) ) + { + // Get a surface for the GDI + if( m_pFramework ) + m_pFramework->FlipToGDISurface( true ); + + // Stop the scene from animating + m_pD3DEngine->TimeEnterGel(); + } + + if( 0 == dwAppPausedCount ) + { + // Restart the scene + m_pD3DEngine->TimeExitGel(); + } +} + + +// Called when the app receives a PBT_APMQUERYSUSPEND message, meaning +// the computer is about to be suspended. At this point, the app should +// save any data for open network connections, files, etc.., and prepare +// to go into a suspended mode. + +LRESULT CD3DApplication::OnQuerySuspend( DWORD dwFlags ) +{ + OutputDebugString("OnQuerySuspend\n"); + Pause(true); + return true; +} + + +// Called when the app receives a PBT_APMRESUMESUSPEND message, meaning +// the computer has just resumed from a suspended state. At this point, +// the app should recover any data, network connections, files, etc.., +// and resume running from when the app was suspended. + +LRESULT CD3DApplication::OnResumeSuspend( DWORD dwData ) +{ + OutputDebugString("OnResumeSuspend\n"); + Pause(false); + return true; +} + + +// Draw all the additional graphic elements. + +void CD3DApplication::DrawSuppl() +{ + HDC hDC; + Math::Point p1, p2; + POINT list[3]; + RECT rect; + HPEN hPen; + HGDIOBJ old; + Math::Point pos; + float d; + int nbOut; + + if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return; + + // Displays the selection rectangle. + if ( m_pD3DEngine->GetHilite(p1, p2) ) + { + nbOut = 0; + if ( p1.x < 0.0f || p1.x > 1.0f ) nbOut ++; + if ( p1.y < 0.0f || p1.y > 1.0f ) nbOut ++; + if ( p2.x < 0.0f || p2.x > 1.0f ) nbOut ++; + if ( p2.y < 0.0f || p2.y > 1.0f ) nbOut ++; + if ( nbOut <= 2 ) + { +#if 0 + time = Math::Mod(m_aTime, 0.5f); + if ( time < 0.25f ) d = time*4.0f; + else d = (2.0f-time*4.0f); +#endif +#if 0 + time = Math::Mod(m_aTime, 0.5f); + if ( time < 0.4f ) d = time/0.4f; + else d = 1.0f-(time-0.4f)/0.1f; +#endif +#if 1 + d = 0.5f+sinf(m_aTime*6.0f)*0.5f; +#endif + d *= (p2.x-p1.x)*0.1f; + p1.x += d; + p1.y += d; + p2.x -= d; + p2.y -= d; + + hPen = CreatePen(PS_SOLID, 1, RGB(255,255,0)); // yellow + old = SelectObject(hDC, hPen); + + rect.left = (int)(p1.x*m_ddsdRenderTarget.dwWidth); + rect.right = (int)(p2.x*m_ddsdRenderTarget.dwWidth); + rect.top = (int)((1.0f-p2.y)*m_ddsdRenderTarget.dwHeight); + rect.bottom = (int)((1.0f-p1.y)*m_ddsdRenderTarget.dwHeight); + + list[0].x = rect.left; + list[0].y = rect.top+(rect.bottom-rect.top)/5; + list[1].x = rect.left; + list[1].y = rect.top; + list[2].x = rect.left+(rect.right-rect.left)/5; + list[2].y = rect.top; + Polyline(hDC, list, 3); + + list[0].x = rect.right; + list[0].y = rect.top+(rect.bottom-rect.top)/5; + list[1].x = rect.right; + list[1].y = rect.top; + list[2].x = rect.right+(rect.left-rect.right)/5; + list[2].y = rect.top; + Polyline(hDC, list, 3); + + list[0].x = rect.left; + list[0].y = rect.bottom+(rect.top-rect.bottom)/5; + list[1].x = rect.left; + list[1].y = rect.bottom; + list[2].x = rect.left+(rect.right-rect.left)/5; + list[2].y = rect.bottom; + Polyline(hDC, list, 3); + + list[0].x = rect.right; + list[0].y = rect.bottom+(rect.top-rect.bottom)/5; + list[1].x = rect.right; + list[1].y = rect.bottom; + list[2].x = rect.right+(rect.left-rect.right)/5; + list[2].y = rect.bottom; + Polyline(hDC, list, 3); + + if ( old != 0 ) SelectObject(hDC, old); + DeleteObject(hPen); + } + } + + m_pddsRenderTarget->ReleaseDC(hDC); +} + +// Shows frame rate and dimensions of the rendering device. + +VOID CD3DApplication::ShowStats() +{ + static FLOAT fFPS = 0.0f; + static FLOAT fLastTime = 0.0f; + static DWORD dwFrames = 0L; + + // Keep track of the time lapse and frame count + FLOAT fTime = timeGetTime() * 0.001f; // Get current time in seconds + ++dwFrames; + + // Update the frame rate once per second + if( fTime - fLastTime > 1.0f ) + { + fFPS = dwFrames / (fTime - fLastTime); + fLastTime = fTime; + dwFrames = 0L; + } + + int t = m_pD3DEngine->RetStatisticTriangle(); + + // Setup the text buffer to write out dimensions + TCHAR buffer[100]; + sprintf( buffer, _T("%7.02f fps T=%d (%dx%dx%d)"), fFPS, t, + m_ddsdRenderTarget.dwWidth, m_ddsdRenderTarget.dwHeight, + m_ddsdRenderTarget.ddpfPixelFormat.dwRGBBitCount ); + OutputText( 400, 2, buffer ); + + int x, y, i; + if ( m_pD3DEngine->GetSpriteCoord(x, y) ) + { + OutputText( x, y, "+" ); + } + + for ( i=0 ; i<10 ; i++ ) + { + char* info = m_pD3DEngine->RetInfoText(i); + x = 50; + y = m_ddsdRenderTarget.dwHeight-20-i*20; + OutputText( x, y, info ); + } +} + + +// Draws text on the window. + +VOID CD3DApplication::OutputText( DWORD x, DWORD y, TCHAR* str ) +{ + HDC hDC; + + // Get a DC for the surface. Then, write out the buffer + if( m_pddsRenderTarget ) + { + if( SUCCEEDED( m_pddsRenderTarget->GetDC(&hDC) ) ) + { + SetTextColor( hDC, RGB(255,255,0) ); + SetBkMode( hDC, TRANSPARENT ); + ExtTextOut( hDC, x, y, 0, NULL, str, lstrlen(str), NULL ); + m_pddsRenderTarget->ReleaseDC(hDC); + } + } +} + + + + +// Defines a function that allocates memory for and initializes +// members within a BITMAPINFOHEADER structure + +PBITMAPINFO CD3DApplication::CreateBitmapInfoStruct(HBITMAP hBmp) +{ + BITMAP bmp; + PBITMAPINFO pbmi; + WORD cClrBits; + + // Retrieve the bitmap's color format, width, and height. + if ( !GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp) ) + return 0; + + // Convert the color format to a count of bits. + cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); + + if ( cClrBits == 1 ) cClrBits = 1; + else if ( cClrBits <= 4 ) cClrBits = 4; + else if ( cClrBits <= 8 ) cClrBits = 8; + else if ( cClrBits <= 16 ) cClrBits = 16; + else if ( cClrBits <= 24 ) cClrBits = 24; + else cClrBits = 32; + + // Allocate memory for the BITMAPINFO structure. (This structure + // contains a BITMAPINFOHEADER structure and an array of RGBQUAD data + // structures.) + if ( cClrBits != 24 ) + { + pbmi = (PBITMAPINFO)LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER) + + sizeof(RGBQUAD) * (2^cClrBits)); + } + // There is no RGBQUAD array for the 24-bit-per-pixel format. + else + { + pbmi = (PBITMAPINFO)LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER)); + } + + // Initialize the fields in the BITMAPINFO structure. + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = bmp.bmWidth; + pbmi->bmiHeader.biHeight = bmp.bmHeight; + pbmi->bmiHeader.biPlanes = bmp.bmPlanes; + pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; + if ( cClrBits < 24 ) + pbmi->bmiHeader.biClrUsed = 2^cClrBits; + + // If the bitmap is not compressed, set the BI_RGB flag. + pbmi->bmiHeader.biCompression = BI_RGB; + + // Compute the number of bytes in the array of color + // indices and store the result in biSizeImage. + pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8 + * pbmi->bmiHeader.biHeight + * cClrBits; + + // Set biClrImportant to 0, indicating that all of the + // device colors are important. + pbmi->bmiHeader.biClrImportant = 0; + + return pbmi; +} + +// Defines a function that initializes the remaining structures, +// retrieves the array of palette indices, opens the file, copies +// the data, and closes the file. + +bool CD3DApplication::CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) +{ + FILE* file; // file handle + BITMAPFILEHEADER hdr; // bitmap file-header + PBITMAPINFOHEADER pbih; // bitmap info-header + LPBYTE lpBits; // memory pointer + DWORD dwTotal; // total count of bytes + + pbih = (PBITMAPINFOHEADER)pbi; + lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); + if ( !lpBits ) return false; + + // Retrieve the color table (RGBQUAD array) and the bits + // (array of palette indices) from the DIB. + if ( !GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight, + lpBits, pbi, DIB_RGB_COLORS) ) + return false; + + // Create the .BMP file. + file = fopen(pszFile, "wb"); + if ( file == NULL ) return false; + + hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" + + // Compute the size of the entire file. + hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof(RGBQUAD) + pbih->biSizeImage); + + hdr.bfReserved1 = 0; + hdr.bfReserved2 = 0; + + // Compute the offset to the array of color indices. + hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof (RGBQUAD); + + // Copy the BITMAPFILEHEADER into the .BMP file. + fwrite(&hdr, sizeof(BITMAPFILEHEADER), 1, file); + + // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. + fwrite(pbih, sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD), 1, file); + + // Copy the array of color indices into the .BMP file. + dwTotal = pbih->biSizeImage; + fwrite(lpBits, dwTotal, 1, file); + + // Close the .BMP file. + fclose(file); + + // Free memory. + GlobalFree((HGLOBAL)lpBits); + return true; +} + +// Write a file. BMP screenshot. + +bool CD3DApplication::WriteScreenShot(char *filename, int width, int height) +{ + D3DVIEWPORT7 vp; + HDC hDC; + HDC hDCImage; + HBITMAP hb; + PBITMAPINFO info; + int dx, dy; + + m_pD3DDevice->GetViewport(&vp); + dx = vp.dwWidth; + dy = vp.dwHeight; + + if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return false; + + hDCImage = CreateCompatibleDC(hDC); + if ( hDCImage == 0 ) + { + m_pddsRenderTarget->ReleaseDC(hDC); + return false; + } + + hb = CreateCompatibleBitmap(hDC, width, height); + if ( hb == 0 ) + { + DeleteDC(hDCImage); + m_pddsRenderTarget->ReleaseDC(hDC); + return false; + } + + SelectObject(hDCImage, hb); + StretchBlt(hDCImage, 0, 0, width, height, hDC, 0, 0, dx, dy, SRCCOPY); + + info = CreateBitmapInfoStruct(hb); + if ( info == 0 ) + { + DeleteObject(hb); + DeleteDC(hDCImage); + m_pddsRenderTarget->ReleaseDC(hDC); + return false; + } + + CreateBMPFile(filename, info, hb, hDCImage); + + DeleteObject(hb); + DeleteDC(hDCImage); + m_pddsRenderTarget->ReleaseDC(hDC); + return true; +} + + +// Initializes an hDC on the rendering surface. + +bool CD3DApplication::GetRenderDC(HDC &hDC) +{ + if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return false; + return true; +} + +// Frees the hDC of the rendering surface. + +bool CD3DApplication::ReleaseRenderDC(HDC &hDC) +{ + m_pddsRenderTarget->ReleaseDC(hDC); + return true; +} + + + + +// Perform the list of all graphics devices available. +// For the device selected, lists the full screen modes +// possible. +// buf* --> nom1<0> nom2<0> <0> + +bool CD3DApplication::EnumDevices(char *bufDevices, int lenDevices, + char *bufModes, int lenModes, + int &totalDevices, int &selectDevices, + int &totalModes, int &selectModes) +{ + D3DEnum_DeviceInfo* pDeviceList; + D3DEnum_DeviceInfo* pDevice; + DDSURFACEDESC2* pddsdMode; + DWORD numDevices, device, mode; + int len; + char text[100]; + + D3DEnum_GetDevices(&pDeviceList, &numDevices); + + selectDevices = -1; + selectModes = -1; + totalModes = 0; + for( device=0 ; devicestrDesc)+1; + if ( len >= lenDevices ) break; // bufDevices full! + strcpy(bufDevices, pDevice->strDesc); + bufDevices += len; + lenDevices -= len; + + if ( pDevice == m_pDeviceInfo ) // select device ? + { + selectDevices = device; + + for( mode=0 ; modedwNumModes ; mode++ ) + { + pddsdMode = &pDevice->pddsdModes[mode]; + + sprintf(text, "%ld x %ld x %ld", + pddsdMode->dwWidth, + pddsdMode->dwHeight, + pddsdMode->ddpfPixelFormat.dwRGBBitCount); + + len = strlen(text)+1; + if ( len >= lenModes ) break; // bufModes full ! + strcpy(bufModes, text); + bufModes += len; + lenModes -= len; + + if ( mode == m_pDeviceInfo->dwCurrentMode ) // select mode ? + { + selectModes = mode; + } + } + bufModes[0] = 0; + totalModes = pDevice->dwNumModes; + } + } + bufDevices[0] = 0; + totalDevices = numDevices; + + return true; +} + +// Indicates whether it is in full screen mode. + +bool CD3DApplication::RetFullScreen() +{ + return !m_pDeviceInfo->bWindowed; +} + +// Change the graphics mode. + +bool CD3DApplication::ChangeDevice(char *deviceName, char *modeName, + bool bFull) +{ + D3DEnum_DeviceInfo* pDeviceList; + D3DEnum_DeviceInfo* pDevice; + DDSURFACEDESC2* pddsdMode; + DWORD numDevices, device, mode; + HRESULT hr; + char text[100]; + + D3DEnum_GetDevices(&pDeviceList, &numDevices); + + for( device=0 ; devicestrDesc, deviceName) == 0 ) // device found ? + { + for( mode=0 ; modedwNumModes ; mode++ ) + { + pddsdMode = &pDevice->pddsdModes[mode]; + + sprintf(text, "%ld x %ld x %ld", + pddsdMode->dwWidth, + pddsdMode->dwHeight, + pddsdMode->ddpfPixelFormat.dwRGBBitCount); + + if ( strcmp(text, modeName) == 0 ) // mode found ? + { + m_pDeviceInfo = pDevice; + pDevice->bWindowed = !bFull; + pDevice->dwCurrentMode = mode; + pDevice->ddsdFullscreenMode = pDevice->pddsdModes[mode]; + + m_bReady = false; + + if ( FAILED( hr = Change3DEnvironment() ) ) + { + return false; + } + + SetProfileString("Device", "Name", deviceName); + SetProfileString("Device", "Mode", modeName); + SetProfileInt("Device", "FullScreen", bFull); + m_bReady = true; + return true; + } + } + } + } + + return false; +} + + + +// Displays error messages in a message box. + +VOID CD3DApplication::DisplayFrameworkError( HRESULT hr, DWORD dwType ) +{ + TCHAR strMsg[512]; + + switch( hr ) + { + case D3DENUMERR_ENGINE: + lstrcpy( strMsg, _T("Could not create 3D Engine application!") ); + break; + case D3DENUMERR_ROBOT: + lstrcpy( strMsg, _T("Could not create Robot application!") ); + break; + case D3DENUMERR_NODIRECTDRAW: + lstrcpy( strMsg, _T("Could not create DirectDraw!") ); + break; + case D3DENUMERR_NOCOMPATIBLEDEVICES: + lstrcpy( strMsg, _T("Could not find any compatible Direct3D\n" + "devices.") ); + break; + case D3DENUMERR_SUGGESTREFRAST: + lstrcpy( strMsg, _T("Could not find any compatible devices.\n\n" + "Try enabling the reference rasterizer using\n" + "EnableRefRast.reg.") ); + break; + case D3DENUMERR_ENUMERATIONFAILED: + lstrcpy( strMsg, _T("Enumeration failed. Your system may be in an\n" + "unstable state and need to be rebooted") ); + break; + case D3DFWERR_INITIALIZATIONFAILED: + lstrcpy( strMsg, _T("Generic initialization error.\n\nEnable " + "debug output for detailed information.") ); + break; + case D3DFWERR_NODIRECTDRAW: + lstrcpy( strMsg, _T("No DirectDraw") ); + break; + case D3DFWERR_NODIRECT3D: + lstrcpy( strMsg, _T("No Direct3D") ); + break; + case D3DFWERR_INVALIDMODE: + lstrcpy( strMsg, _T("COLOBOT requires a 16-bit (or higher) " + "display mode\nto run in a window.\n\nPlease " + "switch your desktop settings accordingly.") ); + break; + case D3DFWERR_COULDNTSETCOOPLEVEL: + lstrcpy( strMsg, _T("Could not set Cooperative Level") ); + break; + case D3DFWERR_NO3DDEVICE: + lstrcpy( strMsg, _T("Could not create the Direct3DDevice object.") ); + + if( MSGWARN_SWITCHEDTOSOFTWARE == dwType ) + lstrcat( strMsg, _T("\nThe 3D hardware chipset may not support" + "\nrendering in the current display mode.") ); + break; + case D3DFWERR_NOZBUFFER: + lstrcpy( strMsg, _T("No ZBuffer") ); + break; + case D3DFWERR_INVALIDZBUFFERDEPTH: + lstrcpy( strMsg, _T("Invalid Z-buffer depth. Try switching modes\n" + "from 16- to 32-bit (or vice versa)") ); + break; + case D3DFWERR_NOVIEWPORT: + lstrcpy( strMsg, _T("No Viewport") ); + break; + case D3DFWERR_NOPRIMARY: + lstrcpy( strMsg, _T("No primary") ); + break; + case D3DFWERR_NOCLIPPER: + lstrcpy( strMsg, _T("No Clipper") ); + break; + case D3DFWERR_BADDISPLAYMODE: + lstrcpy( strMsg, _T("Bad display mode") ); + break; + case D3DFWERR_NOBACKBUFFER: + lstrcpy( strMsg, _T("No backbuffer") ); + break; + case D3DFWERR_NONZEROREFCOUNT: + lstrcpy( strMsg, _T("A DDraw object has a non-zero reference\n" + "count (meaning it was not properly cleaned up)." ) ); + break; + case D3DFWERR_NORENDERTARGET: + lstrcpy( strMsg, _T("No render target") ); + break; + case E_OUTOFMEMORY: + lstrcpy( strMsg, _T("Not enough memory!") ); + break; + case DDERR_OUTOFVIDEOMEMORY: + lstrcpy( strMsg, _T("There was insufficient video memory " + "to use the\nhardware device.") ); + break; + default: + lstrcpy( strMsg, _T("Generic application error.\n\nEnable " + "debug output for detailed information.") ); + } + + if( MSGERR_APPMUSTEXIT == dwType ) + { + lstrcat( strMsg, _T("\n\nCOLOBOT will now exit.") ); + MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK ); + } + else + { + if( MSGWARN_SWITCHEDTOSOFTWARE == dwType ) + lstrcat( strMsg, _T("\n\nSwitching to software rasterizer.") ); + MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK ); + } +} + + diff --git a/src/old/d3dapp.h b/src/old/d3dapp.h index 1126d69..7e217d4 100644 --- a/src/old/d3dapp.h +++ b/src/old/d3dapp.h @@ -1,166 +1,166 @@ -// * 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/. - -// d3dapp.h - -#pragma once - - -#define D3D_OVERLOADS -#include - -#include "math/vector.h" -#include "old/d3dengine.h" -#include "old/d3dframe.h" -#include "old/d3denum.h" -#include "old/d3dutil.h" -#include "old/d3dres.h" -#include "common/misc.h" -#include "common/struct.h" - - -class CInstanceManager; -class CEvent; -class CRobotMain; -class CSound; - - - -class CD3DApplication -{ -public: - CD3DApplication(); - ~CD3DApplication(); - -protected: - LRESULT OnQuerySuspend( DWORD dwFlags ); - LRESULT OnResumeSuspend( DWORD dwData ); - -public: - Error RegQuery(); - Error AudioQuery(); - Error CheckMistery(char *strCmdLine); - int GetVidMemTotal(); - bool IsVideo8MB(); - bool IsVideo32MB(); - HRESULT Create( HINSTANCE, TCHAR* ); - INT Run(); - LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); - VOID Pause( bool bPause ); - Math::Point ConvPosToInterface(HWND hWnd, LPARAM lParam); - void SetMousePos(Math::Point pos); - void StepSimul(float rTime); - char* RetCDpath(); - - void SetShowStat(bool bShow); - bool RetShowStat(); - void SetDebugMode(bool bMode); - bool RetDebugMode(); - bool RetSetupMode(); - - bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); - bool RetFullScreen(); - bool ChangeDevice(char *device, char *mode, bool bFull); - - void FlushPressKey(); - void ResetKey(); - void SetKey(int keyRank, int option, int key); - int RetKey(int keyRank, int option); - - void SetJoystick(bool bEnable); - bool RetJoystick(); - - void SetMouseType(D3DMouse type); - void SetNiceMouse(bool bNice); - bool RetNiceMouse(); - bool RetNiceMouseCap(); - - bool WriteScreenShot(char *filename, int width, int height); - - bool GetRenderDC(HDC &hDC); - bool ReleaseRenderDC(HDC &hDC); - PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); - bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); - -protected: - HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc ); - HRESULT Initialize3DEnvironment(); - HRESULT Change3DEnvironment(); - HRESULT CreateZBuffer(GUID* pDeviceGUID); - HRESULT Render3DEnvironment(); - VOID Cleanup3DEnvironment(); - VOID DeleteDeviceObjects(); - VOID DisplayFrameworkError( HRESULT, DWORD ); - - void InitText(); - void DrawSuppl(); - VOID ShowStats(); - VOID OutputText( DWORD x, DWORD y, TCHAR* str ); - -protected: - CInstanceManager* m_iMan; - CEvent* m_event; - - HINSTANCE m_instance; - HWND m_hWnd; - D3DEnum_DeviceInfo* m_pDeviceInfo; - LPDIRECTDRAW7 m_pDD; - LPDIRECT3D7 m_pD3D; - LPDIRECT3DDEVICE7 m_pD3DDevice; - LPDIRECTDRAWSURFACE7 m_pddsRenderTarget; - DDSURFACEDESC2 m_ddsdRenderTarget; - LPDIRECTDRAWSURFACE7 m_pddsDepthBuffer; - - HANDLE m_thread; - DWORD m_threadId; - - char m_CDpath[100]; - - CD3DFramework7* m_pFramework; - bool m_bActive; - bool m_bActivateApp; - bool m_bReady; - bool m_bJoystick; - - DWORD m_vidMemTotal; - TCHAR* m_strWindowTitle; - bool m_bAppUseZBuffer; - bool m_bAppUseStereo; - bool m_bShowStats; - bool m_bDebugMode; - bool m_bAudioState; - bool m_bAudioTrack; - bool m_bNiceMouse; - bool m_bSetupMode; - HRESULT (*m_fnConfirmDevice)(DDCAPS*, D3DDEVICEDESC7*); - -public: - CD3DEngine* m_pD3DEngine; - CRobotMain* m_pRobotMain; - CSound* m_pSound; - - int m_keyState; - Math::Vector m_axeKey; - Math::Vector m_axeJoy; - bool m_bJoyButton[32]; - Math::Point m_mousePos; - DWORD m_mshMouseWheel; - - float m_aTime; - DWORD m_key[50][2]; -}; - - +// * 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/. + +// d3dapp.h + +#pragma once + + +#define D3D_OVERLOADS +#include + +#include "math/vector.h" +#include "old/d3dengine.h" +#include "old/d3dframe.h" +#include "old/d3denum.h" +#include "old/d3dutil.h" +#include "old/d3dres.h" +#include "common/misc.h" +#include "common/struct.h" + + +class CInstanceManager; +class CEvent; +class CRobotMain; +class CSound; + + + +class CD3DApplication +{ +public: + CD3DApplication(); + ~CD3DApplication(); + +protected: + LRESULT OnQuerySuspend( DWORD dwFlags ); + LRESULT OnResumeSuspend( DWORD dwData ); + +public: + Error RegQuery(); + Error AudioQuery(); + Error CheckMistery(char *strCmdLine); + int GetVidMemTotal(); + bool IsVideo8MB(); + bool IsVideo32MB(); + HRESULT Create( HINSTANCE, TCHAR* ); + INT Run(); + LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); + VOID Pause( bool bPause ); + Math::Point ConvPosToInterface(HWND hWnd, LPARAM lParam); + void SetMousePos(Math::Point pos); + void StepSimul(float rTime); + char* RetCDpath(); + + void SetShowStat(bool bShow); + bool RetShowStat(); + void SetDebugMode(bool bMode); + bool RetDebugMode(); + bool RetSetupMode(); + + bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); + bool RetFullScreen(); + bool ChangeDevice(char *device, char *mode, bool bFull); + + void FlushPressKey(); + void ResetKey(); + void SetKey(int keyRank, int option, int key); + int RetKey(int keyRank, int option); + + void SetJoystick(bool bEnable); + bool RetJoystick(); + + void SetMouseType(D3DMouse type); + void SetNiceMouse(bool bNice); + bool RetNiceMouse(); + bool RetNiceMouseCap(); + + bool WriteScreenShot(char *filename, int width, int height); + + bool GetRenderDC(HDC &hDC); + bool ReleaseRenderDC(HDC &hDC); + PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); + bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); + +protected: + HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc ); + HRESULT Initialize3DEnvironment(); + HRESULT Change3DEnvironment(); + HRESULT CreateZBuffer(GUID* pDeviceGUID); + HRESULT Render3DEnvironment(); + VOID Cleanup3DEnvironment(); + VOID DeleteDeviceObjects(); + VOID DisplayFrameworkError( HRESULT, DWORD ); + + void InitText(); + void DrawSuppl(); + VOID ShowStats(); + VOID OutputText( DWORD x, DWORD y, TCHAR* str ); + +protected: + CInstanceManager* m_iMan; + CEvent* m_event; + + HINSTANCE m_instance; + HWND m_hWnd; + D3DEnum_DeviceInfo* m_pDeviceInfo; + LPDIRECTDRAW7 m_pDD; + LPDIRECT3D7 m_pD3D; + LPDIRECT3DDEVICE7 m_pD3DDevice; + LPDIRECTDRAWSURFACE7 m_pddsRenderTarget; + DDSURFACEDESC2 m_ddsdRenderTarget; + LPDIRECTDRAWSURFACE7 m_pddsDepthBuffer; + + HANDLE m_thread; + DWORD m_threadId; + + char m_CDpath[100]; + + CD3DFramework7* m_pFramework; + bool m_bActive; + bool m_bActivateApp; + bool m_bReady; + bool m_bJoystick; + + DWORD m_vidMemTotal; + TCHAR* m_strWindowTitle; + bool m_bAppUseZBuffer; + bool m_bAppUseStereo; + bool m_bShowStats; + bool m_bDebugMode; + bool m_bAudioState; + bool m_bAudioTrack; + bool m_bNiceMouse; + bool m_bSetupMode; + HRESULT (*m_fnConfirmDevice)(DDCAPS*, D3DDEVICEDESC7*); + +public: + CD3DEngine* m_pD3DEngine; + CRobotMain* m_pRobotMain; + CSound* m_pSound; + + int m_keyState; + Math::Vector m_axeKey; + Math::Vector m_axeJoy; + bool m_bJoyButton[32]; + Math::Point m_mousePos; + DWORD m_mshMouseWheel; + + float m_aTime; + DWORD m_key[50][2]; +}; + + diff --git a/src/old/d3dengine.cpp b/src/old/d3dengine.cpp index e28483d..79e4646 100644 --- a/src/old/d3dengine.cpp +++ b/src/old/d3dengine.cpp @@ -1,5825 +1,5825 @@ -// * 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 - - -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dapp.h" -#include "old/d3dtextr.h" -#include "old/d3dutil.h" -#include "old/d3dmath.h" -#include "old/d3dengine.h" -#include "common/language.h" -#include "common/iman.h" -#include "common/event.h" -#include "common/profile.h" -#include "old/math3d.h" -#include "object/object.h" -#include "ui/interface.h" -#include "old/light.h" -#include "old/text.h" -#include "old/particule.h" -#include "old/terrain.h" -#include "old/water.h" -#include "old/cloud.h" -#include "old/blitz.h" -#include "old/planet.h" -#include "old/sound.h" - - - -const int SIZEBLOC_TEXTURE = 50; -const int SIZEBLOC_TRANSFORM = 100; -const int SIZEBLOC_MINMAX = 5; -const int SIZEBLOC_LIGHT = 10; -const int SIZEBLOC_MATERIAL = 100; -const int 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 = Math::Point(0.5f, 0.5f); - m_mouseType = D3DMOUSENORM; - m_bMouseHide = false; - m_imageSurface = 0; - m_imageCopy = 0; - m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); - m_lookatPt = Math::Vector(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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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() -{ - Math::Matrix mat; - int i; - - for ( i=0 ; 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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 ; itotalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - if ( p3->objRank != objRank ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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 ) 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 ; l1totalUsed ; 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 ; l2totalUsed ; 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 ; l3totalUsed ; 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 ; l4totalUsed ; 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 ; l5totalUsed ; 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 ; ivertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb); - p6->totalUsed += nb; - - if ( bGlobalUpdate ) - { - m_bUpdateGeometry = true; - } - else - { - for ( i=0 ; itotalUsed++; - p5->table[l5] = buffer; - - if ( bGlobalUpdate ) - { - m_bUpdateGeometry = true; - } - else - { - for ( i=0 ; itotalUsed ; i++ ) - { - m_objectParam[objRank].bboxMin.x = Math::Min(buffer->vertex[i].x, m_objectParam[objRank].bboxMin.x); - m_objectParam[objRank].bboxMin.y = Math::Min(buffer->vertex[i].y, m_objectParam[objRank].bboxMin.y); - m_objectParam[objRank].bboxMin.z = Math::Min(buffer->vertex[i].z, m_objectParam[objRank].bboxMin.z); - m_objectParam[objRank].bboxMax.x = Math::Max(buffer->vertex[i].x, m_objectParam[objRank].bboxMax.x); - m_objectParam[objRank].bboxMax.y = Math::Max(buffer->vertex[i].y, m_objectParam[objRank].bboxMax.y); - m_objectParam[objRank].bboxMax.z = Math::Max(buffer->vertex[i].z, m_objectParam[objRank].bboxMax.z); - } - - m_objectParam[objRank].radius = Math::Max(m_objectParam[objRank].bboxMin.Length(), - m_objectParam[objRank].bboxMax.Length()); - } - 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - - if ( Math::IsEqual(p4->min, 0.0f ) && - Math::IsEqual(p4->max, oldLimit[0]) ) - { - p4->max = newLimit[0]; - } - else if ( Math::IsEqual(p4->min, oldLimit[0]) && - Math::IsEqual(p4->max, oldLimit[1]) ) - { - p4->min = newLimit[0]; - p4->max = newLimit[1]; - } - else if ( Math::IsEqual(p4->min, oldLimit[1]) && - Math::IsEqual(p4->max, 1000000.0f ) ) - { - p4->min = newLimit[1]; - } - else if ( Math::IsEqual(p4->min, 0.0f ) && - Math::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 ; l1totalUsed ; 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 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - if ( p3->objRank != objRank ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - if ( p4->min != min || - p4->max != max ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - if ( strcmp(p2->texName2, texName2) == 0 ) continue; // already new - for ( l2=0 ; l2totalUsed ; 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; -//? if ( p2->texName[0] == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - if ( p3->objRank != objRank ) continue; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - if ( p4->min != min || - p4->max != max ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; l5++ ) - { - p6 = p5->table[l5]; - if ( p6 == 0 ) continue; - if ( p6->type == D3DTYPE6T ) - { - pv = &p6->vertex[0]; - for ( l6=0 ; l6totalUsed/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 ; l6totalUsed-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, Math::Vector &min, Math::Vector &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 ; l6tu = pv->z*au+bu; - pv->tv = pv->y*av+bv; - pv ++; - } - } - - if ( mode == D3DMAPPINGY ) - { - for ( l6=0 ; l6tu = pv->x*au+bu; - pv->tv = pv->z*av+bv; - pv ++; - } - } - - if ( mode == D3DMAPPINGZ ) - { - for ( l6=0 ; l6tu = pv->x*au+bu; - pv->tv = pv->y*av+bv; - pv ++; - } - } - - if ( mode == D3DMAPPING1X ) - { - for ( l6=0 ; l6tu = pv->x*au+bu; - pv ++; - } - } - - if ( mode == D3DMAPPING1Y ) - { - for ( l6=0 ; l6tv = pv->y*au+bu; - pv ++; - } - } - - if ( mode == D3DMAPPING1Z ) - { - for ( l6=0 ; l6tu = 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; - Math::Vector 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)-1 ) break; - for ( i=0 ; i<6 ; i++ ) - { - if ( fabs(pv[i+6].x-current.x) > 0.0001f || - fabs(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 ; itotalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - objRank = p3->objRank; - for ( l3=0 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; l5++ ) - { - p6 = p5->table[l5]; - if ( p6 == 0 ) continue; - - for ( i=0 ; itotalUsed ; i++ ) - { - m_objectParam[objRank].bboxMin.x = Math::Min(p6->vertex[i].x, m_objectParam[objRank].bboxMin.x); - m_objectParam[objRank].bboxMin.y = Math::Min(p6->vertex[i].y, m_objectParam[objRank].bboxMin.y); - m_objectParam[objRank].bboxMin.z = Math::Min(p6->vertex[i].z, m_objectParam[objRank].bboxMin.z); - m_objectParam[objRank].bboxMax.x = Math::Max(p6->vertex[i].x, m_objectParam[objRank].bboxMax.x); - m_objectParam[objRank].bboxMax.y = Math::Max(p6->vertex[i].y, m_objectParam[objRank].bboxMax.y); - m_objectParam[objRank].bboxMax.z = Math::Max(p6->vertex[i].z, m_objectParam[objRank].bboxMax.z); - } - - m_objectParam[objRank].radius = Math::Max(m_objectParam[objRank].bboxMin.Length(), - m_objectParam[objRank].bboxMax.Length()); - } - } - } - } - } - - m_bUpdateGeometry = false; -} - - -// Determines whether an object is visible, even partially. -// Transformation of "world" must be done​​! - -bool CD3DEngine::IsVisible(int objRank) -{ - Math::Vector center; - DWORD flags; - float radius; - - radius = m_objectParam[objRank].radius; - center = Math::Vector(0.0f, 0.0f, 0.0f); - { - D3DVECTOR centerD3D = VEC_TO_D3DVEC(center); - m_pD3DDevice->ComputeSphereVisibility(¢erD3D, &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(Math::Point 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - for ( l2=0 ; l2totalUsed ; 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 ; l3totalUsed ; l3++ ) - { - p4 = p3->table[l3]; - if ( p4 == 0 ) continue; - if ( p4->min != 0.0f ) continue; // LOD B or C? - for ( l4=0 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; l5++ ) - { - p6 = p5->table[l5]; - if ( p6 == 0 ) continue; - - if ( p6->type == D3DTYPE6T ) - { - pv = &p6->vertex[0]; - for ( i=0 ; itotalUsed/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 ; itotalUsed-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(Math::Point mouse, D3DVERTEX2 *triangle, - int objRank, float &dist) -{ - Math::Vector p2D[3], p3D; - Math::Point 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 ( !Math::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, Math::Point mouse) -{ - Math::Vector p, pp; - Math::Point 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(Math::Vector &p2D, int objRank, Math::Vector p3D) -{ - p3D = Math::Transform(m_objectParam[objRank].transform, p3D); - p3D = Math::Transform(m_matView, p3D); - - if ( p3D.z < 2.0f ) return false; // behind? - - p2D.x = (p3D.x/p3D.z)*m_matProj.Get(1,1); - p2D.y = (p3D.y/p3D.z)*m_matProj.Get(2,2); - 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() -{ - Math::Vector v; - int i; - float distance; - - if ( s_resol == 0 ) - { - for ( i=0 ; iIsVideo8MB() ) - { - 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); -} - - - -Math::Matrix* CD3DEngine::RetMatView() -{ - return &m_matView; -} - -Math::Matrix* CD3DEngine::RetMatLeftView() -{ - return &m_matLeftView; -} - -Math::Matrix* CD3DEngine::RetMatRightView() -{ - return &m_matRightView; -} - - -// Specifies the location and direction of view. - -void CD3DEngine::SetViewParams(const Math::Vector &vEyePt, - const Math::Vector &vLookatPt, - const Math::Vector &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. - Math::Vector vView = (vLookatPt) - (vEyePt); - vView = CrossProduct( vView, (vUpVec) ); - vView = Normalize( vView ) * fEyeDistance; - - Math::Vector vLeftEyePt = (vEyePt) + vView; - Math::Vector vRightEyePt = (vEyePt) - vView; - - // Set the view matrices - Math::LoadViewMatrix( m_matLeftView, (Math::Vector)vLeftEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); - Math::LoadViewMatrix( m_matRightView, (Math::Vector)vRightEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); - Math::LoadViewMatrix( m_matView, (Math::Vector)vEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); -#else - m_eyePt = vEyePt; - m_lookatPt = vLookatPt; - m_eyeDirH = Math::RotateAngle(vEyePt.x-vLookatPt.x, vEyePt.z-vLookatPt.z); - m_eyeDirV = Math::RotateAngle(Math::DistanceProjected(vEyePt, vLookatPt), vEyePt.y-vLookatPt.y); - - Math::LoadViewMatrix(m_matView, vEyePt, vLookatPt, 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 Math::Matrix &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, Math::Matrix &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= 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 Math::Vector &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 Math::Vector &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 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. - -Math::Vector CD3DEngine::RetEyePt() -{ - return m_eyePt; -} - -Math::Vector 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 ; l1totalUsed ; 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; - Math::Vector pos; - Math::Point 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-Math::Mod(cx, 1.0f); - py = cy-Math::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-Math::Mod(cx, 1.0f); - py = cy-Math::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 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 = Math::Point(ppx-cx, ppy-cy).Length()/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-Math::Mod(cx, 1.0f); - py = cy-Math::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-Math::Point((float)ix, (float)iy).Length()/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 ; iSetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, false); - - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - 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 = Math::Vector(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 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 = Math::Distance(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 = Math::Distance(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 = Math::RotatePoint(-m_shadow[i].angle, Math::Point(radius, radius)); - corner[0].x = rot.x; - corner[0].z = rot.y; - corner[0].y = 0.0f; - - rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(-radius, radius)); - corner[1].x = rot.x; - corner[1].z = rot.y; - corner[1].y = 0.0f; - - rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(radius, -radius)); - corner[2].x = rot.x; - corner[2].z = rot.y; - corner[2].y = 0.0f; - - rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(-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] = Math::CrossProduct(corner[0], m_shadow[i].normal); - corner[1] = Math::CrossProduct(corner[1], m_shadow[i].normal); - corner[2] = Math::CrossProduct(corner[2], m_shadow[i].normal); - corner[3] = Math::CrossProduct(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); - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - 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])); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matView); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - - if ( m_bWaterMode ) m_water->DrawBack(); // draws water - - if ( m_bShadow ) - { - // Draw the field. - p1 = m_objectPointer; - for ( l1=0 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - SetTexture(p2->texName1, 0); - SetTexture(p2->texName2, 1); - for ( l2=0 ; l2totalUsed ; 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; - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - if ( !IsVisible(objRank) ) continue; - m_light->LightUpdate(m_objectParam[objRank].type); - for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - SetTexture(p2->texName1, 0); - SetTexture(p2->texName2, 1); - for ( l2=0 ; l2totalUsed ; 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; - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - if ( !IsVisible(objRank) ) continue; - m_light->LightUpdate(m_objectParam[objRank].type); - for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - SetTexture(p2->texName1, 0); - SetTexture(p2->texName2, 1); - for ( l2=0 ; l2totalUsed ; 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; - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - if ( !IsVisible(objRank) ) continue; - m_light->LightUpdate(m_objectParam[objRank].type); - for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - 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); - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - 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])); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matView); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - - p1 = m_objectPointer; - for ( l1=0 ; l1totalUsed ; l1++ ) - { - p2 = p1->table[l1]; - if ( p2 == 0 ) continue; - SetTexture(p2->texName1, 0); - SetTexture(p2->texName2, 1); - for ( l2=0 ; l2totalUsed ; l2++ ) - { - p3 = p2->table[l2]; - if ( p3 == 0 ) continue; - objRank = p3->objRank; - if ( !m_objectParam[objRank].bDrawFront ) continue; - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - if ( !IsVisible(objRank) ) continue; - m_light->LightUpdate(m_objectParam[objRank].type); - for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) - { - p5 = p4->table[l4]; - if ( p5 == 0 ) continue; - for ( l5=0 ; l5totalUsed ; 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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - } - - 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]; - Math::Point 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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - 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(Math::Point p1, Math::Point p2, char *name) -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector n; - float u1, u2, v1, v2, h, a; - - n = Math::Vector(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-Math::PI*0.15f; - if ( a > Math::PI ) a -= Math::PI*2.0f; // a = -Math::PI..Math::PI - if ( a > Math::PI/4.0f ) a = Math::PI/4.0f; - if ( a < -Math::PI/4.0f ) a = -Math::PI/4.0f; - - u1 = -m_eyeDirH/Math::PI; - u2 = u1+1.0f/Math::PI; -//? u1 = -m_eyeDirH/(Math::PI*2.0f); -//? u2 = u1+1.0f/(Math::PI*2.0f); - - v1 = (1.0f-h)*(0.5f+a/(2.0f*Math::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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(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() -{ - Math::Point 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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - m_planet->Draw(); // draws the planets -} - -// Draws the image foreground. - -void CD3DEngine::DrawFrontsize() -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector n; - Math::Point p1, p2; - float u1, u2, v1, v2; - - if ( m_frontsizeName[0] == 0 ) return; - - n = Math::Vector(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/(Math::PI*0.6f)+Math::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(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - 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]; - Math::Point 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); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); - } - { - D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - 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, Math::Point &min, Math::Point &max) -{ - Math::Vector 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() -{ - Math::Point 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 = Math::Min(min.x, omin.x); - min.y = Math::Min(min.y, omin.y); - max.x = Math::Max(max.x, omax.x); - max.y = Math::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(Math::Point &p1, Math::Point &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; - Math::Vector v, vv; - - return false; - //? - vv = Math::Vector(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(Math::Point *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, - Math::Point ts, Math::Point ti, - Math::Point *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 0.01f && fabs(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 && fabs(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 ( fabs(color.r-colorRef1.r)+ - fabs(color.g-colorRef1.g)+ - fabs(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 && - fabs(color.r-colorRef2.r)+ - fabs(color.g-colorRef2.g)+ - fabs(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 0 ) - { - for ( y=0 ; y=-dx ; x-- ) - { - m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX]; - } - } - } - - if ( dy > 0 ) - { - for ( y=0 ; 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; -//? Math::LoadProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[m_rankView]); - Math::LoadProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[0]); -} - -float CD3DEngine::RetFocus() -{ - return m_focus; -} - -// - -void CD3DEngine::UpdateMatProj() -{ - D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); -} - - - -// 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 Math::Vector &pos) -{ - return ( Math::Distance(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. - m_matWorldInterface.LoadIdentity(); - - m_matViewInterface.LoadIdentity(); - m_matViewInterface.Set(1, 4, -0.5f); - m_matViewInterface.Set(2, 4, -0.5f); - m_matViewInterface.Set(3, 4, 1.0f); - - m_matProjInterface.LoadIdentity(); - m_matProjInterface.Set(1, 1, 2.0f); - m_matProjInterface.Set(2, 2, 2.0f); - m_matProjInterface.Set(4, 3, 1.0f); - m_matProjInterface.Set(3, 4, -1.0f); - m_matProjInterface.Set(4, 4, 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(Math::Point pos) -{ - m_mousePos = pos; - m_app->SetMousePos(pos); -} - -void CD3DEngine::SetMousePos(Math::Point pos) -{ - m_mousePos = pos; -} - -Math::Point 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; - Math::Point pos, ppos, dim; - int i; - - struct Mouse - { - D3DMouse type; - int icon1, icon2, iconShadow; - int mode1, mode2; - float hotx, hoty; - }; - - 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(Math::Point pos, Math::Point dim, int icon) -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Point p1, p2; - Math::Vector 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 = Math::Vector(0.0f, 0.0f, -1.0f); // normal - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - AddStatisticTriangle(2); -} - +// * 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 + + +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dapp.h" +#include "old/d3dtextr.h" +#include "old/d3dutil.h" +#include "old/d3dmath.h" +#include "old/d3dengine.h" +#include "common/language.h" +#include "common/iman.h" +#include "common/event.h" +#include "common/profile.h" +#include "old/math3d.h" +#include "object/object.h" +#include "ui/interface.h" +#include "old/light.h" +#include "old/text.h" +#include "old/particule.h" +#include "old/terrain.h" +#include "old/water.h" +#include "old/cloud.h" +#include "old/blitz.h" +#include "old/planet.h" +#include "old/sound.h" + + + +const int SIZEBLOC_TEXTURE = 50; +const int SIZEBLOC_TRANSFORM = 100; +const int SIZEBLOC_MINMAX = 5; +const int SIZEBLOC_LIGHT = 10; +const int SIZEBLOC_MATERIAL = 100; +const int 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 = Math::Point(0.5f, 0.5f); + m_mouseType = D3DMOUSENORM; + m_bMouseHide = false; + m_imageSurface = 0; + m_imageCopy = 0; + m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); + m_lookatPt = Math::Vector(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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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() +{ + Math::Matrix mat; + int i; + + for ( i=0 ; 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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 ; itotalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + if ( p3->objRank != objRank ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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 ) 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 ; l1totalUsed ; 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 ; l2totalUsed ; 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 ; l3totalUsed ; 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 ; l4totalUsed ; 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 ; l5totalUsed ; 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 ; ivertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb); + p6->totalUsed += nb; + + if ( bGlobalUpdate ) + { + m_bUpdateGeometry = true; + } + else + { + for ( i=0 ; itotalUsed++; + p5->table[l5] = buffer; + + if ( bGlobalUpdate ) + { + m_bUpdateGeometry = true; + } + else + { + for ( i=0 ; itotalUsed ; i++ ) + { + m_objectParam[objRank].bboxMin.x = Math::Min(buffer->vertex[i].x, m_objectParam[objRank].bboxMin.x); + m_objectParam[objRank].bboxMin.y = Math::Min(buffer->vertex[i].y, m_objectParam[objRank].bboxMin.y); + m_objectParam[objRank].bboxMin.z = Math::Min(buffer->vertex[i].z, m_objectParam[objRank].bboxMin.z); + m_objectParam[objRank].bboxMax.x = Math::Max(buffer->vertex[i].x, m_objectParam[objRank].bboxMax.x); + m_objectParam[objRank].bboxMax.y = Math::Max(buffer->vertex[i].y, m_objectParam[objRank].bboxMax.y); + m_objectParam[objRank].bboxMax.z = Math::Max(buffer->vertex[i].z, m_objectParam[objRank].bboxMax.z); + } + + m_objectParam[objRank].radius = Math::Max(m_objectParam[objRank].bboxMin.Length(), + m_objectParam[objRank].bboxMax.Length()); + } + 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + + if ( Math::IsEqual(p4->min, 0.0f ) && + Math::IsEqual(p4->max, oldLimit[0]) ) + { + p4->max = newLimit[0]; + } + else if ( Math::IsEqual(p4->min, oldLimit[0]) && + Math::IsEqual(p4->max, oldLimit[1]) ) + { + p4->min = newLimit[0]; + p4->max = newLimit[1]; + } + else if ( Math::IsEqual(p4->min, oldLimit[1]) && + Math::IsEqual(p4->max, 1000000.0f ) ) + { + p4->min = newLimit[1]; + } + else if ( Math::IsEqual(p4->min, 0.0f ) && + Math::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 ; l1totalUsed ; 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 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + if ( p3->objRank != objRank ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + if ( p4->min != min || + p4->max != max ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + if ( strcmp(p2->texName2, texName2) == 0 ) continue; // already new + for ( l2=0 ; l2totalUsed ; 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; +//? if ( p2->texName[0] == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + if ( p3->objRank != objRank ) continue; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + if ( p4->min != min || + p4->max != max ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; l5++ ) + { + p6 = p5->table[l5]; + if ( p6 == 0 ) continue; + if ( p6->type == D3DTYPE6T ) + { + pv = &p6->vertex[0]; + for ( l6=0 ; l6totalUsed/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 ; l6totalUsed-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, Math::Vector &min, Math::Vector &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 ; l6tu = pv->z*au+bu; + pv->tv = pv->y*av+bv; + pv ++; + } + } + + if ( mode == D3DMAPPINGY ) + { + for ( l6=0 ; l6tu = pv->x*au+bu; + pv->tv = pv->z*av+bv; + pv ++; + } + } + + if ( mode == D3DMAPPINGZ ) + { + for ( l6=0 ; l6tu = pv->x*au+bu; + pv->tv = pv->y*av+bv; + pv ++; + } + } + + if ( mode == D3DMAPPING1X ) + { + for ( l6=0 ; l6tu = pv->x*au+bu; + pv ++; + } + } + + if ( mode == D3DMAPPING1Y ) + { + for ( l6=0 ; l6tv = pv->y*au+bu; + pv ++; + } + } + + if ( mode == D3DMAPPING1Z ) + { + for ( l6=0 ; l6tu = 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; + Math::Vector 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)-1 ) break; + for ( i=0 ; i<6 ; i++ ) + { + if ( fabs(pv[i+6].x-current.x) > 0.0001f || + fabs(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 ; itotalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + objRank = p3->objRank; + for ( l3=0 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; l5++ ) + { + p6 = p5->table[l5]; + if ( p6 == 0 ) continue; + + for ( i=0 ; itotalUsed ; i++ ) + { + m_objectParam[objRank].bboxMin.x = Math::Min(p6->vertex[i].x, m_objectParam[objRank].bboxMin.x); + m_objectParam[objRank].bboxMin.y = Math::Min(p6->vertex[i].y, m_objectParam[objRank].bboxMin.y); + m_objectParam[objRank].bboxMin.z = Math::Min(p6->vertex[i].z, m_objectParam[objRank].bboxMin.z); + m_objectParam[objRank].bboxMax.x = Math::Max(p6->vertex[i].x, m_objectParam[objRank].bboxMax.x); + m_objectParam[objRank].bboxMax.y = Math::Max(p6->vertex[i].y, m_objectParam[objRank].bboxMax.y); + m_objectParam[objRank].bboxMax.z = Math::Max(p6->vertex[i].z, m_objectParam[objRank].bboxMax.z); + } + + m_objectParam[objRank].radius = Math::Max(m_objectParam[objRank].bboxMin.Length(), + m_objectParam[objRank].bboxMax.Length()); + } + } + } + } + } + + m_bUpdateGeometry = false; +} + + +// Determines whether an object is visible, even partially. +// Transformation of "world" must be done​​! + +bool CD3DEngine::IsVisible(int objRank) +{ + Math::Vector center; + DWORD flags; + float radius; + + radius = m_objectParam[objRank].radius; + center = Math::Vector(0.0f, 0.0f, 0.0f); + { + D3DVECTOR centerD3D = VEC_TO_D3DVEC(center); + m_pD3DDevice->ComputeSphereVisibility(¢erD3D, &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(Math::Point 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + for ( l2=0 ; l2totalUsed ; 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 ; l3totalUsed ; l3++ ) + { + p4 = p3->table[l3]; + if ( p4 == 0 ) continue; + if ( p4->min != 0.0f ) continue; // LOD B or C? + for ( l4=0 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; l5++ ) + { + p6 = p5->table[l5]; + if ( p6 == 0 ) continue; + + if ( p6->type == D3DTYPE6T ) + { + pv = &p6->vertex[0]; + for ( i=0 ; itotalUsed/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 ; itotalUsed-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(Math::Point mouse, D3DVERTEX2 *triangle, + int objRank, float &dist) +{ + Math::Vector p2D[3], p3D; + Math::Point 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 ( !Math::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, Math::Point mouse) +{ + Math::Vector p, pp; + Math::Point 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(Math::Vector &p2D, int objRank, Math::Vector p3D) +{ + p3D = Math::Transform(m_objectParam[objRank].transform, p3D); + p3D = Math::Transform(m_matView, p3D); + + if ( p3D.z < 2.0f ) return false; // behind? + + p2D.x = (p3D.x/p3D.z)*m_matProj.Get(1,1); + p2D.y = (p3D.y/p3D.z)*m_matProj.Get(2,2); + 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() +{ + Math::Vector v; + int i; + float distance; + + if ( s_resol == 0 ) + { + for ( i=0 ; iIsVideo8MB() ) + { + 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); +} + + + +Math::Matrix* CD3DEngine::RetMatView() +{ + return &m_matView; +} + +Math::Matrix* CD3DEngine::RetMatLeftView() +{ + return &m_matLeftView; +} + +Math::Matrix* CD3DEngine::RetMatRightView() +{ + return &m_matRightView; +} + + +// Specifies the location and direction of view. + +void CD3DEngine::SetViewParams(const Math::Vector &vEyePt, + const Math::Vector &vLookatPt, + const Math::Vector &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. + Math::Vector vView = (vLookatPt) - (vEyePt); + vView = CrossProduct( vView, (vUpVec) ); + vView = Normalize( vView ) * fEyeDistance; + + Math::Vector vLeftEyePt = (vEyePt) + vView; + Math::Vector vRightEyePt = (vEyePt) - vView; + + // Set the view matrices + Math::LoadViewMatrix( m_matLeftView, (Math::Vector)vLeftEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); + Math::LoadViewMatrix( m_matRightView, (Math::Vector)vRightEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); + Math::LoadViewMatrix( m_matView, (Math::Vector)vEyePt, (Math::Vector)vLookatPt, (Math::Vector)vUpVec ); +#else + m_eyePt = vEyePt; + m_lookatPt = vLookatPt; + m_eyeDirH = Math::RotateAngle(vEyePt.x-vLookatPt.x, vEyePt.z-vLookatPt.z); + m_eyeDirV = Math::RotateAngle(Math::DistanceProjected(vEyePt, vLookatPt), vEyePt.y-vLookatPt.y); + + Math::LoadViewMatrix(m_matView, vEyePt, vLookatPt, 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 Math::Matrix &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, Math::Matrix &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= 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 Math::Vector &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 Math::Vector &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 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. + +Math::Vector CD3DEngine::RetEyePt() +{ + return m_eyePt; +} + +Math::Vector 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 ; l1totalUsed ; 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; + Math::Vector pos; + Math::Point 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-Math::Mod(cx, 1.0f); + py = cy-Math::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-Math::Mod(cx, 1.0f); + py = cy-Math::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 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 = Math::Point(ppx-cx, ppy-cy).Length()/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-Math::Mod(cx, 1.0f); + py = cy-Math::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-Math::Point((float)ix, (float)iy).Length()/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 ; iSetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + 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 = Math::Vector(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 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 = Math::Distance(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 = Math::Distance(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 = Math::RotatePoint(-m_shadow[i].angle, Math::Point(radius, radius)); + corner[0].x = rot.x; + corner[0].z = rot.y; + corner[0].y = 0.0f; + + rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(-radius, radius)); + corner[1].x = rot.x; + corner[1].z = rot.y; + corner[1].y = 0.0f; + + rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(radius, -radius)); + corner[2].x = rot.x; + corner[2].z = rot.y; + corner[2].y = 0.0f; + + rot = Math::RotatePoint(-m_shadow[i].angle, Math::Point(-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] = Math::CrossProduct(corner[0], m_shadow[i].normal); + corner[1] = Math::CrossProduct(corner[1], m_shadow[i].normal); + corner[2] = Math::CrossProduct(corner[2], m_shadow[i].normal); + corner[3] = Math::CrossProduct(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); + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + 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])); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matView); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + + if ( m_bWaterMode ) m_water->DrawBack(); // draws water + + if ( m_bShadow ) + { + // Draw the field. + p1 = m_objectPointer; + for ( l1=0 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + SetTexture(p2->texName1, 0); + SetTexture(p2->texName2, 1); + for ( l2=0 ; l2totalUsed ; 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; + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + if ( !IsVisible(objRank) ) continue; + m_light->LightUpdate(m_objectParam[objRank].type); + for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + SetTexture(p2->texName1, 0); + SetTexture(p2->texName2, 1); + for ( l2=0 ; l2totalUsed ; 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; + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + if ( !IsVisible(objRank) ) continue; + m_light->LightUpdate(m_objectParam[objRank].type); + for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + SetTexture(p2->texName1, 0); + SetTexture(p2->texName2, 1); + for ( l2=0 ; l2totalUsed ; 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; + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + if ( !IsVisible(objRank) ) continue; + m_light->LightUpdate(m_objectParam[objRank].type); + for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + 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); + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + 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])); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matView); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + + p1 = m_objectPointer; + for ( l1=0 ; l1totalUsed ; l1++ ) + { + p2 = p1->table[l1]; + if ( p2 == 0 ) continue; + SetTexture(p2->texName1, 0); + SetTexture(p2->texName2, 1); + for ( l2=0 ; l2totalUsed ; l2++ ) + { + p3 = p2->table[l2]; + if ( p3 == 0 ) continue; + objRank = p3->objRank; + if ( !m_objectParam[objRank].bDrawFront ) continue; + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_objectParam[objRank].transform); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + if ( !IsVisible(objRank) ) continue; + m_light->LightUpdate(m_objectParam[objRank].type); + for ( l3=0 ; l3totalUsed ; 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 ; l4totalUsed ; l4++ ) + { + p5 = p4->table[l4]; + if ( p5 == 0 ) continue; + for ( l5=0 ; l5totalUsed ; 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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + } + + 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]; + Math::Point 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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + 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(Math::Point p1, Math::Point p2, char *name) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector n; + float u1, u2, v1, v2, h, a; + + n = Math::Vector(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-Math::PI*0.15f; + if ( a > Math::PI ) a -= Math::PI*2.0f; // a = -Math::PI..Math::PI + if ( a > Math::PI/4.0f ) a = Math::PI/4.0f; + if ( a < -Math::PI/4.0f ) a = -Math::PI/4.0f; + + u1 = -m_eyeDirH/Math::PI; + u2 = u1+1.0f/Math::PI; +//? u1 = -m_eyeDirH/(Math::PI*2.0f); +//? u2 = u1+1.0f/(Math::PI*2.0f); + + v1 = (1.0f-h)*(0.5f+a/(2.0f*Math::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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(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() +{ + Math::Point 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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + m_planet->Draw(); // draws the planets +} + +// Draws the image foreground. + +void CD3DEngine::DrawFrontsize() +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector n; + Math::Point p1, p2; + float u1, u2, v1, v2; + + if ( m_frontsizeName[0] == 0 ) return; + + n = Math::Vector(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/(Math::PI*0.6f)+Math::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(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + 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]; + Math::Point 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); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matViewInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProjInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); + } + { + D3DMATRIX mat = MAT_TO_D3DMAT(m_matWorldInterface); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + 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, Math::Point &min, Math::Point &max) +{ + Math::Vector 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() +{ + Math::Point 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 = Math::Min(min.x, omin.x); + min.y = Math::Min(min.y, omin.y); + max.x = Math::Max(max.x, omax.x); + max.y = Math::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(Math::Point &p1, Math::Point &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; + Math::Vector v, vv; + + return false; + //? + vv = Math::Vector(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(Math::Point *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, + Math::Point ts, Math::Point ti, + Math::Point *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 0.01f && fabs(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 && fabs(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 ( fabs(color.r-colorRef1.r)+ + fabs(color.g-colorRef1.g)+ + fabs(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 && + fabs(color.r-colorRef2.r)+ + fabs(color.g-colorRef2.g)+ + fabs(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 0 ) + { + for ( y=0 ; y=-dx ; x-- ) + { + m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX]; + } + } + } + + if ( dy > 0 ) + { + for ( y=0 ; 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; +//? Math::LoadProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[m_rankView]); + Math::LoadProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[0]); +} + +float CD3DEngine::RetFocus() +{ + return m_focus; +} + +// + +void CD3DEngine::UpdateMatProj() +{ + D3DMATRIX mat = MAT_TO_D3DMAT(m_matProj); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &mat); +} + + + +// 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 Math::Vector &pos) +{ + return ( Math::Distance(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. + m_matWorldInterface.LoadIdentity(); + + m_matViewInterface.LoadIdentity(); + m_matViewInterface.Set(1, 4, -0.5f); + m_matViewInterface.Set(2, 4, -0.5f); + m_matViewInterface.Set(3, 4, 1.0f); + + m_matProjInterface.LoadIdentity(); + m_matProjInterface.Set(1, 1, 2.0f); + m_matProjInterface.Set(2, 2, 2.0f); + m_matProjInterface.Set(4, 3, 1.0f); + m_matProjInterface.Set(3, 4, -1.0f); + m_matProjInterface.Set(4, 4, 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(Math::Point pos) +{ + m_mousePos = pos; + m_app->SetMousePos(pos); +} + +void CD3DEngine::SetMousePos(Math::Point pos) +{ + m_mousePos = pos; +} + +Math::Point 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; + Math::Point pos, ppos, dim; + int i; + + struct Mouse + { + D3DMouse type; + int icon1, icon2, iconShadow; + int mode1, mode2; + float hotx, hoty; + }; + + 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(Math::Point pos, Math::Point dim, int icon) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Point p1, p2; + Math::Vector 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 = Math::Vector(0.0f, 0.0f, -1.0f); // normal + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + AddStatisticTriangle(2); +} + diff --git a/src/old/d3dengine.h b/src/old/d3dengine.h index d028d2c..700e7b3 100644 --- a/src/old/d3dengine.h +++ b/src/old/d3dengine.h @@ -1,676 +1,678 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -// d3dengine.h - -#pragma once - - -#include "math/point.h" -#include "math/vector.h" -#include "math/matrix.h" -#include "common/struct.h" - - -class CD3DApplication; -class CInstanceManager; -class CObject; -class CLight; -class CText; -class CParticule; -class CWater; -class CCloud; -class CBlitz; -class CPlanet; -class CSound; -class CTerrain; - - -const int D3DMAXOBJECT = 1200; -const int D3DMAXSHADOW = 500; -const int D3DMAXGROUNDSPOT = 100; - - -enum D3DTypeObj -{ - TYPENULL = 0, // object doesn't exist - TYPETERRAIN = 1, // terrain - TYPEFIX = 2, // fixed object - TYPEVEHICULE = 3, // moving object - TYPEDESCENDANT = 4, // part of a moving object - TYPEQUARTZ = 5, // fixed object type quartz - TYPEMETAL = 6, // fixed object type metal -}; - -enum D3DTypeTri -{ - D3DTYPE6T = 1, // triangles - D3DTYPE6S = 2, // surfaces -}; - -enum D3DMaping -{ - D3DMAPPINGX = 1, - D3DMAPPINGY = 2, - D3DMAPPINGZ = 3, - D3DMAPPING1X = 4, - D3DMAPPING1Y = 5, - D3DMAPPING1Z = 6, -}; - -enum D3DMouse -{ - D3DMOUSEHIDE = 0, // no mouse - D3DMOUSENORM = 1, - D3DMOUSEWAIT = 2, - D3DMOUSEEDIT = 3, - D3DMOUSEHAND = 4, - D3DMOUSECROSS = 5, - D3DMOUSESHOW = 6, - D3DMOUSENO = 7, - D3DMOUSEMOVE = 8, // + - D3DMOUSEMOVEH = 9, // - - D3DMOUSEMOVEV = 10, // | - D3DMOUSEMOVED = 11, // / - D3DMOUSEMOVEI = 12, // \ // - D3DMOUSESCROLLL = 13, // << - D3DMOUSESCROLLR = 14, // >> - D3DMOUSESCROLLU = 15, // ^ - D3DMOUSESCROLLD = 16, // v - D3DMOUSETARGET = 17, -}; - -enum D3DShadowType -{ - D3DSHADOWNORM = 0, - D3DSHADOWWORM = 1, -}; - - -const int D3DSTATENORMAL = 0; // normal opaque materials -const int D3DSTATETTb = (1<<0); // the transparent texture (black = no) -const int D3DSTATETTw = (1<<1); // the transparent texture (white = no) -const int D3DSTATETD = (1<<2); // the transparent diffuse color -const int D3DSTATEWRAP = (1<<3); // texture wrappe -const int D3DSTATECLAMP = (1<<4); // texture borders with solid color -const int D3DSTATELIGHT = (1<<5); // light texture (ambient max) -const int D3DSTATEDUALb = (1<<6); // double black texturing -const int D3DSTATEDUALw = (1<<7); // double white texturing -const int D3DSTATEPART1 = (1<<8); // part 1 (no change in. MOD!) -const int D3DSTATEPART2 = (1<<9); // part 2 -const int D3DSTATEPART3 = (1<<10); // part 3 -const int D3DSTATEPART4 = (1<<11); // part 4 -const int D3DSTATE2FACE = (1<<12); // double-sided face -const int D3DSTATEALPHA = (1<<13); // image using alpha channel -const int D3DSTATESECOND = (1<<14); // always use 2nd floor texturing -const int D3DSTATEFOG = (1<<15); // causes the fog -const int D3DSTATETCb = (1<<16); // the transparent color (black = no) -const int D3DSTATETCw = (1<<17); // the transparent color (white = no) - - -struct D3DTriangle -{ - D3DVERTEX2 triangle[3]; - D3DMATERIAL7 material; - int state; - char texName1[20]; - char texName2[20]; -}; - - -struct D3DObjLevel6 -{ - int totalPossible; - int totalUsed; - D3DMATERIAL7 material; - int state; - D3DTypeTri type; // D3DTYPE6x - D3DVERTEX2 vertex[1]; -}; - -struct D3DObjLevel5 -{ - int totalPossible; - int totalUsed; - int reserve; - D3DObjLevel6* table[1]; -}; - -struct D3DObjLevel4 -{ - int totalPossible; - int totalUsed; - float min, max; - D3DObjLevel5* table[1]; -}; - -struct D3DObjLevel3 -{ - int totalPossible; - int totalUsed; - int objRank; - D3DObjLevel4* table[1]; -}; - -struct D3DObjLevel2 -{ - int totalPossible; - int totalUsed; - char texName1[20]; - char texName2[20]; - D3DObjLevel3* table[1]; -}; - -struct D3DObjLevel1 -{ - int totalPossible; - int totalUsed; - D3DObjLevel2* table[1]; -}; - - -struct D3DObject -{ - char bUsed; // true -> object exists - char bVisible; // true -> visible object - char bDrawWorld; // true -> shape behind the interface - char bDrawFront; // true -> shape before the interface - int totalTriangle; // number of triangles used - D3DTypeObj type; // type of the object (TYPE*) - Math::Matrix transform; // transformation matrix - float distance; // distance point of view - original - Math::Vector bboxMin; // bounding box of the object - Math::Vector bboxMax; // (the origin 0, 0, 0 is always included) - float radius; // radius of the sphere at the origin - int shadowRank; // rank of the associated shadow - float transparency; // transparency of the object (0 .. 1) -}; - -struct D3DShadow -{ - char bUsed; // true -> object exists - char bHide; // true -> invisible shadow (object carried by ex.) - int objRank; // rank of the object - D3DShadowType type; // type of shadow - Math::Vector pos; // position for the shadow - Math::Vector normal; // normal terrain - float angle; // angle of the shadow - float radius; // radius of the shadow - float intensity; // intensity of the shadow - float height; // height from the ground -}; - -struct D3DGroundSpot -{ - char bUsed; // true -> object exists - D3DCOLORVALUE color; // color of the shadow - float min, max; // altitudes min / max - float smooth; // transition area - Math::Vector pos; // position for the shadow - float radius; // radius of the shadow - Math::Vector drawPos; // drawn to position the shade - float drawRadius; // radius of the shadow drawn -}; - -struct D3DGroundMark -{ - char bUsed; // true -> object exists - char bDraw; // true -> drawn mark - int phase; // 1 = increase, 2 = fixed, 3 = decrease - float delay[3]; // time for 3 phases - float fix; // fixed time - Math::Vector pos; // position for marks - float radius; // radius of marks - float intensity; // color intensity - Math::Vector drawPos; // drawn in position marks - float drawRadius; // radius marks drawn - float drawIntensity; // current drawn - int dx, dy; // dimensions table - char* table; // pointer to the table -}; - - - -class CD3DEngine -{ -public: - CD3DEngine(CInstanceManager *iMan, CD3DApplication *app); - ~CD3DEngine(); - - void SetD3DDevice(LPDIRECT3DDEVICE7 device); - LPDIRECT3DDEVICE7 RetD3DDevice(); - - void SetTerrain(CTerrain* terrain); - - bool WriteProfile(); - - void SetPause(bool bPause); - bool RetPause(); - - void SetMovieLock(bool bLock); - bool RetMovieLock(); - - void SetShowStat(bool bShow); - bool RetShowStat(); - - void SetRenderEnable(bool bEnable); - - HRESULT OneTimeSceneInit(); - HRESULT InitDeviceObjects(); - HRESULT DeleteDeviceObjects(); - HRESULT RestoreSurfaces(); - HRESULT Render(); - HRESULT FrameMove(float rTime); - void StepSimul(float rTime); - HRESULT FinalCleanup(); - void AddStatisticTriangle(int nb); - int RetStatisticTriangle(); - void SetHiliteRank(int *rankList); - bool GetHilite(Math::Point &p1, Math::Point &p2); - bool GetSpriteCoord(int &x, int &y); - void SetInfoText(int line, char* text); - char* RetInfoText(int line); - LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - void FirstExecuteAdapt(bool bFirst); - int GetVidMemTotal(); - bool IsVideo8MB(); - bool IsVideo32MB(); - - bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); - bool RetFullScreen(); - bool ChangeDevice(char *device, char *mode, bool bFull); - - Math::Matrix* RetMatView(); - Math::Matrix* RetMatLeftView(); - Math::Matrix* RetMatRightView(); - - void TimeInit(); - void TimeEnterGel(); - void TimeExitGel(); - float TimeGet(); - - int RetRestCreate(); - int CreateObject(); - void FlushObject(); - bool DeleteObject(int objRank); - bool SetDrawWorld(int objRank, bool bDraw); - bool SetDrawFront(int objRank, bool bDraw); - bool AddTriangle(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); - bool AddSurface(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); - bool AddQuick(int objRank, D3DObjLevel6* buffer, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); - D3DObjLevel6* SearchTriangle(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max); - void ChangeLOD(); - bool ChangeSecondTexture(int objRank, char* texName2); - int RetTotalTriangles(int objRank); - int GetTriangles(int objRank, float min, float max, D3DTriangle* buffer, int size, float percent); - bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max); - bool ChangeTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float au, float bu, float av, float bv); - bool TrackTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float pos, float factor, float tl, float ts, float tt); - bool SetObjectTransform(int objRank, const Math::Matrix &transform); - bool GetObjectTransform(int objRank, Math::Matrix &transform); - bool SetObjectType(int objRank, D3DTypeObj type); - D3DTypeObj RetObjectType(int objRank); - bool SetObjectTransparency(int objRank, float value); - - bool ShadowCreate(int objRank); - void ShadowDelete(int objRank); - bool SetObjectShadowHide(int objRank, bool bHide); - bool SetObjectShadowType(int objRank, D3DShadowType type); - bool SetObjectShadowPos(int objRank, const Math::Vector &pos); - bool SetObjectShadowNormal(int objRank, const Math::Vector &n); - bool SetObjectShadowAngle(int objRank, float angle); - bool SetObjectShadowRadius(int objRank, float radius); - bool SetObjectShadowIntensity(int objRank, float intensity); - bool SetObjectShadowHeight(int objRank, float h); - float RetObjectShadowRadius(int objRank); - - void GroundSpotFlush(); - int GroundSpotCreate(); - void GroundSpotDelete(int rank); - bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos); - bool SetObjectGroundSpotRadius(int rank, float radius); - bool SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color); - bool SetObjectGroundSpotMinMax(int rank, float min, float max); - bool SetObjectGroundSpotSmooth(int rank, float smooth); - - int GroundMarkCreate(Math::Vector pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table); - bool GroundMarkDelete(int rank); - - void Update(); - - void SetViewParams(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, const Math::Vector &vUpVec, FLOAT fEyeDistance); - - bool FreeTexture(char* name); - bool LoadTexture(char* name, int stage=0); - bool LoadAllTexture(); - - void SetLimitLOD(int rank, float limit); - float RetLimitLOD(int rank, bool bLast=false); - - void SetTerrainVision(float vision); - - void SetGroundSpot(bool bMode); - bool RetGroundSpot(); - void SetShadow(bool bMode); - bool RetShadow(); - void SetDirty(bool bMode); - bool RetDirty(); - void SetFog(bool bMode); - bool RetFog(); - bool RetStateColor(); - - void SetSecondTexture(int texNum); - int RetSecondTexture(); - - void SetRankView(int rank); - int RetRankView(); - - void SetDrawWorld(bool bDraw); - void SetDrawFront(bool bDraw); - - void SetAmbiantColor(D3DCOLOR color, int rank=0); - D3DCOLOR RetAmbiantColor(int rank=0); - - void SetWaterAddColor(D3DCOLORVALUE color); - D3DCOLORVALUE RetWaterAddColor(); - - void SetFogColor(D3DCOLOR color, int rank=0); - D3DCOLOR RetFogColor(int rank=0); - - void SetDeepView(float length, int rank=0, bool bRef=false); - float RetDeepView(int rank=0); - - void SetFogStart(float start, int rank=0); - float RetFogStart(int rank=0); - - void SetBackground(char *name, D3DCOLOR up=0, D3DCOLOR down=0, D3DCOLOR cloudUp=0, D3DCOLOR cloudDown=0, bool bFull=false, bool bQuarter=false); - void RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down, D3DCOLOR &cloudUp, D3DCOLOR &cloudDown, bool &bFull, bool &bQuarter); - void SetFrontsizeName(char *name); - void SetOverFront(bool bFront); - void SetOverColor(D3DCOLOR color=0, int mode=D3DSTATETCb); - - void SetParticuleDensity(float value); - float RetParticuleDensity(); - float ParticuleAdapt(float factor); - - void SetClippingDistance(float value); - float RetClippingDistance(); - - void SetObjectDetail(float value); - float RetObjectDetail(); - - void SetGadgetQuantity(float value); - float RetGadgetQuantity(); - - void SetTextureQuality(int value); - int RetTextureQuality(); - - void SetTotoMode(bool bPresent); - bool RetTotoMode(); - - void SetLensMode(bool bPresent); - bool RetLensMode(); - - void SetWaterMode(bool bPresent); - bool RetWaterMode(); - - void SetBlitzMode(bool bPresent); - bool RetBlitzMode(); - - void SetSkyMode(bool bPresent); - bool RetSkyMode(); - - void SetBackForce(bool bPresent); - bool RetBackForce(); - - void SetPlanetMode(bool bPresent); - bool RetPlanetMode(); - - void SetLightMode(bool bPresent); - bool RetLightMode(); - - void SetEditIndentMode(bool bAuto); - bool RetEditIndentMode(); - - void SetEditIndentValue(int value); - int RetEditIndentValue(); - - void SetSpeed(float speed); - float RetSpeed(); - - void SetTracePrecision(float factor); - float RetTracePrecision(); - - void SetFocus(float focus); - float RetFocus(); - Math::Vector RetEyePt(); - Math::Vector RetLookatPt(); - float RetEyeDirH(); - float RetEyeDirV(); - POINT RetDim(); - void UpdateMatProj(); - - void ApplyChange(); - - void FlushPressKey(); - void ResetKey(); - void SetKey(int keyRank, int option, int key); - int RetKey(int keyRank, int option); - - void SetJoystick(bool bEnable); - bool RetJoystick(); - - void SetDebugMode(bool bMode); - bool RetDebugMode(); - bool RetSetupMode(); - - bool IsVisiblePoint(const Math::Vector &pos); - - int DetectObject(Math::Point mouse); - void SetState(int state, D3DCOLOR color=0xffffffff); - void SetTexture(char *name, int stage=0); - void SetMaterial(const D3DMATERIAL7 &mat); - - void MoveMousePos(Math::Point pos); - void SetMousePos(Math::Point pos); - Math::Point RetMousePos(); - void SetMouseType(D3DMouse type); - D3DMouse RetMouseType(); - void SetMouseHide(bool bHide); - bool RetMouseHide(); - void SetNiceMouse(bool bNice); - bool RetNiceMouse(); - bool RetNiceMouseCap(); - - CText* RetText(); - - bool ChangeColor(char *name, D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1, D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2, float tolerance1, float tolerance2, Math::Point ts, Math::Point ti, Math::Point *pExclu=0, float shift=0.0f, bool bHSV=false); - bool OpenImage(char *name); - bool CopyImage(); - bool LoadImage(); - bool ScrollImage(int dx, int dy); - bool SetDot(int x, int y, D3DCOLORVALUE color); - bool CloseImage(); - bool WriteScreenShot(char *filename, int width, int height); - bool GetRenderDC(HDC &hDC); - bool ReleaseRenderDC(HDC &hDC); - PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); - bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); - -protected: - void MemSpace1(D3DObjLevel1 *&p, int nb); - void MemSpace2(D3DObjLevel2 *&p, int nb); - void MemSpace3(D3DObjLevel3 *&p, int nb); - void MemSpace4(D3DObjLevel4 *&p, int nb); - void MemSpace5(D3DObjLevel5 *&p, int nb); - void MemSpace6(D3DObjLevel6 *&p, int nb); - - D3DObjLevel2* AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2); - D3DObjLevel3* AddLevel2(D3DObjLevel2 *&p2, int objRank); - D3DObjLevel4* AddLevel3(D3DObjLevel3 *&p3, float min, float max); - D3DObjLevel5* AddLevel4(D3DObjLevel4 *&p4, int reserve); - D3DObjLevel6* AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type, const D3DMATERIAL7 &mat, int state, int nb); - - bool IsVisible(int objRank); - bool DetectBBox(int objRank, Math::Point mouse); - bool DetectTriangle(Math::Point mouse, D3DVERTEX2 *triangle, int objRank, float &dist); - bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D); - void ComputeDistance(); - void UpdateGeometry(); - void RenderGroundSpot(); - void DrawShadow(); - void DrawBackground(); - void DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down); - void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name); - void DrawBackgroundImage(); - void DrawPlanet(); - void DrawFrontsize(); - void DrawOverColor(); - bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max); - void DrawHilite(); - void DrawMouse(); - void DrawSprite(Math::Point pos, Math::Point dim, int icon); - -protected: - CInstanceManager* m_iMan; - CD3DApplication* m_app; - LPDIRECT3DDEVICE7 m_pD3DDevice; - CText* m_text; - CLight* m_light; - CParticule* m_particule; - CWater* m_water; - CCloud* m_cloud; - CBlitz* m_blitz; - CPlanet* m_planet; - CSound* m_sound; - CTerrain* m_terrain; - - int m_blackSrcBlend[2]; - int m_blackDestBlend[2]; - int m_whiteSrcBlend[2]; - int m_whiteDestBlend[2]; - int m_diffuseSrcBlend[2]; - int m_diffuseDestBlend[2]; - int m_alphaSrcBlend[2]; - int m_alphaDestBlend[2]; - - Math::Matrix m_matProj; - Math::Matrix m_matLeftView; - Math::Matrix m_matRightView; - Math::Matrix m_matView; - float m_focus; - - Math::Matrix m_matWorldInterface; - Math::Matrix m_matProjInterface; - Math::Matrix m_matViewInterface; - - DWORD m_baseTime; - DWORD m_stopTime; - float m_absTime; - float m_lastTime; - float m_speed; - bool m_bPause; - bool m_bRender; - bool m_bMovieLock; - - POINT m_dim; - POINT m_lastDim; - D3DObjLevel1* m_objectPointer; - int m_objectParamTotal; - D3DObject* m_objectParam; - int m_shadowTotal; - D3DShadow* m_shadow; - D3DGroundSpot* m_groundSpot; - D3DGroundMark m_groundMark; - Math::Vector m_eyePt; - Math::Vector m_lookatPt; - float m_eyeDirH; - float m_eyeDirV; - int m_rankView; - D3DCOLOR m_ambiantColor[2]; - D3DCOLOR m_backColor[2]; - D3DCOLOR m_fogColor[2]; - float m_deepView[2]; - float m_fogStart[2]; - D3DCOLORVALUE m_waterAddColor; - int m_statisticTriangle; - bool m_bUpdateGeometry; - char m_infoText[10][200]; - int m_alphaMode; - bool m_bStateColor; - bool m_bForceStateColor; - bool m_bGroundSpot; - bool m_bShadow; - bool m_bDirty; - bool m_bFog; - bool m_bFirstGroundSpot; - int m_secondTexNum; - char m_backgroundName[50]; - D3DCOLOR m_backgroundColorUp; - D3DCOLOR m_backgroundColorDown; - D3DCOLOR m_backgroundCloudUp; - D3DCOLOR m_backgroundCloudDown; - bool m_bBackgroundFull; - bool m_bBackgroundQuarter; - bool m_bOverFront; - D3DCOLOR m_overColor; - int m_overMode; - char m_frontsizeName[50]; - bool m_bDrawWorld; - bool m_bDrawFront; - float m_limitLOD[2]; - float m_particuleDensity; - float m_clippingDistance; - float m_lastClippingDistance; - float m_objectDetail; - float m_lastObjectDetail; - float m_terrainVision; - float m_gadgetQuantity; - int m_textureQuality; - bool m_bTotoMode; - bool m_bLensMode; - bool m_bWaterMode; - bool m_bSkyMode; - bool m_bBackForce; - bool m_bPlanetMode; - bool m_bLightMode; - bool m_bEditIndentMode; - int m_editIndentValue; - float m_tracePrecision; - - int m_hiliteRank[100]; - bool m_bHilite; - Math::Point m_hiliteP1; - Math::Point m_hiliteP2; - - int m_lastState; - D3DCOLOR m_lastColor; - char m_lastTexture[2][50]; - D3DMATERIAL7 m_lastMaterial; - - Math::Point m_mousePos; - D3DMouse m_mouseType; - bool m_bMouseHide; - bool m_bNiceMouse; - - LPDIRECTDRAWSURFACE7 m_imageSurface; - DDSURFACEDESC2 m_imageDDSD; - WORD* m_imageCopy; - int m_imageDX; - int m_imageDY; -}; - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// d3dengine.h + +#pragma once + + +#include + +#include "math/point.h" +#include "math/vector.h" +#include "math/matrix.h" +#include "common/struct.h" + + +class CD3DApplication; +class CInstanceManager; +class CObject; +class CLight; +class CText; +class CParticule; +class CWater; +class CCloud; +class CBlitz; +class CPlanet; +class CSound; +class CTerrain; + + +const int D3DMAXOBJECT = 1200; +const int D3DMAXSHADOW = 500; +const int D3DMAXGROUNDSPOT = 100; + + +enum D3DTypeObj +{ + TYPENULL = 0, // object doesn't exist + TYPETERRAIN = 1, // terrain + TYPEFIX = 2, // fixed object + TYPEVEHICULE = 3, // moving object + TYPEDESCENDANT = 4, // part of a moving object + TYPEQUARTZ = 5, // fixed object type quartz + TYPEMETAL = 6, // fixed object type metal +}; + +enum D3DTypeTri +{ + D3DTYPE6T = 1, // triangles + D3DTYPE6S = 2, // surfaces +}; + +enum D3DMaping +{ + D3DMAPPINGX = 1, + D3DMAPPINGY = 2, + D3DMAPPINGZ = 3, + D3DMAPPING1X = 4, + D3DMAPPING1Y = 5, + D3DMAPPING1Z = 6, +}; + +enum D3DMouse +{ + D3DMOUSEHIDE = 0, // no mouse + D3DMOUSENORM = 1, + D3DMOUSEWAIT = 2, + D3DMOUSEEDIT = 3, + D3DMOUSEHAND = 4, + D3DMOUSECROSS = 5, + D3DMOUSESHOW = 6, + D3DMOUSENO = 7, + D3DMOUSEMOVE = 8, // + + D3DMOUSEMOVEH = 9, // - + D3DMOUSEMOVEV = 10, // | + D3DMOUSEMOVED = 11, // / + D3DMOUSEMOVEI = 12, // \ // + D3DMOUSESCROLLL = 13, // << + D3DMOUSESCROLLR = 14, // >> + D3DMOUSESCROLLU = 15, // ^ + D3DMOUSESCROLLD = 16, // v + D3DMOUSETARGET = 17, +}; + +enum D3DShadowType +{ + D3DSHADOWNORM = 0, + D3DSHADOWWORM = 1, +}; + + +const int D3DSTATENORMAL = 0; // normal opaque materials +const int D3DSTATETTb = (1<<0); // the transparent texture (black = no) +const int D3DSTATETTw = (1<<1); // the transparent texture (white = no) +const int D3DSTATETD = (1<<2); // the transparent diffuse color +const int D3DSTATEWRAP = (1<<3); // texture wrappe +const int D3DSTATECLAMP = (1<<4); // texture borders with solid color +const int D3DSTATELIGHT = (1<<5); // light texture (ambient max) +const int D3DSTATEDUALb = (1<<6); // double black texturing +const int D3DSTATEDUALw = (1<<7); // double white texturing +const int D3DSTATEPART1 = (1<<8); // part 1 (no change in. MOD!) +const int D3DSTATEPART2 = (1<<9); // part 2 +const int D3DSTATEPART3 = (1<<10); // part 3 +const int D3DSTATEPART4 = (1<<11); // part 4 +const int D3DSTATE2FACE = (1<<12); // double-sided face +const int D3DSTATEALPHA = (1<<13); // image using alpha channel +const int D3DSTATESECOND = (1<<14); // always use 2nd floor texturing +const int D3DSTATEFOG = (1<<15); // causes the fog +const int D3DSTATETCb = (1<<16); // the transparent color (black = no) +const int D3DSTATETCw = (1<<17); // the transparent color (white = no) + + +struct D3DTriangle +{ + D3DVERTEX2 triangle[3]; + D3DMATERIAL7 material; + int state; + char texName1[20]; + char texName2[20]; +}; + + +struct D3DObjLevel6 +{ + int totalPossible; + int totalUsed; + D3DMATERIAL7 material; + int state; + D3DTypeTri type; // D3DTYPE6x + D3DVERTEX2 vertex[1]; +}; + +struct D3DObjLevel5 +{ + int totalPossible; + int totalUsed; + int reserve; + D3DObjLevel6* table[1]; +}; + +struct D3DObjLevel4 +{ + int totalPossible; + int totalUsed; + float min, max; + D3DObjLevel5* table[1]; +}; + +struct D3DObjLevel3 +{ + int totalPossible; + int totalUsed; + int objRank; + D3DObjLevel4* table[1]; +}; + +struct D3DObjLevel2 +{ + int totalPossible; + int totalUsed; + char texName1[20]; + char texName2[20]; + D3DObjLevel3* table[1]; +}; + +struct D3DObjLevel1 +{ + int totalPossible; + int totalUsed; + D3DObjLevel2* table[1]; +}; + + +struct D3DObject +{ + char bUsed; // true -> object exists + char bVisible; // true -> visible object + char bDrawWorld; // true -> shape behind the interface + char bDrawFront; // true -> shape before the interface + int totalTriangle; // number of triangles used + D3DTypeObj type; // type of the object (TYPE*) + Math::Matrix transform; // transformation matrix + float distance; // distance point of view - original + Math::Vector bboxMin; // bounding box of the object + Math::Vector bboxMax; // (the origin 0, 0, 0 is always included) + float radius; // radius of the sphere at the origin + int shadowRank; // rank of the associated shadow + float transparency; // transparency of the object (0 .. 1) +}; + +struct D3DShadow +{ + char bUsed; // true -> object exists + char bHide; // true -> invisible shadow (object carried by ex.) + int objRank; // rank of the object + D3DShadowType type; // type of shadow + Math::Vector pos; // position for the shadow + Math::Vector normal; // normal terrain + float angle; // angle of the shadow + float radius; // radius of the shadow + float intensity; // intensity of the shadow + float height; // height from the ground +}; + +struct D3DGroundSpot +{ + char bUsed; // true -> object exists + D3DCOLORVALUE color; // color of the shadow + float min, max; // altitudes min / max + float smooth; // transition area + Math::Vector pos; // position for the shadow + float radius; // radius of the shadow + Math::Vector drawPos; // drawn to position the shade + float drawRadius; // radius of the shadow drawn +}; + +struct D3DGroundMark +{ + char bUsed; // true -> object exists + char bDraw; // true -> drawn mark + int phase; // 1 = increase, 2 = fixed, 3 = decrease + float delay[3]; // time for 3 phases + float fix; // fixed time + Math::Vector pos; // position for marks + float radius; // radius of marks + float intensity; // color intensity + Math::Vector drawPos; // drawn in position marks + float drawRadius; // radius marks drawn + float drawIntensity; // current drawn + int dx, dy; // dimensions table + char* table; // pointer to the table +}; + + + +class CD3DEngine +{ +public: + CD3DEngine(CInstanceManager *iMan, CD3DApplication *app); + ~CD3DEngine(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + LPDIRECT3DDEVICE7 RetD3DDevice(); + + void SetTerrain(CTerrain* terrain); + + bool WriteProfile(); + + void SetPause(bool bPause); + bool RetPause(); + + void SetMovieLock(bool bLock); + bool RetMovieLock(); + + void SetShowStat(bool bShow); + bool RetShowStat(); + + void SetRenderEnable(bool bEnable); + + HRESULT OneTimeSceneInit(); + HRESULT InitDeviceObjects(); + HRESULT DeleteDeviceObjects(); + HRESULT RestoreSurfaces(); + HRESULT Render(); + HRESULT FrameMove(float rTime); + void StepSimul(float rTime); + HRESULT FinalCleanup(); + void AddStatisticTriangle(int nb); + int RetStatisticTriangle(); + void SetHiliteRank(int *rankList); + bool GetHilite(Math::Point &p1, Math::Point &p2); + bool GetSpriteCoord(int &x, int &y); + void SetInfoText(int line, char* text); + char* RetInfoText(int line); + LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + void FirstExecuteAdapt(bool bFirst); + int GetVidMemTotal(); + bool IsVideo8MB(); + bool IsVideo32MB(); + + bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes); + bool RetFullScreen(); + bool ChangeDevice(char *device, char *mode, bool bFull); + + Math::Matrix* RetMatView(); + Math::Matrix* RetMatLeftView(); + Math::Matrix* RetMatRightView(); + + void TimeInit(); + void TimeEnterGel(); + void TimeExitGel(); + float TimeGet(); + + int RetRestCreate(); + int CreateObject(); + void FlushObject(); + bool DeleteObject(int objRank); + bool SetDrawWorld(int objRank, bool bDraw); + bool SetDrawFront(int objRank, bool bDraw); + bool AddTriangle(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); + bool AddSurface(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); + bool AddQuick(int objRank, D3DObjLevel6* buffer, char* texName1, char* texName2, float min, float max, bool bGlobalUpdate); + D3DObjLevel6* SearchTriangle(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max); + void ChangeLOD(); + bool ChangeSecondTexture(int objRank, char* texName2); + int RetTotalTriangles(int objRank); + int GetTriangles(int objRank, float min, float max, D3DTriangle* buffer, int size, float percent); + bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max); + bool ChangeTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float au, float bu, float av, float bv); + bool TrackTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float pos, float factor, float tl, float ts, float tt); + bool SetObjectTransform(int objRank, const Math::Matrix &transform); + bool GetObjectTransform(int objRank, Math::Matrix &transform); + bool SetObjectType(int objRank, D3DTypeObj type); + D3DTypeObj RetObjectType(int objRank); + bool SetObjectTransparency(int objRank, float value); + + bool ShadowCreate(int objRank); + void ShadowDelete(int objRank); + bool SetObjectShadowHide(int objRank, bool bHide); + bool SetObjectShadowType(int objRank, D3DShadowType type); + bool SetObjectShadowPos(int objRank, const Math::Vector &pos); + bool SetObjectShadowNormal(int objRank, const Math::Vector &n); + bool SetObjectShadowAngle(int objRank, float angle); + bool SetObjectShadowRadius(int objRank, float radius); + bool SetObjectShadowIntensity(int objRank, float intensity); + bool SetObjectShadowHeight(int objRank, float h); + float RetObjectShadowRadius(int objRank); + + void GroundSpotFlush(); + int GroundSpotCreate(); + void GroundSpotDelete(int rank); + bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos); + bool SetObjectGroundSpotRadius(int rank, float radius); + bool SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color); + bool SetObjectGroundSpotMinMax(int rank, float min, float max); + bool SetObjectGroundSpotSmooth(int rank, float smooth); + + int GroundMarkCreate(Math::Vector pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table); + bool GroundMarkDelete(int rank); + + void Update(); + + void SetViewParams(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, const Math::Vector &vUpVec, FLOAT fEyeDistance); + + bool FreeTexture(char* name); + bool LoadTexture(char* name, int stage=0); + bool LoadAllTexture(); + + void SetLimitLOD(int rank, float limit); + float RetLimitLOD(int rank, bool bLast=false); + + void SetTerrainVision(float vision); + + void SetGroundSpot(bool bMode); + bool RetGroundSpot(); + void SetShadow(bool bMode); + bool RetShadow(); + void SetDirty(bool bMode); + bool RetDirty(); + void SetFog(bool bMode); + bool RetFog(); + bool RetStateColor(); + + void SetSecondTexture(int texNum); + int RetSecondTexture(); + + void SetRankView(int rank); + int RetRankView(); + + void SetDrawWorld(bool bDraw); + void SetDrawFront(bool bDraw); + + void SetAmbiantColor(D3DCOLOR color, int rank=0); + D3DCOLOR RetAmbiantColor(int rank=0); + + void SetWaterAddColor(D3DCOLORVALUE color); + D3DCOLORVALUE RetWaterAddColor(); + + void SetFogColor(D3DCOLOR color, int rank=0); + D3DCOLOR RetFogColor(int rank=0); + + void SetDeepView(float length, int rank=0, bool bRef=false); + float RetDeepView(int rank=0); + + void SetFogStart(float start, int rank=0); + float RetFogStart(int rank=0); + + void SetBackground(char *name, D3DCOLOR up=0, D3DCOLOR down=0, D3DCOLOR cloudUp=0, D3DCOLOR cloudDown=0, bool bFull=false, bool bQuarter=false); + void RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down, D3DCOLOR &cloudUp, D3DCOLOR &cloudDown, bool &bFull, bool &bQuarter); + void SetFrontsizeName(char *name); + void SetOverFront(bool bFront); + void SetOverColor(D3DCOLOR color=0, int mode=D3DSTATETCb); + + void SetParticuleDensity(float value); + float RetParticuleDensity(); + float ParticuleAdapt(float factor); + + void SetClippingDistance(float value); + float RetClippingDistance(); + + void SetObjectDetail(float value); + float RetObjectDetail(); + + void SetGadgetQuantity(float value); + float RetGadgetQuantity(); + + void SetTextureQuality(int value); + int RetTextureQuality(); + + void SetTotoMode(bool bPresent); + bool RetTotoMode(); + + void SetLensMode(bool bPresent); + bool RetLensMode(); + + void SetWaterMode(bool bPresent); + bool RetWaterMode(); + + void SetBlitzMode(bool bPresent); + bool RetBlitzMode(); + + void SetSkyMode(bool bPresent); + bool RetSkyMode(); + + void SetBackForce(bool bPresent); + bool RetBackForce(); + + void SetPlanetMode(bool bPresent); + bool RetPlanetMode(); + + void SetLightMode(bool bPresent); + bool RetLightMode(); + + void SetEditIndentMode(bool bAuto); + bool RetEditIndentMode(); + + void SetEditIndentValue(int value); + int RetEditIndentValue(); + + void SetSpeed(float speed); + float RetSpeed(); + + void SetTracePrecision(float factor); + float RetTracePrecision(); + + void SetFocus(float focus); + float RetFocus(); + Math::Vector RetEyePt(); + Math::Vector RetLookatPt(); + float RetEyeDirH(); + float RetEyeDirV(); + POINT RetDim(); + void UpdateMatProj(); + + void ApplyChange(); + + void FlushPressKey(); + void ResetKey(); + void SetKey(int keyRank, int option, int key); + int RetKey(int keyRank, int option); + + void SetJoystick(bool bEnable); + bool RetJoystick(); + + void SetDebugMode(bool bMode); + bool RetDebugMode(); + bool RetSetupMode(); + + bool IsVisiblePoint(const Math::Vector &pos); + + int DetectObject(Math::Point mouse); + void SetState(int state, D3DCOLOR color=0xffffffff); + void SetTexture(char *name, int stage=0); + void SetMaterial(const D3DMATERIAL7 &mat); + + void MoveMousePos(Math::Point pos); + void SetMousePos(Math::Point pos); + Math::Point RetMousePos(); + void SetMouseType(D3DMouse type); + D3DMouse RetMouseType(); + void SetMouseHide(bool bHide); + bool RetMouseHide(); + void SetNiceMouse(bool bNice); + bool RetNiceMouse(); + bool RetNiceMouseCap(); + + CText* RetText(); + + bool ChangeColor(char *name, D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1, D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2, float tolerance1, float tolerance2, Math::Point ts, Math::Point ti, Math::Point *pExclu=0, float shift=0.0f, bool bHSV=false); + bool OpenImage(char *name); + bool CopyImage(); + bool LoadImage(); + bool ScrollImage(int dx, int dy); + bool SetDot(int x, int y, D3DCOLORVALUE color); + bool CloseImage(); + bool WriteScreenShot(char *filename, int width, int height); + bool GetRenderDC(HDC &hDC); + bool ReleaseRenderDC(HDC &hDC); + PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp); + bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); + +protected: + void MemSpace1(D3DObjLevel1 *&p, int nb); + void MemSpace2(D3DObjLevel2 *&p, int nb); + void MemSpace3(D3DObjLevel3 *&p, int nb); + void MemSpace4(D3DObjLevel4 *&p, int nb); + void MemSpace5(D3DObjLevel5 *&p, int nb); + void MemSpace6(D3DObjLevel6 *&p, int nb); + + D3DObjLevel2* AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2); + D3DObjLevel3* AddLevel2(D3DObjLevel2 *&p2, int objRank); + D3DObjLevel4* AddLevel3(D3DObjLevel3 *&p3, float min, float max); + D3DObjLevel5* AddLevel4(D3DObjLevel4 *&p4, int reserve); + D3DObjLevel6* AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type, const D3DMATERIAL7 &mat, int state, int nb); + + bool IsVisible(int objRank); + bool DetectBBox(int objRank, Math::Point mouse); + bool DetectTriangle(Math::Point mouse, D3DVERTEX2 *triangle, int objRank, float &dist); + bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D); + void ComputeDistance(); + void UpdateGeometry(); + void RenderGroundSpot(); + void DrawShadow(); + void DrawBackground(); + void DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down); + void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name); + void DrawBackgroundImage(); + void DrawPlanet(); + void DrawFrontsize(); + void DrawOverColor(); + bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max); + void DrawHilite(); + void DrawMouse(); + void DrawSprite(Math::Point pos, Math::Point dim, int icon); + +protected: + CInstanceManager* m_iMan; + CD3DApplication* m_app; + LPDIRECT3DDEVICE7 m_pD3DDevice; + CText* m_text; + CLight* m_light; + CParticule* m_particule; + CWater* m_water; + CCloud* m_cloud; + CBlitz* m_blitz; + CPlanet* m_planet; + CSound* m_sound; + CTerrain* m_terrain; + + int m_blackSrcBlend[2]; + int m_blackDestBlend[2]; + int m_whiteSrcBlend[2]; + int m_whiteDestBlend[2]; + int m_diffuseSrcBlend[2]; + int m_diffuseDestBlend[2]; + int m_alphaSrcBlend[2]; + int m_alphaDestBlend[2]; + + Math::Matrix m_matProj; + Math::Matrix m_matLeftView; + Math::Matrix m_matRightView; + Math::Matrix m_matView; + float m_focus; + + Math::Matrix m_matWorldInterface; + Math::Matrix m_matProjInterface; + Math::Matrix m_matViewInterface; + + DWORD m_baseTime; + DWORD m_stopTime; + float m_absTime; + float m_lastTime; + float m_speed; + bool m_bPause; + bool m_bRender; + bool m_bMovieLock; + + POINT m_dim; + POINT m_lastDim; + D3DObjLevel1* m_objectPointer; + int m_objectParamTotal; + D3DObject* m_objectParam; + int m_shadowTotal; + D3DShadow* m_shadow; + D3DGroundSpot* m_groundSpot; + D3DGroundMark m_groundMark; + Math::Vector m_eyePt; + Math::Vector m_lookatPt; + float m_eyeDirH; + float m_eyeDirV; + int m_rankView; + D3DCOLOR m_ambiantColor[2]; + D3DCOLOR m_backColor[2]; + D3DCOLOR m_fogColor[2]; + float m_deepView[2]; + float m_fogStart[2]; + D3DCOLORVALUE m_waterAddColor; + int m_statisticTriangle; + bool m_bUpdateGeometry; + char m_infoText[10][200]; + int m_alphaMode; + bool m_bStateColor; + bool m_bForceStateColor; + bool m_bGroundSpot; + bool m_bShadow; + bool m_bDirty; + bool m_bFog; + bool m_bFirstGroundSpot; + int m_secondTexNum; + char m_backgroundName[50]; + D3DCOLOR m_backgroundColorUp; + D3DCOLOR m_backgroundColorDown; + D3DCOLOR m_backgroundCloudUp; + D3DCOLOR m_backgroundCloudDown; + bool m_bBackgroundFull; + bool m_bBackgroundQuarter; + bool m_bOverFront; + D3DCOLOR m_overColor; + int m_overMode; + char m_frontsizeName[50]; + bool m_bDrawWorld; + bool m_bDrawFront; + float m_limitLOD[2]; + float m_particuleDensity; + float m_clippingDistance; + float m_lastClippingDistance; + float m_objectDetail; + float m_lastObjectDetail; + float m_terrainVision; + float m_gadgetQuantity; + int m_textureQuality; + bool m_bTotoMode; + bool m_bLensMode; + bool m_bWaterMode; + bool m_bSkyMode; + bool m_bBackForce; + bool m_bPlanetMode; + bool m_bLightMode; + bool m_bEditIndentMode; + int m_editIndentValue; + float m_tracePrecision; + + int m_hiliteRank[100]; + bool m_bHilite; + Math::Point m_hiliteP1; + Math::Point m_hiliteP2; + + int m_lastState; + D3DCOLOR m_lastColor; + char m_lastTexture[2][50]; + D3DMATERIAL7 m_lastMaterial; + + Math::Point m_mousePos; + D3DMouse m_mouseType; + bool m_bMouseHide; + bool m_bNiceMouse; + + LPDIRECTDRAWSURFACE7 m_imageSurface; + DDSURFACEDESC2 m_imageDDSD; + WORD* m_imageCopy; + int m_imageDX; + int m_imageDY; +}; + + diff --git a/src/old/d3denum.cpp b/src/old/d3denum.cpp index 5bce9ab..234ce5a 100644 --- a/src/old/d3denum.cpp +++ b/src/old/d3denum.cpp @@ -1,620 +1,620 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DEnum.cpp -// -// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- -#include -#include -#include -#include "old/d3denum.h" -#include "old/d3dutil.h" // For DEBUG_MSG -#include "old/d3dres.h" // For dialog controls - - - - -//----------------------------------------------------------------------------- -// Global data for the enumerator functions -//----------------------------------------------------------------------------- -static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL; - -static D3DEnum_DeviceInfo g_pDeviceList[20]; -static DWORD g_dwNumDevicesEnumerated = 0L; -static DWORD g_dwNumDevices = 0L; - - - - -//----------------------------------------------------------------------------- -// Name: SortModesCallback() -// Desc: Callback function for sorting display modes. -//----------------------------------------------------------------------------- -int SortModesCallback( const VOID* arg1, const VOID* arg2 ) -{ - DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1; - DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2; - - if( p1->dwWidth < p2->dwWidth ) - return -1; - if( p1->dwWidth > p2->dwWidth ) - return +1; - - if( p1->dwHeight < p2->dwHeight ) - return -1; - if( p1->dwHeight > p2->dwHeight ) - return +1; - - if( p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount ) - return -1; - if( p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount ) - return +1; - - return 0; -} - - - - -//----------------------------------------------------------------------------- -// Name: ModeEnumCallback() -// Desc: Callback function for enumerating display modes. -//----------------------------------------------------------------------------- -static HRESULT WINAPI ModeEnumCallback( DDSURFACEDESC2* pddsd, - VOID* pParentInfo ) -{ - D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo; - - // Reallocate storage for the modes - DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1]; - memcpy( pddsdNewModes, pDevice->pddsdModes, - pDevice->dwNumModes * sizeof(DDSURFACEDESC2) ); - delete pDevice->pddsdModes; - pDevice->pddsdModes = pddsdNewModes; - - // Add the new mode - pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd); - - return DDENUMRET_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: DeviceEnumCallback() -// Desc: Callback function for enumerating devices -//----------------------------------------------------------------------------- -static HRESULT WINAPI DeviceEnumCallback( TCHAR* strDesc, TCHAR* strName, - D3DDEVICEDESC7* pDesc, - VOID* pParentInfo ) -{ - DWORD i; - - // Keep track of # of devices that were enumerated - g_dwNumDevicesEnumerated++; - - D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo; - D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices]; - ZeroMemory( pDeviceInfo, sizeof(D3DEnum_DeviceInfo) ); - - // Select either the HAL or HEL device desc: - pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION; - memcpy( &pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7) ); - - // Set up device info for this device - pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible; - pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps; - pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps; - pDeviceInfo->guidDevice = pDesc->deviceGUID; - pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice; - pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes]; - - // Copy the driver GUID and description for the device - if( pDriverInfo->pDriverGUID ) - { - pDeviceInfo->guidDriver = pDriverInfo->guidDriver; - pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver; - lstrcpyn( pDeviceInfo->strDesc, pDriverInfo->strDesc, 39 ); - } - else - { - pDeviceInfo->pDriverGUID = NULL; - lstrcpyn( pDeviceInfo->strDesc, strName, 39 ); - } - -//? if( strstr(strName, "T&L") != 0 ) return D3DENUMRET_OK; - - // Avoid duplicates: only enum HW devices for secondary DDraw drivers. - if( NULL != pDeviceInfo->pDriverGUID && false == pDeviceInfo->bHardware ) - return D3DENUMRET_OK; - - // Give the app a chance to accept or reject this device. - if( g_fnAppConfirmFn ) - if( FAILED( g_fnAppConfirmFn( &pDeviceInfo->ddDriverCaps, - &pDeviceInfo->ddDeviceDesc ) ) ) - return D3DENUMRET_OK; - - // Build list of supported modes for the device - for( i=0; idwNumModes; i++ ) - { - DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i]; - DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth; - DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount; - - // Accept modes that are compatable with the device - if( ( ( dwDepth == 32 ) && ( dwRenderDepths & DDBD_32 ) ) || - ( ( dwDepth == 24 ) && ( dwRenderDepths & DDBD_24 ) ) || - ( ( dwDepth == 16 ) && ( dwRenderDepths & DDBD_16 ) ) ) - { - // Copy compatible modes to the list of device-supported modes - pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode; - - // Record whether the device has any stereo modes - if( ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT ) - pDeviceInfo->bStereoCompatible = true; - } - } - - // Bail if the device has no supported modes - if( 0 == pDeviceInfo->dwNumModes ) - return D3DENUMRET_OK; - - // Find a 640x480x16 mode for the default fullscreen mode - for( i=0; idwNumModes; i++ ) - { - if( ( pDeviceInfo->pddsdModes[i].dwWidth == 640 ) && - ( pDeviceInfo->pddsdModes[i].dwHeight == 480 ) && - ( pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16 ) ) - { - pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i]; - pDeviceInfo->dwCurrentMode = i; - } - } - - // Select whether the device is initially windowed - pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible; - - // Accept the device and return - g_dwNumDevices++; - - return D3DENUMRET_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: DriverEnumCallback() -// Desc: Callback function for enumerating drivers. -//----------------------------------------------------------------------------- -static bool WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc, - TCHAR* strName, VOID*, HMONITOR ) -{ - D3DEnum_DeviceInfo d3dDeviceInfo; - LPDIRECTDRAW7 pDD; - LPDIRECT3D7 pD3D; - HRESULT hr; - - // Use the GUID to create the DirectDraw object - hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL ); - if( FAILED(hr) ) - { - DEBUG_MSG( _T("Can't create DDraw during enumeration!") ); - return D3DENUMRET_OK; - } - - // Create a D3D object, to enumerate the d3d devices - hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3D ); - if( FAILED(hr) ) - { - pDD->Release(); - DEBUG_MSG( _T("Can't query IDirect3D7 during enumeration!") ); - return D3DENUMRET_OK; - } - - // Copy data to a device info structure - ZeroMemory( &d3dDeviceInfo, sizeof(d3dDeviceInfo) ); - lstrcpyn( d3dDeviceInfo.strDesc, strDesc, 39 ); - d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS); - d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS); - pDD->GetCaps( &d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps ); - if( pGUID ) - { - d3dDeviceInfo.guidDriver = (*pGUID); - d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver; - } - - // Record whether the device can render into a desktop window - if( d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED ) - if( NULL == d3dDeviceInfo.pDriverGUID ) - d3dDeviceInfo.bDesktopCompatible = true; - - // Enumerate the fullscreen display modes. - pDD->EnumDisplayModes( 0, NULL, &d3dDeviceInfo, ModeEnumCallback ); - - // Sort list of display modes - qsort( d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes, - sizeof(DDSURFACEDESC2), SortModesCallback ); - - // Now, enumerate all the 3D devices - pD3D->EnumDevices( DeviceEnumCallback, &d3dDeviceInfo ); - - // Clean up and return - SAFE_DELETE( d3dDeviceInfo.pddsdModes ); - pD3D->Release(); - pDD->Release(); - - return DDENUMRET_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_EnumerateDevices() -// Desc: Enumerates all drivers, devices, and modes. The callback function is -// called each device, to confirm that the device supports the feature -// set required by the app. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_EnumerateDevices( HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) ) -{ - // Store the device enumeration callback function - g_fnAppConfirmFn = AppConfirmFn; - - // Enumerate drivers, devices, and modes - DirectDrawEnumerateEx( DriverEnumCallback, NULL, - DDENUM_ATTACHEDSECONDARYDEVICES | - DDENUM_DETACHEDSECONDARYDEVICES | - DDENUM_NONDISPLAYDEVICES ); - - // Make sure devices were actually enumerated - if( 0 == g_dwNumDevicesEnumerated ) - { - DEBUG_MSG( _T("No devices and/or modes were enumerated!") ); - return D3DENUMERR_ENUMERATIONFAILED; - } - if( 0 == g_dwNumDevices ) - { - DEBUG_MSG( _T("No enumerated devices were accepted!") ); - DEBUG_MSG( _T("Try enabling the D3D Reference Rasterizer.") ); - return D3DENUMERR_SUGGESTREFRAST; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_FreeResources() -// Desc: Cleans up any memory allocated during device enumeration -//----------------------------------------------------------------------------- -VOID D3DEnum_FreeResources() -{ - for( DWORD i=0; ibDesktopCompatible ) - bWindowed = false; - - // Add a list of devices to the device combo box - for( DWORD device = 0; device < dwNumDevices; device++ ) - { - D3DEnum_DeviceInfo* pDevice = &pDeviceList[device]; - - // Add device name to the combo box - DWORD dwItem = ComboBox_AddString( hwndDevice, pDevice->strDesc ); - - // Set the remaining UI states for the current device - if( pDevice == pCurrentDevice ) - { - // Set the combobox selection on the current device - ComboBox_SetCurSel( hwndDevice, dwItem ); - - // Enable/set the fullscreen checkbox, as appropriate - if( hwndWindowed ) - { - EnableWindow( hwndWindowed, pDevice->bDesktopCompatible ); - Button_SetCheck( hwndWindowed, bWindowed ); - } - - // Enable/set the stereo checkbox, as appropriate - if( hwndStereo ) - { - EnableWindow( hwndStereo, pDevice->bStereoCompatible && !bWindowed ); - Button_SetCheck( hwndStereo, bStereo ); - } - - // Enable/set the fullscreen modes combo, as appropriate - EnableWindow( hwndMode, !bWindowed ); - EnableWindow( hwndFullscreenText, !bWindowed ); - - // Build the list of fullscreen modes - for( DWORD mode = 0; mode < pDevice->dwNumModes; mode++ ) - { - DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode]; - - // Skip non-stereo modes, if the device is in stereo mode - if( 0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT) ) - if( bStereo ) - continue; - - TCHAR strMode[80]; - wsprintf( strMode, _T("%ld x %ld x %ld"), - pddsdMode->dwWidth, pddsdMode->dwHeight, - pddsdMode->ddpfPixelFormat.dwRGBBitCount ); - - // Add mode desc to the combo box - DWORD dwItem = ComboBox_AddString( hwndMode, strMode ); - - // Set the item data to identify this mode - ComboBox_SetItemData( hwndMode, dwItem, mode ); - - // Set the combobox selection on the current mode - if( mode == dwCurrentMode ) - ComboBox_SetCurSel( hwndMode, dwItem ); - - // Since not all modes support stereo, select a default mode in - // case none was chosen yet. - if( bStereo && ( CB_ERR == ComboBox_GetCurSel( hwndMode ) ) ) - ComboBox_SetCurSel( hwndMode, dwItem ); - } - } - } -} - - - - -//----------------------------------------------------------------------------- -// Name: ChangeDeviceProc() -// Desc: Windows message handling function for the device select dialog -//----------------------------------------------------------------------------- -static INT_PTR CALLBACK ChangeDeviceProc( HWND hDlg, UINT uiMsg, WPARAM wParam, - LPARAM lParam ) -{ - static D3DEnum_DeviceInfo** ppDeviceArg; - static D3DEnum_DeviceInfo* pCurrentDevice; - static DWORD dwCurrentMode; - static bool bCurrentWindowed; - static bool bCurrentStereo; - - // Get access to the enumerated device list - D3DEnum_DeviceInfo* pDeviceList; - DWORD dwNumDevices; - D3DEnum_GetDevices( &pDeviceList, &dwNumDevices ); - - // Handle the initialization message - if( WM_INITDIALOG == uiMsg ) - { - // Get the app's current device, passed in as an lParam argument - ppDeviceArg = (D3DEnum_DeviceInfo**)lParam; - if( NULL == ppDeviceArg ) - return false; - - // Setup temp storage pointers for dialog - pCurrentDevice = (*ppDeviceArg); - dwCurrentMode = pCurrentDevice->dwCurrentMode; - bCurrentWindowed = pCurrentDevice->bWindowed; - bCurrentStereo = pCurrentDevice->bStereo; - - UpdateDialogControls( hDlg, pCurrentDevice, dwCurrentMode, - bCurrentWindowed, bCurrentStereo ); - - return true; - } - else if( WM_COMMAND == uiMsg ) - { - HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO ); - HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO ); - HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX ); - HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX ); - - // Get current UI state - DWORD dwDevice = ComboBox_GetCurSel( hwndDevice ); - DWORD dwModeItem = ComboBox_GetCurSel( hwndMode ); - DWORD dwMode = ComboBox_GetItemData( hwndMode, dwModeItem ); - bool bWindowed = hwndWindowed ? Button_GetCheck( hwndWindowed ) : 0; - bool bStereo = hwndStereo ? Button_GetCheck( hwndStereo ) : 0; - - D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice]; - - if( IDOK == LOWORD(wParam) ) - { - // Handle the case when the user hits the OK button. Check if any - // of the options were changed - if( pDevice != pCurrentDevice || dwMode != dwCurrentMode || - bWindowed != bCurrentWindowed || bStereo != bCurrentStereo ) - { - // Return the newly selected device and its new properties - (*ppDeviceArg) = pDevice; - pDevice->bWindowed = bWindowed; - pDevice->bStereo = bStereo; - pDevice->dwCurrentMode = dwMode; - pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode]; - - EndDialog( hDlg, IDOK ); - } - else - EndDialog( hDlg, IDCANCEL ); - - return true; - } - else if( IDCANCEL == LOWORD(wParam) ) - { - // Handle the case when the user hits the Cancel button - EndDialog( hDlg, IDCANCEL ); - return true; - } - else if( CBN_SELENDOK == HIWORD(wParam) ) - { - if( LOWORD(wParam) == IDC_DEVICE_COMBO ) - { - // Handle the case when the user chooses the device combo - dwMode = pDeviceList[dwDevice].dwCurrentMode; - bWindowed = pDeviceList[dwDevice].bWindowed; - bStereo = pDeviceList[dwDevice].bStereo; - } - } - - // Keep the UI current - UpdateDialogControls( hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo ); - return true; - } - - return false; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_UserChangeDevice() -// Desc: Pops up a dialog which allows the user to select a new device. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice ) -{ - if( IDOK == DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL), - MAKEINTRESOURCE(IDD_CHANGEDEVICE), - GetForegroundWindow(), - ChangeDeviceProc, (LPARAM)ppDevice ) ) - return S_OK; - - return E_FAIL; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_SelectDefaultDevice() -// Desc: Pick a default device, preferably hardware and desktop compatible. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** ppDevice, - DWORD dwFlags ) -{ - // Check arguments - if( NULL == ppDevice ) - return E_INVALIDARG; - - // Get access to the enumerated device list - D3DEnum_DeviceInfo* pDeviceList; - DWORD dwNumDevices; - D3DEnum_GetDevices( &pDeviceList, &dwNumDevices ); - - // Look for windowable software, hardware, and hardware TnL devices - D3DEnum_DeviceInfo* pRefRastDevice = NULL; - D3DEnum_DeviceInfo* pSoftwareDevice = NULL; - D3DEnum_DeviceInfo* pHardwareDevice = NULL; - D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL; - - for( DWORD i=0; ibWindowed = true; - - return S_OK; -} - - - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DEnum.cpp +// +// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- +#include +#include +#include +#include "old/d3denum.h" +#include "old/d3dutil.h" // For DEBUG_MSG +#include "old/d3dres.h" // For dialog controls + + + + +//----------------------------------------------------------------------------- +// Global data for the enumerator functions +//----------------------------------------------------------------------------- +static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL; + +static D3DEnum_DeviceInfo g_pDeviceList[20]; +static DWORD g_dwNumDevicesEnumerated = 0L; +static DWORD g_dwNumDevices = 0L; + + + + +//----------------------------------------------------------------------------- +// Name: SortModesCallback() +// Desc: Callback function for sorting display modes. +//----------------------------------------------------------------------------- +int SortModesCallback( const VOID* arg1, const VOID* arg2 ) +{ + DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1; + DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2; + + if( p1->dwWidth < p2->dwWidth ) + return -1; + if( p1->dwWidth > p2->dwWidth ) + return +1; + + if( p1->dwHeight < p2->dwHeight ) + return -1; + if( p1->dwHeight > p2->dwHeight ) + return +1; + + if( p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount ) + return -1; + if( p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount ) + return +1; + + return 0; +} + + + + +//----------------------------------------------------------------------------- +// Name: ModeEnumCallback() +// Desc: Callback function for enumerating display modes. +//----------------------------------------------------------------------------- +static HRESULT WINAPI ModeEnumCallback( DDSURFACEDESC2* pddsd, + VOID* pParentInfo ) +{ + D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo; + + // Reallocate storage for the modes + DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1]; + memcpy( pddsdNewModes, pDevice->pddsdModes, + pDevice->dwNumModes * sizeof(DDSURFACEDESC2) ); + delete pDevice->pddsdModes; + pDevice->pddsdModes = pddsdNewModes; + + // Add the new mode + pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd); + + return DDENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: DeviceEnumCallback() +// Desc: Callback function for enumerating devices +//----------------------------------------------------------------------------- +static HRESULT WINAPI DeviceEnumCallback( TCHAR* strDesc, TCHAR* strName, + D3DDEVICEDESC7* pDesc, + VOID* pParentInfo ) +{ + DWORD i; + + // Keep track of # of devices that were enumerated + g_dwNumDevicesEnumerated++; + + D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo; + D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices]; + ZeroMemory( pDeviceInfo, sizeof(D3DEnum_DeviceInfo) ); + + // Select either the HAL or HEL device desc: + pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION; + memcpy( &pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7) ); + + // Set up device info for this device + pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible; + pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps; + pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps; + pDeviceInfo->guidDevice = pDesc->deviceGUID; + pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice; + pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes]; + + // Copy the driver GUID and description for the device + if( pDriverInfo->pDriverGUID ) + { + pDeviceInfo->guidDriver = pDriverInfo->guidDriver; + pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver; + lstrcpyn( pDeviceInfo->strDesc, pDriverInfo->strDesc, 39 ); + } + else + { + pDeviceInfo->pDriverGUID = NULL; + lstrcpyn( pDeviceInfo->strDesc, strName, 39 ); + } + +//? if( strstr(strName, "T&L") != 0 ) return D3DENUMRET_OK; + + // Avoid duplicates: only enum HW devices for secondary DDraw drivers. + if( NULL != pDeviceInfo->pDriverGUID && false == pDeviceInfo->bHardware ) + return D3DENUMRET_OK; + + // Give the app a chance to accept or reject this device. + if( g_fnAppConfirmFn ) + if( FAILED( g_fnAppConfirmFn( &pDeviceInfo->ddDriverCaps, + &pDeviceInfo->ddDeviceDesc ) ) ) + return D3DENUMRET_OK; + + // Build list of supported modes for the device + for( i=0; idwNumModes; i++ ) + { + DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i]; + DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth; + DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount; + + // Accept modes that are compatable with the device + if( ( ( dwDepth == 32 ) && ( dwRenderDepths & DDBD_32 ) ) || + ( ( dwDepth == 24 ) && ( dwRenderDepths & DDBD_24 ) ) || + ( ( dwDepth == 16 ) && ( dwRenderDepths & DDBD_16 ) ) ) + { + // Copy compatible modes to the list of device-supported modes + pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode; + + // Record whether the device has any stereo modes + if( ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT ) + pDeviceInfo->bStereoCompatible = true; + } + } + + // Bail if the device has no supported modes + if( 0 == pDeviceInfo->dwNumModes ) + return D3DENUMRET_OK; + + // Find a 640x480x16 mode for the default fullscreen mode + for( i=0; idwNumModes; i++ ) + { + if( ( pDeviceInfo->pddsdModes[i].dwWidth == 640 ) && + ( pDeviceInfo->pddsdModes[i].dwHeight == 480 ) && + ( pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16 ) ) + { + pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i]; + pDeviceInfo->dwCurrentMode = i; + } + } + + // Select whether the device is initially windowed + pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible; + + // Accept the device and return + g_dwNumDevices++; + + return D3DENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: DriverEnumCallback() +// Desc: Callback function for enumerating drivers. +//----------------------------------------------------------------------------- +static bool WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc, + TCHAR* strName, VOID*, HMONITOR ) +{ + D3DEnum_DeviceInfo d3dDeviceInfo; + LPDIRECTDRAW7 pDD; + LPDIRECT3D7 pD3D; + HRESULT hr; + + // Use the GUID to create the DirectDraw object + hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL ); + if( FAILED(hr) ) + { + DEBUG_MSG( _T("Can't create DDraw during enumeration!") ); + return D3DENUMRET_OK; + } + + // Create a D3D object, to enumerate the d3d devices + hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3D ); + if( FAILED(hr) ) + { + pDD->Release(); + DEBUG_MSG( _T("Can't query IDirect3D7 during enumeration!") ); + return D3DENUMRET_OK; + } + + // Copy data to a device info structure + ZeroMemory( &d3dDeviceInfo, sizeof(d3dDeviceInfo) ); + lstrcpyn( d3dDeviceInfo.strDesc, strDesc, 39 ); + d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS); + d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS); + pDD->GetCaps( &d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps ); + if( pGUID ) + { + d3dDeviceInfo.guidDriver = (*pGUID); + d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver; + } + + // Record whether the device can render into a desktop window + if( d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED ) + if( NULL == d3dDeviceInfo.pDriverGUID ) + d3dDeviceInfo.bDesktopCompatible = true; + + // Enumerate the fullscreen display modes. + pDD->EnumDisplayModes( 0, NULL, &d3dDeviceInfo, ModeEnumCallback ); + + // Sort list of display modes + qsort( d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes, + sizeof(DDSURFACEDESC2), SortModesCallback ); + + // Now, enumerate all the 3D devices + pD3D->EnumDevices( DeviceEnumCallback, &d3dDeviceInfo ); + + // Clean up and return + SAFE_DELETE( d3dDeviceInfo.pddsdModes ); + pD3D->Release(); + pDD->Release(); + + return DDENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_EnumerateDevices() +// Desc: Enumerates all drivers, devices, and modes. The callback function is +// called each device, to confirm that the device supports the feature +// set required by the app. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_EnumerateDevices( HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) ) +{ + // Store the device enumeration callback function + g_fnAppConfirmFn = AppConfirmFn; + + // Enumerate drivers, devices, and modes + DirectDrawEnumerateEx( DriverEnumCallback, NULL, + DDENUM_ATTACHEDSECONDARYDEVICES | + DDENUM_DETACHEDSECONDARYDEVICES | + DDENUM_NONDISPLAYDEVICES ); + + // Make sure devices were actually enumerated + if( 0 == g_dwNumDevicesEnumerated ) + { + DEBUG_MSG( _T("No devices and/or modes were enumerated!") ); + return D3DENUMERR_ENUMERATIONFAILED; + } + if( 0 == g_dwNumDevices ) + { + DEBUG_MSG( _T("No enumerated devices were accepted!") ); + DEBUG_MSG( _T("Try enabling the D3D Reference Rasterizer.") ); + return D3DENUMERR_SUGGESTREFRAST; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_FreeResources() +// Desc: Cleans up any memory allocated during device enumeration +//----------------------------------------------------------------------------- +VOID D3DEnum_FreeResources() +{ + for( DWORD i=0; ibDesktopCompatible ) + bWindowed = false; + + // Add a list of devices to the device combo box + for( DWORD device = 0; device < dwNumDevices; device++ ) + { + D3DEnum_DeviceInfo* pDevice = &pDeviceList[device]; + + // Add device name to the combo box + DWORD dwItem = ComboBox_AddString( hwndDevice, pDevice->strDesc ); + + // Set the remaining UI states for the current device + if( pDevice == pCurrentDevice ) + { + // Set the combobox selection on the current device + ComboBox_SetCurSel( hwndDevice, dwItem ); + + // Enable/set the fullscreen checkbox, as appropriate + if( hwndWindowed ) + { + EnableWindow( hwndWindowed, pDevice->bDesktopCompatible ); + Button_SetCheck( hwndWindowed, bWindowed ); + } + + // Enable/set the stereo checkbox, as appropriate + if( hwndStereo ) + { + EnableWindow( hwndStereo, pDevice->bStereoCompatible && !bWindowed ); + Button_SetCheck( hwndStereo, bStereo ); + } + + // Enable/set the fullscreen modes combo, as appropriate + EnableWindow( hwndMode, !bWindowed ); + EnableWindow( hwndFullscreenText, !bWindowed ); + + // Build the list of fullscreen modes + for( DWORD mode = 0; mode < pDevice->dwNumModes; mode++ ) + { + DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode]; + + // Skip non-stereo modes, if the device is in stereo mode + if( 0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT) ) + if( bStereo ) + continue; + + TCHAR strMode[80]; + wsprintf( strMode, _T("%ld x %ld x %ld"), + pddsdMode->dwWidth, pddsdMode->dwHeight, + pddsdMode->ddpfPixelFormat.dwRGBBitCount ); + + // Add mode desc to the combo box + DWORD dwItem = ComboBox_AddString( hwndMode, strMode ); + + // Set the item data to identify this mode + ComboBox_SetItemData( hwndMode, dwItem, mode ); + + // Set the combobox selection on the current mode + if( mode == dwCurrentMode ) + ComboBox_SetCurSel( hwndMode, dwItem ); + + // Since not all modes support stereo, select a default mode in + // case none was chosen yet. + if( bStereo && ( CB_ERR == ComboBox_GetCurSel( hwndMode ) ) ) + ComboBox_SetCurSel( hwndMode, dwItem ); + } + } + } +} + + + + +//----------------------------------------------------------------------------- +// Name: ChangeDeviceProc() +// Desc: Windows message handling function for the device select dialog +//----------------------------------------------------------------------------- +static INT_PTR CALLBACK ChangeDeviceProc( HWND hDlg, UINT uiMsg, WPARAM wParam, + LPARAM lParam ) +{ + static D3DEnum_DeviceInfo** ppDeviceArg; + static D3DEnum_DeviceInfo* pCurrentDevice; + static DWORD dwCurrentMode; + static bool bCurrentWindowed; + static bool bCurrentStereo; + + // Get access to the enumerated device list + D3DEnum_DeviceInfo* pDeviceList; + DWORD dwNumDevices; + D3DEnum_GetDevices( &pDeviceList, &dwNumDevices ); + + // Handle the initialization message + if( WM_INITDIALOG == uiMsg ) + { + // Get the app's current device, passed in as an lParam argument + ppDeviceArg = (D3DEnum_DeviceInfo**)lParam; + if( NULL == ppDeviceArg ) + return false; + + // Setup temp storage pointers for dialog + pCurrentDevice = (*ppDeviceArg); + dwCurrentMode = pCurrentDevice->dwCurrentMode; + bCurrentWindowed = pCurrentDevice->bWindowed; + bCurrentStereo = pCurrentDevice->bStereo; + + UpdateDialogControls( hDlg, pCurrentDevice, dwCurrentMode, + bCurrentWindowed, bCurrentStereo ); + + return true; + } + else if( WM_COMMAND == uiMsg ) + { + HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO ); + HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO ); + HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX ); + HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX ); + + // Get current UI state + DWORD dwDevice = ComboBox_GetCurSel( hwndDevice ); + DWORD dwModeItem = ComboBox_GetCurSel( hwndMode ); + DWORD dwMode = ComboBox_GetItemData( hwndMode, dwModeItem ); + bool bWindowed = hwndWindowed ? Button_GetCheck( hwndWindowed ) : 0; + bool bStereo = hwndStereo ? Button_GetCheck( hwndStereo ) : 0; + + D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice]; + + if( IDOK == LOWORD(wParam) ) + { + // Handle the case when the user hits the OK button. Check if any + // of the options were changed + if( pDevice != pCurrentDevice || dwMode != dwCurrentMode || + bWindowed != bCurrentWindowed || bStereo != bCurrentStereo ) + { + // Return the newly selected device and its new properties + (*ppDeviceArg) = pDevice; + pDevice->bWindowed = bWindowed; + pDevice->bStereo = bStereo; + pDevice->dwCurrentMode = dwMode; + pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode]; + + EndDialog( hDlg, IDOK ); + } + else + EndDialog( hDlg, IDCANCEL ); + + return true; + } + else if( IDCANCEL == LOWORD(wParam) ) + { + // Handle the case when the user hits the Cancel button + EndDialog( hDlg, IDCANCEL ); + return true; + } + else if( CBN_SELENDOK == HIWORD(wParam) ) + { + if( LOWORD(wParam) == IDC_DEVICE_COMBO ) + { + // Handle the case when the user chooses the device combo + dwMode = pDeviceList[dwDevice].dwCurrentMode; + bWindowed = pDeviceList[dwDevice].bWindowed; + bStereo = pDeviceList[dwDevice].bStereo; + } + } + + // Keep the UI current + UpdateDialogControls( hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo ); + return true; + } + + return false; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_UserChangeDevice() +// Desc: Pops up a dialog which allows the user to select a new device. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice ) +{ + if( IDOK == DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL), + MAKEINTRESOURCE(IDD_CHANGEDEVICE), + GetForegroundWindow(), + ChangeDeviceProc, (LPARAM)ppDevice ) ) + return S_OK; + + return E_FAIL; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_SelectDefaultDevice() +// Desc: Pick a default device, preferably hardware and desktop compatible. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** ppDevice, + DWORD dwFlags ) +{ + // Check arguments + if( NULL == ppDevice ) + return E_INVALIDARG; + + // Get access to the enumerated device list + D3DEnum_DeviceInfo* pDeviceList; + DWORD dwNumDevices; + D3DEnum_GetDevices( &pDeviceList, &dwNumDevices ); + + // Look for windowable software, hardware, and hardware TnL devices + D3DEnum_DeviceInfo* pRefRastDevice = NULL; + D3DEnum_DeviceInfo* pSoftwareDevice = NULL; + D3DEnum_DeviceInfo* pHardwareDevice = NULL; + D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL; + + for( DWORD i=0; ibWindowed = true; + + return S_OK; +} + + + + + diff --git a/src/old/d3denum.h b/src/old/d3denum.h index 4f1edfc..fe49249 100644 --- a/src/old/d3denum.h +++ b/src/old/d3denum.h @@ -1,133 +1,133 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DEnum.h -// -// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- - -#pragma once - -#include - - -//----------------------------------------------------------------------------- -// Flag and error definitions -//----------------------------------------------------------------------------- -#define D3DENUM_SOFTWAREONLY 0x00000001 // Software-devices only flag - -#define D3DENUMERR_NODIRECTDRAW 0x81000001 // Could not create DDraw -#define D3DENUMERR_ENUMERATIONFAILED 0x81000002 // Enumeration failed -#define D3DENUMERR_SUGGESTREFRAST 0x81000003 // Suggest using the RefRast -#define D3DENUMERR_NOCOMPATIBLEDEVICES 0x81000004 // No devices were found that - // meet the app's desired - // capabilities -#define D3DENUMERR_ENGINE 0x81000005 // 3D engine error -#define D3DENUMERR_ROBOT 0x81000006 // robot error -#define D3DENUMERR_SOUND 0x81000007 // sound error - - -//----------------------------------------------------------------------------- -// Name: struct D3DEnum_DeviceInfo -// Desc: Structure to hold info about the enumerated Direct3D devices. -//----------------------------------------------------------------------------- -struct D3DEnum_DeviceInfo -{ - // D3D Device info - TCHAR strDesc[40]; - GUID* pDeviceGUID; - D3DDEVICEDESC7 ddDeviceDesc; - bool bHardware; - - // DDraw Driver info - GUID* pDriverGUID; - DDCAPS ddDriverCaps; - DDCAPS ddHELCaps; - - // DDraw Mode Info - DDSURFACEDESC2 ddsdFullscreenMode; - bool bWindowed; - bool bStereo; - - // For internal use (apps should not need to use these) - GUID guidDevice; - GUID guidDriver; - DDSURFACEDESC2* pddsdModes; - DWORD dwNumModes; - DWORD dwCurrentMode; - bool bDesktopCompatible; - bool bStereoCompatible; -}; - - -// For code not yet switched to new struct name -typedef D3DEnum_DeviceInfo D3DDEVICEINFO; - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_EnumerateDevices() -// Desc: Enumerates all drivers, devices, and modes. The callback function is -// called each device, to confirm that the device supports the feature -// set required by the app. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_EnumerateDevices( HRESULT (*fn)(DDCAPS*, D3DDEVICEDESC7*) ); - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_FreeResources() -// Desc: Cleans up any memory allocated during device enumeration -//----------------------------------------------------------------------------- -VOID D3DEnum_FreeResources(); - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_GetDevices() -// Desc: Returns a ptr to the array of enumerated D3DDEVICEINFO structures. -//----------------------------------------------------------------------------- -VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount ); - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_SelectDefaultDevice() -// Desc: Picks a driver based on a set of passed in criteria. The -// D3DENUM_SOFTWAREONLY flag can be used to pick a software device. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** pDevice, - DWORD dwFlags = 0L ); - - - - -//----------------------------------------------------------------------------- -// Name: D3DEnum_UserChangeDevice() -// Desc: Pops up a dialog which allows the user to select a new device. -//----------------------------------------------------------------------------- -HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice ); - - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DEnum.h +// +// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#pragma once + +#include + + +//----------------------------------------------------------------------------- +// Flag and error definitions +//----------------------------------------------------------------------------- +#define D3DENUM_SOFTWAREONLY 0x00000001 // Software-devices only flag + +#define D3DENUMERR_NODIRECTDRAW 0x81000001 // Could not create DDraw +#define D3DENUMERR_ENUMERATIONFAILED 0x81000002 // Enumeration failed +#define D3DENUMERR_SUGGESTREFRAST 0x81000003 // Suggest using the RefRast +#define D3DENUMERR_NOCOMPATIBLEDEVICES 0x81000004 // No devices were found that + // meet the app's desired + // capabilities +#define D3DENUMERR_ENGINE 0x81000005 // 3D engine error +#define D3DENUMERR_ROBOT 0x81000006 // robot error +#define D3DENUMERR_SOUND 0x81000007 // sound error + + +//----------------------------------------------------------------------------- +// Name: struct D3DEnum_DeviceInfo +// Desc: Structure to hold info about the enumerated Direct3D devices. +//----------------------------------------------------------------------------- +struct D3DEnum_DeviceInfo +{ + // D3D Device info + TCHAR strDesc[40]; + GUID* pDeviceGUID; + D3DDEVICEDESC7 ddDeviceDesc; + bool bHardware; + + // DDraw Driver info + GUID* pDriverGUID; + DDCAPS ddDriverCaps; + DDCAPS ddHELCaps; + + // DDraw Mode Info + DDSURFACEDESC2 ddsdFullscreenMode; + bool bWindowed; + bool bStereo; + + // For internal use (apps should not need to use these) + GUID guidDevice; + GUID guidDriver; + DDSURFACEDESC2* pddsdModes; + DWORD dwNumModes; + DWORD dwCurrentMode; + bool bDesktopCompatible; + bool bStereoCompatible; +}; + + +// For code not yet switched to new struct name +typedef D3DEnum_DeviceInfo D3DDEVICEINFO; + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_EnumerateDevices() +// Desc: Enumerates all drivers, devices, and modes. The callback function is +// called each device, to confirm that the device supports the feature +// set required by the app. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_EnumerateDevices( HRESULT (*fn)(DDCAPS*, D3DDEVICEDESC7*) ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_FreeResources() +// Desc: Cleans up any memory allocated during device enumeration +//----------------------------------------------------------------------------- +VOID D3DEnum_FreeResources(); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_GetDevices() +// Desc: Returns a ptr to the array of enumerated D3DDEVICEINFO structures. +//----------------------------------------------------------------------------- +VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_SelectDefaultDevice() +// Desc: Picks a driver based on a set of passed in criteria. The +// D3DENUM_SOFTWAREONLY flag can be used to pick a software device. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** pDevice, + DWORD dwFlags = 0L ); + + + + +//----------------------------------------------------------------------------- +// Name: D3DEnum_UserChangeDevice() +// Desc: Pops up a dialog which allows the user to select a new device. +//----------------------------------------------------------------------------- +HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice ); + + + + diff --git a/src/old/d3dframe.cpp b/src/old/d3dframe.cpp index 3f984bd..370babb 100644 --- a/src/old/d3dframe.cpp +++ b/src/old/d3dframe.cpp @@ -1,622 +1,622 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DFrame.cpp -// -// Desc: Class functions to implement a Direct3D app framework. -// -// Copyright (c) 1995-1999 by Microsoft, all rights reserved -//----------------------------------------------------------------------------- -#include -#include -#include -#include "old/d3dframe.h" -#include "old/d3dutil.h" - - - - -//----------------------------------------------------------------------------- -// Name: CD3DFramework7() -// Desc: The constructor. Clears static variables -//----------------------------------------------------------------------------- -CD3DFramework7::CD3DFramework7() -{ - m_hWnd = NULL; - m_bIsFullscreen = false; - m_bIsStereo = false; - m_dwRenderWidth = 0L; - m_dwRenderHeight = 0L; - - m_pddsFrontBuffer = NULL; - m_pddsBackBuffer = NULL; - m_pddsBackBufferLeft = NULL; - - m_pddsZBuffer = NULL; - m_pd3dDevice = NULL; - m_pDD = NULL; - m_pD3D = NULL; - m_dwDeviceMemType = NULL; -} - - - - -//----------------------------------------------------------------------------- -// Name: ~CD3DFramework7() -// Desc: The destructor. Deletes all objects -//----------------------------------------------------------------------------- -CD3DFramework7::~CD3DFramework7() -{ - DestroyObjects(); -} - - - - -//----------------------------------------------------------------------------- -// Name: DestroyObjects() -// Desc: Cleans everything up upon deletion. This code returns an error -// if any of the objects have remaining reference counts. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::DestroyObjects() -{ - LONG nDD = 0L; // Number of outstanding DDraw references - LONG nD3D = 0L; // Number of outstanding D3DDevice references - - if( m_pDD ) - { - HRESULT err = m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); - char s[100]; - sprintf(s, "SetCooperativeLevel error=%d\n", err); - OutputDebugString(s); - } - - // Do a safe check for releasing the D3DDEVICE. RefCount must be zero. - if( m_pd3dDevice ) - if( 0 < ( nD3D = m_pd3dDevice->Release() ) ) - DEBUG_MSG( _T("Error: D3DDevice object is still referenced!") ); - m_pd3dDevice = NULL; - - SAFE_RELEASE( m_pddsBackBuffer ); - SAFE_RELEASE( m_pddsBackBufferLeft ); - SAFE_RELEASE( m_pddsZBuffer ); - SAFE_RELEASE( m_pddsFrontBuffer ); - SAFE_RELEASE( m_pD3D ); - - if( m_pDD ) - { - // Do a safe check for releasing DDRAW. RefCount must be zero. - if( 0 < ( nDD = m_pDD->Release() ) ) - DEBUG_MSG( _T("Error: DDraw object is still referenced!") ); - } - m_pDD = NULL; - - // Return successful, unless there are outstanding DD or D3DDevice refs. - return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT; -} - - - - -//----------------------------------------------------------------------------- -// Name: Initialize() -// Desc: Creates the internal objects for the framework -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::Initialize( HWND hWnd, GUID* pDriverGUID, - GUID* pDeviceGUID, DDSURFACEDESC2* pMode, - DWORD dwFlags ) -{ - HRESULT hr; - - // Check params. Note: A NULL mode is valid for windowed modes only. - if( ( NULL==hWnd ) || ( NULL==pDeviceGUID ) || - ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) ) - return E_INVALIDARG; - - // Setup state for windowed/fullscreen mode - m_hWnd = hWnd; - m_bIsStereo = false; - m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? true : false; - - // Support stereoscopic viewing for fullscreen modes which support it - if( ( dwFlags & D3DFW_STEREO ) && ( dwFlags & D3DFW_FULLSCREEN ) ) - if( pMode->ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT ) - m_bIsStereo = true; - - // Create the D3D rendering environment (surfaces, device, viewport, etc.) - if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode, - dwFlags ) ) ) - { - DestroyObjects(); - return hr; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateEnvironment() -// Desc: Creates the internal objects for the framework -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID, - DDSURFACEDESC2* pMode, DWORD dwFlags ) -{ - HRESULT hr; - - // Select the default memory type, for whether the device is HW or SW - if( IsEqualIID( *pDeviceGUID, IID_IDirect3DHALDevice) ) - m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; - else if( IsEqualIID( *pDeviceGUID, IID_IDirect3DTnLHalDevice) ) - m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; - else - m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY; - - // Create the DDraw object - hr = CreateDirectDraw( pDriverGUID, dwFlags ); - if( FAILED( hr ) ) - return hr; - - // Create the front and back buffers, and attach a clipper - if( dwFlags & D3DFW_FULLSCREEN ) - hr = CreateFullscreenBuffers( pMode ); - else - hr = CreateWindowedBuffers(); - if( FAILED( hr ) ) - return hr; - - // Create the Direct3D object and the Direct3DDevice object - hr = CreateDirect3D( pDeviceGUID ); - if( FAILED( hr ) ) - return hr; - - // Create and attach the zbuffer - if( dwFlags & D3DFW_ZBUFFER ) - hr = CreateZBuffer( pDeviceGUID ); - if( FAILED( hr ) ) - return hr; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: EnumZBufferFormatsCallback() -// Desc: Simply returns the first matching enumerated z-buffer format -//----------------------------------------------------------------------------- -static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, - VOID* pContext ) -{ - DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext; - - if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount ) - { - (*pddpfOut) = (*pddpf); - return D3DENUMRET_CANCEL; - } - - return D3DENUMRET_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateDirectDraw() -// Desc: Create the DirectDraw interface -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags ) -{ - // Create the DirectDraw interface, and query for the DD7 interface - if( FAILED( DirectDrawCreateEx( pDriverGUID, (VOID**)&m_pDD, - IID_IDirectDraw7, NULL ) ) ) - { - DEBUG_MSG( _T("Could not create DirectDraw") ); - return D3DFWERR_NODIRECTDRAW; - } - - // Set the Windows cooperative level - DWORD dwCoopFlags = DDSCL_NORMAL; - if( m_bIsFullscreen ) - dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN; - - // By defualt, set the flag to allow D3D to optimize floating point calcs - if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) ) - dwCoopFlags |= DDSCL_FPUSETUP; - - if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) ) - { - DEBUG_MSG( _T("Couldn't set coop level") ); - return D3DFWERR_COULDNTSETCOOPLEVEL; - } - - // Check that we are NOT in a palettized display. That case will fail, - // since the framework doesn't use palettes. - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - m_pDD->GetDisplayMode( &ddsd ); - if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 ) - return D3DFWERR_INVALIDMODE; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateFullscreenBuffers() -// Desc: Creates the primary and (optional) backbuffer for rendering. -// Windowed mode and fullscreen mode are handled differently. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateFullscreenBuffers( DDSURFACEDESC2* pddsd ) -{ - HRESULT hr; - - // Get the dimensions of the screen bounds - // Store the rectangle which contains the renderer - SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight ); - m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left; - m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top; - - // Set the display mode to the requested dimensions. Check for - // 320x200x8 modes, and set flag to avoid using ModeX - DWORD dwModeFlags = 0; - - if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) && - (8==pddsd->ddpfPixelFormat.dwRGBBitCount) ) - dwModeFlags |= DDSDM_STANDARDVGAMODE; - - if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight, - pddsd->ddpfPixelFormat.dwRGBBitCount, - pddsd->dwRefreshRate, dwModeFlags ) ) ) - { - DEBUG_MSG( _T("Can't set display mode") ); - return D3DFWERR_BADDISPLAYMODE; - } - - // Setup to create the primary surface w/backbuffer - DDSURFACEDESC2 ddsd; - ZeroMemory( &ddsd, sizeof(ddsd) ); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | - DDSCAPS_FLIP | DDSCAPS_COMPLEX; - ddsd.dwBackBufferCount = 1; - - // Support for stereoscopic viewing - if( m_bIsStereo ) - { - ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; - ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT; - } - - // Create the primary surface - if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) - { - DEBUG_MSG( _T("Error: Can't create primary surface") ); - if( hr != DDERR_OUTOFVIDEOMEMORY ) - return D3DFWERR_NOPRIMARY; - DEBUG_MSG( _T("Error: Out of video memory") ); - return DDERR_OUTOFVIDEOMEMORY; - } - - // Get the backbuffer, which was created along with the primary. - DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 }; - if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, - &m_pddsBackBuffer ) ) ) - { - DEBUG_ERR( hr, _T("Error: Can't get the backbuffer") ); - return D3DFWERR_NOBACKBUFFER; - } - - // Increment the backbuffer count (for consistency with windowed mode) - m_pddsBackBuffer->AddRef(); - - // Support for stereoscopic viewing - if( m_bIsStereo ) - { - // Get the left backbuffer, which was created along with the primary. - DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 }; - if( FAILED( hr = m_pddsBackBuffer->GetAttachedSurface( &ddscaps, - &m_pddsBackBufferLeft ) ) ) - { - DEBUG_ERR( hr, _T("Error: Can't get the left backbuffer") ); - return D3DFWERR_NOBACKBUFFER; - } - m_pddsBackBufferLeft->AddRef(); - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateWindowedBuffers() -// Desc: Creates the primary and (optional) backbuffer for rendering. -// Windowed mode and fullscreen mode are handled differently. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateWindowedBuffers() -{ - HRESULT hr; - - // Get the dimensions of the viewport and screen bounds - GetClientRect( m_hWnd, &m_rcScreenRect ); - ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left ); - ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right ); - m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left; - m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top; - - // Create the primary surface - DDSURFACEDESC2 ddsd; - ZeroMemory( &ddsd, sizeof(ddsd) ); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) - { - DEBUG_MSG( _T("Error: Can't create primary surface") ); - if( hr != DDERR_OUTOFVIDEOMEMORY ) - return D3DFWERR_NOPRIMARY; - DEBUG_MSG( _T("Error: Out of video memory") ); - return DDERR_OUTOFVIDEOMEMORY; - } - - // If in windowed-mode, create a clipper object - LPDIRECTDRAWCLIPPER pcClipper; - if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't create clipper") ); - return D3DFWERR_NOCLIPPER; - } - - // Associate the clipper with the window - pcClipper->SetHWnd( 0, m_hWnd ); - m_pddsFrontBuffer->SetClipper( pcClipper ); - SAFE_RELEASE( pcClipper ); - - // Create a backbuffer - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; - ddsd.dwWidth = m_dwRenderWidth; - ddsd.dwHeight = m_dwRenderHeight; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; - - if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) ) - { - DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") ); - if( hr != DDERR_OUTOFVIDEOMEMORY ) - return D3DFWERR_NOBACKBUFFER; - DEBUG_MSG( _T("Error: Out of video memory") ); - return DDERR_OUTOFVIDEOMEMORY; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateDirect3D() -// Desc: Create the Direct3D interface -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateDirect3D( GUID* pDeviceGUID ) -{ - // Query DirectDraw for access to Direct3D - if( FAILED( m_pDD->QueryInterface( IID_IDirect3D7, (VOID**)&m_pD3D ) ) ) - { - DEBUG_MSG( _T("Couldn't get the Direct3D interface") ); - return D3DFWERR_NODIRECT3D; - } - - // Create the device - if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsBackBuffer, - &m_pd3dDevice) ) ) - { - DEBUG_MSG( _T("Couldn't create the D3DDevice") ); - return D3DFWERR_NO3DDEVICE; - } - - // Finally, set the viewport for the newly created device - D3DVIEWPORT7 vp = { 0, 0, m_dwRenderWidth, m_dwRenderHeight, 0.0f, 1.0f }; - - if( FAILED( m_pd3dDevice->SetViewport( &vp ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't set current viewport to device") ); - return D3DFWERR_NOVIEWPORT; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CreateZBuffer() -// Desc: Internal function called by Create() to make and attach a zbuffer -// to the renderer -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::CreateZBuffer( GUID* pDeviceGUID ) -{ - HRESULT hr; - - // Check if the device supports z-bufferless hidden surface removal. If so, - // we don't really need a z-buffer - D3DDEVICEDESC7 ddDesc; - m_pd3dDevice->GetCaps( &ddDesc ); - if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) - return S_OK; - - // Get z-buffer dimensions from the render target - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - m_pddsBackBuffer->GetSurfaceDesc( &ddsd ); - - // Setup the surface desc for the z-buffer. - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; - ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType; - ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized - - // Get an appropiate pixel format from enumeration of the formats. On the - // first pass, we look for a zbuffer dpeth which is equal to the frame - // buffer depth (as some cards unfornately require this). - m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, - (VOID*)&ddsd.ddpfPixelFormat ); - if( 0 == ddsd.ddpfPixelFormat.dwSize ) - { - // Try again, just accepting any 16-bit zbuffer - ddsd.ddpfPixelFormat.dwRGBBitCount = 16; - m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, - (VOID*)&ddsd.ddpfPixelFormat ); - - if( 0 == ddsd.ddpfPixelFormat.dwSize ) - { - DEBUG_MSG( _T("Device doesn't support requested zbuffer format") ); - return D3DFWERR_NOZBUFFER; - } - } - - // Create and attach a z-buffer - if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") ); - if( hr != DDERR_OUTOFVIDEOMEMORY ) - return D3DFWERR_NOZBUFFER; - DEBUG_MSG( _T("Error: Out of video memory") ); - return DDERR_OUTOFVIDEOMEMORY; - } - - if( FAILED( m_pddsBackBuffer->AddAttachedSurface( m_pddsZBuffer ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") ); - return D3DFWERR_NOZBUFFER; - } - - // For stereoscopic viewing, attach zbuffer to left surface as well - if( m_bIsStereo ) - { - if( FAILED( m_pddsBackBufferLeft->AddAttachedSurface( m_pddsZBuffer ) ) ) - { - DEBUG_MSG( _T("Error: Couldn't attach zbuffer to left render surface") ); - return D3DFWERR_NOZBUFFER; - } - } - - // Finally, this call rebuilds internal structures - if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsBackBuffer, 0L ) ) ) - { - DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") ); - return D3DFWERR_NOZBUFFER; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: RestoreSurfaces() -// Desc: Checks for lost surfaces and restores them if lost. Note: Don't -// restore render surface, since it's just a duplicate ptr. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::RestoreSurfaces() -{ - // Restore all surfaces (including video memory vertex buffers) - m_pDD->RestoreAllSurfaces(); - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: Move() -// Desc: Moves the screen rect for windowed renderers -//----------------------------------------------------------------------------- -VOID CD3DFramework7::Move( INT x, INT y ) -{ - if( true == m_bIsFullscreen ) - return; - - SetRect( &m_rcScreenRect, x, y, x + m_dwRenderWidth, y + m_dwRenderHeight ); -} - - - - -//----------------------------------------------------------------------------- -// Name: FlipToGDISurface() -// Desc: Puts the GDI surface in front of the primary, so that dialog -// boxes and other windows drawing funcs may happen. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::FlipToGDISurface( bool bDrawFrame ) -{ - if( m_pDD && m_bIsFullscreen ) - { - m_pDD->FlipToGDISurface(); - - if( bDrawFrame ) - { - DrawMenuBar( m_hWnd ); - RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME ); - } - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: ShowFrame() -// Desc: Show the frame on the primary surface, via a blt or a flip. -//----------------------------------------------------------------------------- -HRESULT CD3DFramework7::ShowFrame() -{ - if( NULL == m_pddsFrontBuffer ) - return D3DFWERR_NOTINITIALIZED; - - if( m_bIsFullscreen ) - { - // We are in fullscreen mode, so perform a flip. - if( m_bIsStereo ) - return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO ); - else - return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT ); - } - else - { - // We are in windowed mode, so perform a blit. - return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer, - NULL, DDBLT_WAIT, NULL ); - } -} - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DFrame.cpp +// +// Desc: Class functions to implement a Direct3D app framework. +// +// Copyright (c) 1995-1999 by Microsoft, all rights reserved +//----------------------------------------------------------------------------- +#include +#include +#include +#include "old/d3dframe.h" +#include "old/d3dutil.h" + + + + +//----------------------------------------------------------------------------- +// Name: CD3DFramework7() +// Desc: The constructor. Clears static variables +//----------------------------------------------------------------------------- +CD3DFramework7::CD3DFramework7() +{ + m_hWnd = NULL; + m_bIsFullscreen = false; + m_bIsStereo = false; + m_dwRenderWidth = 0L; + m_dwRenderHeight = 0L; + + m_pddsFrontBuffer = NULL; + m_pddsBackBuffer = NULL; + m_pddsBackBufferLeft = NULL; + + m_pddsZBuffer = NULL; + m_pd3dDevice = NULL; + m_pDD = NULL; + m_pD3D = NULL; + m_dwDeviceMemType = NULL; +} + + + + +//----------------------------------------------------------------------------- +// Name: ~CD3DFramework7() +// Desc: The destructor. Deletes all objects +//----------------------------------------------------------------------------- +CD3DFramework7::~CD3DFramework7() +{ + DestroyObjects(); +} + + + + +//----------------------------------------------------------------------------- +// Name: DestroyObjects() +// Desc: Cleans everything up upon deletion. This code returns an error +// if any of the objects have remaining reference counts. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::DestroyObjects() +{ + LONG nDD = 0L; // Number of outstanding DDraw references + LONG nD3D = 0L; // Number of outstanding D3DDevice references + + if( m_pDD ) + { + HRESULT err = m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); + char s[100]; + sprintf(s, "SetCooperativeLevel error=%d\n", err); + OutputDebugString(s); + } + + // Do a safe check for releasing the D3DDEVICE. RefCount must be zero. + if( m_pd3dDevice ) + if( 0 < ( nD3D = m_pd3dDevice->Release() ) ) + DEBUG_MSG( _T("Error: D3DDevice object is still referenced!") ); + m_pd3dDevice = NULL; + + SAFE_RELEASE( m_pddsBackBuffer ); + SAFE_RELEASE( m_pddsBackBufferLeft ); + SAFE_RELEASE( m_pddsZBuffer ); + SAFE_RELEASE( m_pddsFrontBuffer ); + SAFE_RELEASE( m_pD3D ); + + if( m_pDD ) + { + // Do a safe check for releasing DDRAW. RefCount must be zero. + if( 0 < ( nDD = m_pDD->Release() ) ) + DEBUG_MSG( _T("Error: DDraw object is still referenced!") ); + } + m_pDD = NULL; + + // Return successful, unless there are outstanding DD or D3DDevice refs. + return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT; +} + + + + +//----------------------------------------------------------------------------- +// Name: Initialize() +// Desc: Creates the internal objects for the framework +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::Initialize( HWND hWnd, GUID* pDriverGUID, + GUID* pDeviceGUID, DDSURFACEDESC2* pMode, + DWORD dwFlags ) +{ + HRESULT hr; + + // Check params. Note: A NULL mode is valid for windowed modes only. + if( ( NULL==hWnd ) || ( NULL==pDeviceGUID ) || + ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) ) + return E_INVALIDARG; + + // Setup state for windowed/fullscreen mode + m_hWnd = hWnd; + m_bIsStereo = false; + m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? true : false; + + // Support stereoscopic viewing for fullscreen modes which support it + if( ( dwFlags & D3DFW_STEREO ) && ( dwFlags & D3DFW_FULLSCREEN ) ) + if( pMode->ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT ) + m_bIsStereo = true; + + // Create the D3D rendering environment (surfaces, device, viewport, etc.) + if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode, + dwFlags ) ) ) + { + DestroyObjects(); + return hr; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateEnvironment() +// Desc: Creates the internal objects for the framework +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID, + DDSURFACEDESC2* pMode, DWORD dwFlags ) +{ + HRESULT hr; + + // Select the default memory type, for whether the device is HW or SW + if( IsEqualIID( *pDeviceGUID, IID_IDirect3DHALDevice) ) + m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; + else if( IsEqualIID( *pDeviceGUID, IID_IDirect3DTnLHalDevice) ) + m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; + else + m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY; + + // Create the DDraw object + hr = CreateDirectDraw( pDriverGUID, dwFlags ); + if( FAILED( hr ) ) + return hr; + + // Create the front and back buffers, and attach a clipper + if( dwFlags & D3DFW_FULLSCREEN ) + hr = CreateFullscreenBuffers( pMode ); + else + hr = CreateWindowedBuffers(); + if( FAILED( hr ) ) + return hr; + + // Create the Direct3D object and the Direct3DDevice object + hr = CreateDirect3D( pDeviceGUID ); + if( FAILED( hr ) ) + return hr; + + // Create and attach the zbuffer + if( dwFlags & D3DFW_ZBUFFER ) + hr = CreateZBuffer( pDeviceGUID ); + if( FAILED( hr ) ) + return hr; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: EnumZBufferFormatsCallback() +// Desc: Simply returns the first matching enumerated z-buffer format +//----------------------------------------------------------------------------- +static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, + VOID* pContext ) +{ + DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext; + + if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount ) + { + (*pddpfOut) = (*pddpf); + return D3DENUMRET_CANCEL; + } + + return D3DENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateDirectDraw() +// Desc: Create the DirectDraw interface +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags ) +{ + // Create the DirectDraw interface, and query for the DD7 interface + if( FAILED( DirectDrawCreateEx( pDriverGUID, (VOID**)&m_pDD, + IID_IDirectDraw7, NULL ) ) ) + { + DEBUG_MSG( _T("Could not create DirectDraw") ); + return D3DFWERR_NODIRECTDRAW; + } + + // Set the Windows cooperative level + DWORD dwCoopFlags = DDSCL_NORMAL; + if( m_bIsFullscreen ) + dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN; + + // By defualt, set the flag to allow D3D to optimize floating point calcs + if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) ) + dwCoopFlags |= DDSCL_FPUSETUP; + + if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) ) + { + DEBUG_MSG( _T("Couldn't set coop level") ); + return D3DFWERR_COULDNTSETCOOPLEVEL; + } + + // Check that we are NOT in a palettized display. That case will fail, + // since the framework doesn't use palettes. + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + m_pDD->GetDisplayMode( &ddsd ); + if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 ) + return D3DFWERR_INVALIDMODE; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateFullscreenBuffers() +// Desc: Creates the primary and (optional) backbuffer for rendering. +// Windowed mode and fullscreen mode are handled differently. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateFullscreenBuffers( DDSURFACEDESC2* pddsd ) +{ + HRESULT hr; + + // Get the dimensions of the screen bounds + // Store the rectangle which contains the renderer + SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight ); + m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left; + m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top; + + // Set the display mode to the requested dimensions. Check for + // 320x200x8 modes, and set flag to avoid using ModeX + DWORD dwModeFlags = 0; + + if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) && + (8==pddsd->ddpfPixelFormat.dwRGBBitCount) ) + dwModeFlags |= DDSDM_STANDARDVGAMODE; + + if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight, + pddsd->ddpfPixelFormat.dwRGBBitCount, + pddsd->dwRefreshRate, dwModeFlags ) ) ) + { + DEBUG_MSG( _T("Can't set display mode") ); + return D3DFWERR_BADDISPLAYMODE; + } + + // Setup to create the primary surface w/backbuffer + DDSURFACEDESC2 ddsd; + ZeroMemory( &ddsd, sizeof(ddsd) ); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | + DDSCAPS_FLIP | DDSCAPS_COMPLEX; + ddsd.dwBackBufferCount = 1; + + // Support for stereoscopic viewing + if( m_bIsStereo ) + { + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT; + } + + // Create the primary surface + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) + { + DEBUG_MSG( _T("Error: Can't create primary surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOPRIMARY; + DEBUG_MSG( _T("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + // Get the backbuffer, which was created along with the primary. + DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 }; + if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, + &m_pddsBackBuffer ) ) ) + { + DEBUG_ERR( hr, _T("Error: Can't get the backbuffer") ); + return D3DFWERR_NOBACKBUFFER; + } + + // Increment the backbuffer count (for consistency with windowed mode) + m_pddsBackBuffer->AddRef(); + + // Support for stereoscopic viewing + if( m_bIsStereo ) + { + // Get the left backbuffer, which was created along with the primary. + DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 }; + if( FAILED( hr = m_pddsBackBuffer->GetAttachedSurface( &ddscaps, + &m_pddsBackBufferLeft ) ) ) + { + DEBUG_ERR( hr, _T("Error: Can't get the left backbuffer") ); + return D3DFWERR_NOBACKBUFFER; + } + m_pddsBackBufferLeft->AddRef(); + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateWindowedBuffers() +// Desc: Creates the primary and (optional) backbuffer for rendering. +// Windowed mode and fullscreen mode are handled differently. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateWindowedBuffers() +{ + HRESULT hr; + + // Get the dimensions of the viewport and screen bounds + GetClientRect( m_hWnd, &m_rcScreenRect ); + ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left ); + ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right ); + m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left; + m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top; + + // Create the primary surface + DDSURFACEDESC2 ddsd; + ZeroMemory( &ddsd, sizeof(ddsd) ); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) + { + DEBUG_MSG( _T("Error: Can't create primary surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOPRIMARY; + DEBUG_MSG( _T("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + // If in windowed-mode, create a clipper object + LPDIRECTDRAWCLIPPER pcClipper; + if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't create clipper") ); + return D3DFWERR_NOCLIPPER; + } + + // Associate the clipper with the window + pcClipper->SetHWnd( 0, m_hWnd ); + m_pddsFrontBuffer->SetClipper( pcClipper ); + SAFE_RELEASE( pcClipper ); + + // Create a backbuffer + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwWidth = m_dwRenderWidth; + ddsd.dwHeight = m_dwRenderHeight; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) ) + { + DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOBACKBUFFER; + DEBUG_MSG( _T("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateDirect3D() +// Desc: Create the Direct3D interface +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateDirect3D( GUID* pDeviceGUID ) +{ + // Query DirectDraw for access to Direct3D + if( FAILED( m_pDD->QueryInterface( IID_IDirect3D7, (VOID**)&m_pD3D ) ) ) + { + DEBUG_MSG( _T("Couldn't get the Direct3D interface") ); + return D3DFWERR_NODIRECT3D; + } + + // Create the device + if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsBackBuffer, + &m_pd3dDevice) ) ) + { + DEBUG_MSG( _T("Couldn't create the D3DDevice") ); + return D3DFWERR_NO3DDEVICE; + } + + // Finally, set the viewport for the newly created device + D3DVIEWPORT7 vp = { 0, 0, m_dwRenderWidth, m_dwRenderHeight, 0.0f, 1.0f }; + + if( FAILED( m_pd3dDevice->SetViewport( &vp ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't set current viewport to device") ); + return D3DFWERR_NOVIEWPORT; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CreateZBuffer() +// Desc: Internal function called by Create() to make and attach a zbuffer +// to the renderer +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::CreateZBuffer( GUID* pDeviceGUID ) +{ + HRESULT hr; + + // Check if the device supports z-bufferless hidden surface removal. If so, + // we don't really need a z-buffer + D3DDEVICEDESC7 ddDesc; + m_pd3dDevice->GetCaps( &ddDesc ); + if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) + return S_OK; + + // Get z-buffer dimensions from the render target + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + m_pddsBackBuffer->GetSurfaceDesc( &ddsd ); + + // Setup the surface desc for the z-buffer. + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType; + ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized + + // Get an appropiate pixel format from enumeration of the formats. On the + // first pass, we look for a zbuffer dpeth which is equal to the frame + // buffer depth (as some cards unfornately require this). + m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat ); + if( 0 == ddsd.ddpfPixelFormat.dwSize ) + { + // Try again, just accepting any 16-bit zbuffer + ddsd.ddpfPixelFormat.dwRGBBitCount = 16; + m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, + (VOID*)&ddsd.ddpfPixelFormat ); + + if( 0 == ddsd.ddpfPixelFormat.dwSize ) + { + DEBUG_MSG( _T("Device doesn't support requested zbuffer format") ); + return D3DFWERR_NOZBUFFER; + } + } + + // Create and attach a z-buffer + if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") ); + if( hr != DDERR_OUTOFVIDEOMEMORY ) + return D3DFWERR_NOZBUFFER; + DEBUG_MSG( _T("Error: Out of video memory") ); + return DDERR_OUTOFVIDEOMEMORY; + } + + if( FAILED( m_pddsBackBuffer->AddAttachedSurface( m_pddsZBuffer ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") ); + return D3DFWERR_NOZBUFFER; + } + + // For stereoscopic viewing, attach zbuffer to left surface as well + if( m_bIsStereo ) + { + if( FAILED( m_pddsBackBufferLeft->AddAttachedSurface( m_pddsZBuffer ) ) ) + { + DEBUG_MSG( _T("Error: Couldn't attach zbuffer to left render surface") ); + return D3DFWERR_NOZBUFFER; + } + } + + // Finally, this call rebuilds internal structures + if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsBackBuffer, 0L ) ) ) + { + DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") ); + return D3DFWERR_NOZBUFFER; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: RestoreSurfaces() +// Desc: Checks for lost surfaces and restores them if lost. Note: Don't +// restore render surface, since it's just a duplicate ptr. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::RestoreSurfaces() +{ + // Restore all surfaces (including video memory vertex buffers) + m_pDD->RestoreAllSurfaces(); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: Move() +// Desc: Moves the screen rect for windowed renderers +//----------------------------------------------------------------------------- +VOID CD3DFramework7::Move( INT x, INT y ) +{ + if( true == m_bIsFullscreen ) + return; + + SetRect( &m_rcScreenRect, x, y, x + m_dwRenderWidth, y + m_dwRenderHeight ); +} + + + + +//----------------------------------------------------------------------------- +// Name: FlipToGDISurface() +// Desc: Puts the GDI surface in front of the primary, so that dialog +// boxes and other windows drawing funcs may happen. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::FlipToGDISurface( bool bDrawFrame ) +{ + if( m_pDD && m_bIsFullscreen ) + { + m_pDD->FlipToGDISurface(); + + if( bDrawFrame ) + { + DrawMenuBar( m_hWnd ); + RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME ); + } + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: ShowFrame() +// Desc: Show the frame on the primary surface, via a blt or a flip. +//----------------------------------------------------------------------------- +HRESULT CD3DFramework7::ShowFrame() +{ + if( NULL == m_pddsFrontBuffer ) + return D3DFWERR_NOTINITIALIZED; + + if( m_bIsFullscreen ) + { + // We are in fullscreen mode, so perform a flip. + if( m_bIsStereo ) + return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO ); + else + return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT ); + } + else + { + // We are in windowed mode, so perform a blit. + return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer, + NULL, DDBLT_WAIT, NULL ); + } +} + + + diff --git a/src/old/d3dframe.h b/src/old/d3dframe.h index 1c02e04..10eee57 100644 --- a/src/old/d3dframe.h +++ b/src/old/d3dframe.h @@ -1,141 +1,141 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DFrame.h -// -// Desc: Class to manage the Direct3D environment objects such as buffers, -// viewports, and 3D devices. -// -// The class is initialized with the Initialize() function, after which -// the Get????() functions can be used to access the objects needed for -// rendering. If the device or display needs to be changed, the -// ChangeDevice() function can be called. If the display window is moved -// the changes need to be reported with the Move() function. -// -// After rendering a frame, the ShowFrame() function filps or blits the -// backbuffer contents to the primary. If surfaces are lost, they can be -// restored with the RestoreSurfaces() function. Finally, if normal -// Windows output is needed, the FlipToGDISurface() provides a GDI -// surface to draw on. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- - -#pragma once - -#include -#include - - - - -//----------------------------------------------------------------------------- -// Name: CD3DFramework7 -// Desc: The Direct3D sample framework class for DX7. Maintains the D3D -// surfaces and device used for 3D rendering. -//----------------------------------------------------------------------------- -class CD3DFramework7 -{ - // Internal variables for the framework class - HWND m_hWnd; // The window object - bool m_bIsFullscreen; // Fullscreen vs. windowed - bool m_bIsStereo; // Stereo view mode - DWORD m_dwRenderWidth; // Dimensions of the render target - DWORD m_dwRenderHeight; - RECT m_rcScreenRect; // Screen rect for window - LPDIRECTDRAW7 m_pDD; // The DirectDraw object - LPDIRECT3D7 m_pD3D; // The Direct3D object - LPDIRECT3DDEVICE7 m_pd3dDevice; // The D3D device - LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer; // The primary surface - LPDIRECTDRAWSURFACE7 m_pddsBackBuffer; // The backbuffer surface - LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes - LPDIRECTDRAWSURFACE7 m_pddsZBuffer; // The zbuffer surface - DWORD m_dwDeviceMemType; - - // Internal functions for the framework class - HRESULT CreateZBuffer( GUID* ); - HRESULT CreateFullscreenBuffers( DDSURFACEDESC2* ); - HRESULT CreateWindowedBuffers(); - HRESULT CreateDirectDraw( GUID*, DWORD ); - HRESULT CreateDirect3D( GUID* ); - HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*, DWORD ); - -public: - // Access functions for DirectX objects - LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; } - LPDIRECT3D7 GetDirect3D() { return m_pD3D; } - LPDIRECT3DDEVICE7 GetD3DDevice() { return m_pd3dDevice; } - LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; } - LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; } - LPDIRECTDRAWSURFACE7 GetRenderSurface() { return m_pddsBackBuffer; } - LPDIRECTDRAWSURFACE7 GetRenderSurfaceLeft() { return m_pddsBackBufferLeft; } - - // Functions to aid rendering - HRESULT RestoreSurfaces(); - HRESULT ShowFrame(); - HRESULT FlipToGDISurface( bool bDrawFrame = false ); - - // Functions for managing screen and viewport bounds - bool IsFullscreen() { return m_bIsFullscreen; } - bool IsStereo() { return m_bIsStereo; } - VOID Move( INT x, INT y ); - - // Creates the Framework - HRESULT Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID, - DDSURFACEDESC2* pddsd, DWORD dwFlags ); - HRESULT DestroyObjects(); - - CD3DFramework7(); - ~CD3DFramework7(); -}; - - - - -//----------------------------------------------------------------------------- -// Flags used for the Initialize() method of a CD3DFramework object -//----------------------------------------------------------------------------- -#define D3DFW_FULLSCREEN 0x00000001 // Use fullscreen mode -#define D3DFW_STEREO 0x00000002 // Use stereo-scopic viewing -#define D3DFW_ZBUFFER 0x00000004 // Create and use a zbuffer -#define D3DFW_NO_FPUSETUP 0x00000008 // Don't use default DDSCL_FPUSETUP flag - - - - -//----------------------------------------------------------------------------- -// Errors that the Initialize() and ChangeDriver() calls may return -//----------------------------------------------------------------------------- -#define D3DFWERR_INITIALIZATIONFAILED 0x82000000 -#define D3DFWERR_NODIRECTDRAW 0x82000001 -#define D3DFWERR_COULDNTSETCOOPLEVEL 0x82000002 -#define D3DFWERR_NODIRECT3D 0x82000003 -#define D3DFWERR_NO3DDEVICE 0x82000004 -#define D3DFWERR_NOZBUFFER 0x82000005 -#define D3DFWERR_INVALIDZBUFFERDEPTH 0x82000006 -#define D3DFWERR_NOVIEWPORT 0x82000007 -#define D3DFWERR_NOPRIMARY 0x82000008 -#define D3DFWERR_NOCLIPPER 0x82000009 -#define D3DFWERR_BADDISPLAYMODE 0x8200000a -#define D3DFWERR_NOBACKBUFFER 0x8200000b -#define D3DFWERR_NONZEROREFCOUNT 0x8200000c -#define D3DFWERR_NORENDERTARGET 0x8200000d -#define D3DFWERR_INVALIDMODE 0x8200000e -#define D3DFWERR_NOTINITIALIZED 0x8200000f - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DFrame.h +// +// Desc: Class to manage the Direct3D environment objects such as buffers, +// viewports, and 3D devices. +// +// The class is initialized with the Initialize() function, after which +// the Get????() functions can be used to access the objects needed for +// rendering. If the device or display needs to be changed, the +// ChangeDevice() function can be called. If the display window is moved +// the changes need to be reported with the Move() function. +// +// After rendering a frame, the ShowFrame() function filps or blits the +// backbuffer contents to the primary. If surfaces are lost, they can be +// restored with the RestoreSurfaces() function. Finally, if normal +// Windows output is needed, the FlipToGDISurface() provides a GDI +// surface to draw on. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include + + + + +//----------------------------------------------------------------------------- +// Name: CD3DFramework7 +// Desc: The Direct3D sample framework class for DX7. Maintains the D3D +// surfaces and device used for 3D rendering. +//----------------------------------------------------------------------------- +class CD3DFramework7 +{ + // Internal variables for the framework class + HWND m_hWnd; // The window object + bool m_bIsFullscreen; // Fullscreen vs. windowed + bool m_bIsStereo; // Stereo view mode + DWORD m_dwRenderWidth; // Dimensions of the render target + DWORD m_dwRenderHeight; + RECT m_rcScreenRect; // Screen rect for window + LPDIRECTDRAW7 m_pDD; // The DirectDraw object + LPDIRECT3D7 m_pD3D; // The Direct3D object + LPDIRECT3DDEVICE7 m_pd3dDevice; // The D3D device + LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer; // The primary surface + LPDIRECTDRAWSURFACE7 m_pddsBackBuffer; // The backbuffer surface + LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes + LPDIRECTDRAWSURFACE7 m_pddsZBuffer; // The zbuffer surface + DWORD m_dwDeviceMemType; + + // Internal functions for the framework class + HRESULT CreateZBuffer( GUID* ); + HRESULT CreateFullscreenBuffers( DDSURFACEDESC2* ); + HRESULT CreateWindowedBuffers(); + HRESULT CreateDirectDraw( GUID*, DWORD ); + HRESULT CreateDirect3D( GUID* ); + HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*, DWORD ); + +public: + // Access functions for DirectX objects + LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; } + LPDIRECT3D7 GetDirect3D() { return m_pD3D; } + LPDIRECT3DDEVICE7 GetD3DDevice() { return m_pd3dDevice; } + LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; } + LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; } + LPDIRECTDRAWSURFACE7 GetRenderSurface() { return m_pddsBackBuffer; } + LPDIRECTDRAWSURFACE7 GetRenderSurfaceLeft() { return m_pddsBackBufferLeft; } + + // Functions to aid rendering + HRESULT RestoreSurfaces(); + HRESULT ShowFrame(); + HRESULT FlipToGDISurface( bool bDrawFrame = false ); + + // Functions for managing screen and viewport bounds + bool IsFullscreen() { return m_bIsFullscreen; } + bool IsStereo() { return m_bIsStereo; } + VOID Move( INT x, INT y ); + + // Creates the Framework + HRESULT Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID, + DDSURFACEDESC2* pddsd, DWORD dwFlags ); + HRESULT DestroyObjects(); + + CD3DFramework7(); + ~CD3DFramework7(); +}; + + + + +//----------------------------------------------------------------------------- +// Flags used for the Initialize() method of a CD3DFramework object +//----------------------------------------------------------------------------- +#define D3DFW_FULLSCREEN 0x00000001 // Use fullscreen mode +#define D3DFW_STEREO 0x00000002 // Use stereo-scopic viewing +#define D3DFW_ZBUFFER 0x00000004 // Create and use a zbuffer +#define D3DFW_NO_FPUSETUP 0x00000008 // Don't use default DDSCL_FPUSETUP flag + + + + +//----------------------------------------------------------------------------- +// Errors that the Initialize() and ChangeDriver() calls may return +//----------------------------------------------------------------------------- +#define D3DFWERR_INITIALIZATIONFAILED 0x82000000 +#define D3DFWERR_NODIRECTDRAW 0x82000001 +#define D3DFWERR_COULDNTSETCOOPLEVEL 0x82000002 +#define D3DFWERR_NODIRECT3D 0x82000003 +#define D3DFWERR_NO3DDEVICE 0x82000004 +#define D3DFWERR_NOZBUFFER 0x82000005 +#define D3DFWERR_INVALIDZBUFFERDEPTH 0x82000006 +#define D3DFWERR_NOVIEWPORT 0x82000007 +#define D3DFWERR_NOPRIMARY 0x82000008 +#define D3DFWERR_NOCLIPPER 0x82000009 +#define D3DFWERR_BADDISPLAYMODE 0x8200000a +#define D3DFWERR_NOBACKBUFFER 0x8200000b +#define D3DFWERR_NONZEROREFCOUNT 0x8200000c +#define D3DFWERR_NORENDERTARGET 0x8200000d +#define D3DFWERR_INVALIDMODE 0x8200000e +#define D3DFWERR_NOTINITIALIZED 0x8200000f + + + diff --git a/src/old/d3dmath.cpp b/src/old/d3dmath.cpp index 2686215..15308fe 100644 --- a/src/old/d3dmath.cpp +++ b/src/old/d3dmath.cpp @@ -1,343 +1,343 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DMath.cpp -// -// Desc: Shortcut macros and functions for using DX objects -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- -#define D3D_OVERLOADS -#define STRICT -#include -#include -#include "d3dmath.h" - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_MatrixMultiply() -// Desc: Does the matrix operation: [Q] = [A] * [B]. Note that the order of -// this operation was changed from the previous version of the DXSDK. -//----------------------------------------------------------------------------- -VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b ) -{ - FLOAT* pA = (FLOAT*)&a; - FLOAT* pB = (FLOAT*)&b; - FLOAT pM[16]; - - ZeroMemory( pM, sizeof(D3DMATRIX) ); - - for( WORD i=0; i<4; i++ ) - for( WORD j=0; j<4; j++ ) - for( WORD k=0; k<4; k++ ) - pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; - - memcpy( &q, pM, sizeof(D3DMATRIX) ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_MatrixInvert() -// Desc: Does the matrix operation: [Q] = inv[A]. Note: this function only -// works for matrices with [0 0 0 1] for the 4th column. -//----------------------------------------------------------------------------- -HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a ) -{ - if( fabs(a._44 - 1.0f) > .001f) - return E_INVALIDARG; - if( fabs(a._14) > .001f || fabs(a._24) > .001f || fabs(a._34) > .001f ) - return E_INVALIDARG; - - FLOAT fDetInv = 1.0f / ( a._11 * ( a._22 * a._33 - a._23 * a._32 ) - - a._12 * ( a._21 * a._33 - a._23 * a._31 ) + - a._13 * ( a._21 * a._32 - a._22 * a._31 ) ); - - q._11 = fDetInv * ( a._22 * a._33 - a._23 * a._32 ); - q._12 = -fDetInv * ( a._12 * a._33 - a._13 * a._32 ); - q._13 = fDetInv * ( a._12 * a._23 - a._13 * a._22 ); - q._14 = 0.0f; - - q._21 = -fDetInv * ( a._21 * a._33 - a._23 * a._31 ); - q._22 = fDetInv * ( a._11 * a._33 - a._13 * a._31 ); - q._23 = -fDetInv * ( a._11 * a._23 - a._13 * a._21 ); - q._24 = 0.0f; - - q._31 = fDetInv * ( a._21 * a._32 - a._22 * a._31 ); - q._32 = -fDetInv * ( a._11 * a._32 - a._12 * a._31 ); - q._33 = fDetInv * ( a._11 * a._22 - a._12 * a._21 ); - q._34 = 0.0f; - - q._41 = -( a._41 * q._11 + a._42 * q._21 + a._43 * q._31 ); - q._42 = -( a._41 * q._12 + a._42 * q._22 + a._43 * q._32 ); - q._43 = -( a._41 * q._13 + a._42 * q._23 + a._43 * q._33 ); - q._44 = 1.0f; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_VectorMatrixMultiply() -// Desc: Multiplies a vector by a matrix -//----------------------------------------------------------------------------- -HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc, - D3DMATRIX& mat) -{ - FLOAT x = vSrc.x*mat._11 + vSrc.y*mat._21 + vSrc.z* mat._31 + mat._41; - FLOAT y = vSrc.x*mat._12 + vSrc.y*mat._22 + vSrc.z* mat._32 + mat._42; - FLOAT z = vSrc.x*mat._13 + vSrc.y*mat._23 + vSrc.z* mat._33 + mat._43; - FLOAT w = vSrc.x*mat._14 + vSrc.y*mat._24 + vSrc.z* mat._34 + mat._44; - - if( fabs( w ) < g_EPSILON ) - return E_INVALIDARG; - - vDest.x = x/w; - vDest.y = y/w; - vDest.z = z/w; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_VertexMatrixMultiply() -// Desc: Multiplies a vertex by a matrix -//----------------------------------------------------------------------------- -HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc, - D3DMATRIX& mat ) -{ - HRESULT hr; - D3DVECTOR* pSrcVec = (D3DVECTOR*)&vSrc.x; - D3DVECTOR* pDestVec = (D3DVECTOR*)&vDest.x; - - if( SUCCEEDED( hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec, - mat ) ) ) - { - pSrcVec = (D3DVECTOR*)&vSrc.nx; - pDestVec = (D3DVECTOR*)&vDest.nx; - hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec, mat ); - } - return hr; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_QuaternionFromRotation() -// Desc: Converts a normalized axis and angle to a unit quaternion. -//----------------------------------------------------------------------------- -VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, - D3DVECTOR& v, FLOAT fTheta ) -{ - x = sinf( fTheta/2.0f ) * v.x; - y = sinf( fTheta/2.0f ) * v.y; - z = sinf( fTheta/2.0f ) * v.z; - w = cosf( fTheta/2.0f ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_RotationFromQuaternion() -// Desc: Converts a normalized axis and angle to a unit quaternion. -//----------------------------------------------------------------------------- -VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta, - FLOAT x, FLOAT y, FLOAT z, FLOAT w ) - -{ - fTheta = acosf(w) * 2.0f; - v.x = x / sinf( fTheta/2.0f ); - v.y = y / sinf( fTheta/2.0f ); - v.z = z / sinf( fTheta/2.0f ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_QuaternionFromAngles() -// Desc: Converts euler angles to a unit quaternion. -//----------------------------------------------------------------------------- -VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, - FLOAT fYaw, FLOAT fPitch, FLOAT fRoll ) - -{ - FLOAT fSinYaw = sinf( fYaw/2.0f ); - FLOAT fSinPitch = sinf( fPitch/2.0f ); - FLOAT fSinRoll = sinf( fRoll/2.0f ); - FLOAT fCosYaw = cosf( fYaw/2.0f ); - FLOAT fCosPitch = cosf( fPitch/2.0f ); - FLOAT fCosRoll = cosf( fRoll/2.0f ); - - x = fSinRoll * fCosPitch * fCosYaw - fCosRoll * fSinPitch * fSinYaw; - y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw; - z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw; - w = fCosRoll * fCosPitch * fCosYaw + fSinRoll * fSinPitch * fSinYaw; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_MatrixFromQuaternion() -// Desc: Converts a unit quaternion into a rotation matrix. -//----------------------------------------------------------------------------- -VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z, - FLOAT w ) -{ - FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z; - FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z; - FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z; - - mat._11 = 1 - 2 * ( yy + zz ); - mat._12 = 2 * ( xy - wz ); - mat._13 = 2 * ( xz + wy ); - - mat._21 = 2 * ( xy + wz ); - mat._22 = 1 - 2 * ( xx + zz ); - mat._23 = 2 * ( yz - wx ); - - mat._31 = 2 * ( xz - wy ); - mat._32 = 2 * ( yz + wx ); - mat._33 = 1 - 2 * ( xx + yy ); - - mat._14 = mat._24 = mat._34 = 0.0f; - mat._41 = mat._42 = mat._43 = 0.0f; - mat._44 = 1.0f; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_QuaternionFromMatrix() -// Desc: Converts a rotation matrix into a unit quaternion. -//----------------------------------------------------------------------------- -VOID D3DMath_QuaternionFromMatrix( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, - D3DMATRIX& mat ) -{ - if( mat._11 + mat._22 + mat._33 > 0.0f ) - { - FLOAT s = sqrtf( mat._11 + mat._22 + mat._33 + mat._44 ); - - x = (mat._23-mat._32) / (2*s); - y = (mat._31-mat._13) / (2*s); - z = (mat._12-mat._21) / (2*s); - w = 0.5f * s; - } - else - { - - - } - FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z; - FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z; - FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z; - - mat._11 = 1 - 2 * ( yy + zz ); - mat._12 = 2 * ( xy - wz ); - mat._13 = 2 * ( xz + wy ); - - mat._21 = 2 * ( xy + wz ); - mat._22 = 1 - 2 * ( xx + zz ); - mat._23 = 2 * ( yz - wx ); - - mat._31 = 2 * ( xz - wy ); - mat._32 = 2 * ( yz + wx ); - mat._33 = 1 - 2 * ( xx + yy ); - - mat._14 = mat._24 = mat._34 = 0.0f; - mat._41 = mat._42 = mat._43 = 0.0f; - mat._44 = 1.0f; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_QuaternionMultiply() -// Desc: Mulitples two quaternions together as in {Q} = {A} * {B}. -//----------------------------------------------------------------------------- -VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, - FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, - FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw ) -{ - FLOAT Dx = Ax*Bw + Ay*Bz - Az*By + Aw*Bx; - FLOAT Dy = -Ax*Bz + Ay*Bw + Az*Bx + Aw*By; - FLOAT Dz = Ax*By - Ay*Bx + Az*Bw + Aw*Bz; - FLOAT Dw = -Ax*Bx - Ay*By - Az*Bz + Aw*Bw; - - Qx = Dx; Qy = Dy; Qz = Dz; Qw = Dw; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DMath_SlerpQuaternions() -// Desc: Compute a quaternion which is the spherical linear interpolation -// between two other quaternions by dvFraction. -//----------------------------------------------------------------------------- -VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, - FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, - FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw, - FLOAT fAlpha ) -{ - // Compute dot product (equal to cosine of the angle between quaternions) - FLOAT fCosTheta = Ax*Bx + Ay*By + Az*Bz + Aw*Bw; - - // Check angle to see if quaternions are in opposite hemispheres - if( fCosTheta < 0.0f ) - { - // If so, flip one of the quaterions - fCosTheta = -fCosTheta; - Bx = -Bx; By = -By; Bz = -Bz; Bw = -Bw; - } - - // Set factors to do linear interpolation, as a special case where the - // quaternions are close together. - FLOAT fBeta = 1.0f - fAlpha; - - // If the quaternions aren't close, proceed with spherical interpolation - if( 1.0f - fCosTheta > 0.001f ) - { - FLOAT fTheta = acosf( fCosTheta ); - - fBeta = sinf( fTheta*fBeta ) / sinf( fTheta); - fAlpha = sinf( fTheta*fAlpha ) / sinf( fTheta); - } - - // Do the interpolation - Qx = fBeta*Ax + fAlpha*Bx; - Qy = fBeta*Ay + fAlpha*By; - Qz = fBeta*Az + fAlpha*Bz; - Qw = fBeta*Aw + fAlpha*Bw; -} - - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DMath.cpp +// +// Desc: Shortcut macros and functions for using DX objects +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- +#define D3D_OVERLOADS +#define STRICT +#include +#include +#include "d3dmath.h" + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_MatrixMultiply() +// Desc: Does the matrix operation: [Q] = [A] * [B]. Note that the order of +// this operation was changed from the previous version of the DXSDK. +//----------------------------------------------------------------------------- +VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b ) +{ + FLOAT* pA = (FLOAT*)&a; + FLOAT* pB = (FLOAT*)&b; + FLOAT pM[16]; + + ZeroMemory( pM, sizeof(D3DMATRIX) ); + + for( WORD i=0; i<4; i++ ) + for( WORD j=0; j<4; j++ ) + for( WORD k=0; k<4; k++ ) + pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; + + memcpy( &q, pM, sizeof(D3DMATRIX) ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_MatrixInvert() +// Desc: Does the matrix operation: [Q] = inv[A]. Note: this function only +// works for matrices with [0 0 0 1] for the 4th column. +//----------------------------------------------------------------------------- +HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a ) +{ + if( fabs(a._44 - 1.0f) > .001f) + return E_INVALIDARG; + if( fabs(a._14) > .001f || fabs(a._24) > .001f || fabs(a._34) > .001f ) + return E_INVALIDARG; + + FLOAT fDetInv = 1.0f / ( a._11 * ( a._22 * a._33 - a._23 * a._32 ) - + a._12 * ( a._21 * a._33 - a._23 * a._31 ) + + a._13 * ( a._21 * a._32 - a._22 * a._31 ) ); + + q._11 = fDetInv * ( a._22 * a._33 - a._23 * a._32 ); + q._12 = -fDetInv * ( a._12 * a._33 - a._13 * a._32 ); + q._13 = fDetInv * ( a._12 * a._23 - a._13 * a._22 ); + q._14 = 0.0f; + + q._21 = -fDetInv * ( a._21 * a._33 - a._23 * a._31 ); + q._22 = fDetInv * ( a._11 * a._33 - a._13 * a._31 ); + q._23 = -fDetInv * ( a._11 * a._23 - a._13 * a._21 ); + q._24 = 0.0f; + + q._31 = fDetInv * ( a._21 * a._32 - a._22 * a._31 ); + q._32 = -fDetInv * ( a._11 * a._32 - a._12 * a._31 ); + q._33 = fDetInv * ( a._11 * a._22 - a._12 * a._21 ); + q._34 = 0.0f; + + q._41 = -( a._41 * q._11 + a._42 * q._21 + a._43 * q._31 ); + q._42 = -( a._41 * q._12 + a._42 * q._22 + a._43 * q._32 ); + q._43 = -( a._41 * q._13 + a._42 * q._23 + a._43 * q._33 ); + q._44 = 1.0f; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_VectorMatrixMultiply() +// Desc: Multiplies a vector by a matrix +//----------------------------------------------------------------------------- +HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc, + D3DMATRIX& mat) +{ + FLOAT x = vSrc.x*mat._11 + vSrc.y*mat._21 + vSrc.z* mat._31 + mat._41; + FLOAT y = vSrc.x*mat._12 + vSrc.y*mat._22 + vSrc.z* mat._32 + mat._42; + FLOAT z = vSrc.x*mat._13 + vSrc.y*mat._23 + vSrc.z* mat._33 + mat._43; + FLOAT w = vSrc.x*mat._14 + vSrc.y*mat._24 + vSrc.z* mat._34 + mat._44; + + if( fabs( w ) < g_EPSILON ) + return E_INVALIDARG; + + vDest.x = x/w; + vDest.y = y/w; + vDest.z = z/w; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_VertexMatrixMultiply() +// Desc: Multiplies a vertex by a matrix +//----------------------------------------------------------------------------- +HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc, + D3DMATRIX& mat ) +{ + HRESULT hr; + D3DVECTOR* pSrcVec = (D3DVECTOR*)&vSrc.x; + D3DVECTOR* pDestVec = (D3DVECTOR*)&vDest.x; + + if( SUCCEEDED( hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec, + mat ) ) ) + { + pSrcVec = (D3DVECTOR*)&vSrc.nx; + pDestVec = (D3DVECTOR*)&vDest.nx; + hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec, mat ); + } + return hr; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_QuaternionFromRotation() +// Desc: Converts a normalized axis and angle to a unit quaternion. +//----------------------------------------------------------------------------- +VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, + D3DVECTOR& v, FLOAT fTheta ) +{ + x = sinf( fTheta/2.0f ) * v.x; + y = sinf( fTheta/2.0f ) * v.y; + z = sinf( fTheta/2.0f ) * v.z; + w = cosf( fTheta/2.0f ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_RotationFromQuaternion() +// Desc: Converts a normalized axis and angle to a unit quaternion. +//----------------------------------------------------------------------------- +VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta, + FLOAT x, FLOAT y, FLOAT z, FLOAT w ) + +{ + fTheta = acosf(w) * 2.0f; + v.x = x / sinf( fTheta/2.0f ); + v.y = y / sinf( fTheta/2.0f ); + v.z = z / sinf( fTheta/2.0f ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_QuaternionFromAngles() +// Desc: Converts euler angles to a unit quaternion. +//----------------------------------------------------------------------------- +VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, + FLOAT fYaw, FLOAT fPitch, FLOAT fRoll ) + +{ + FLOAT fSinYaw = sinf( fYaw/2.0f ); + FLOAT fSinPitch = sinf( fPitch/2.0f ); + FLOAT fSinRoll = sinf( fRoll/2.0f ); + FLOAT fCosYaw = cosf( fYaw/2.0f ); + FLOAT fCosPitch = cosf( fPitch/2.0f ); + FLOAT fCosRoll = cosf( fRoll/2.0f ); + + x = fSinRoll * fCosPitch * fCosYaw - fCosRoll * fSinPitch * fSinYaw; + y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw; + z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw; + w = fCosRoll * fCosPitch * fCosYaw + fSinRoll * fSinPitch * fSinYaw; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_MatrixFromQuaternion() +// Desc: Converts a unit quaternion into a rotation matrix. +//----------------------------------------------------------------------------- +VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z, + FLOAT w ) +{ + FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z; + FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z; + FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z; + + mat._11 = 1 - 2 * ( yy + zz ); + mat._12 = 2 * ( xy - wz ); + mat._13 = 2 * ( xz + wy ); + + mat._21 = 2 * ( xy + wz ); + mat._22 = 1 - 2 * ( xx + zz ); + mat._23 = 2 * ( yz - wx ); + + mat._31 = 2 * ( xz - wy ); + mat._32 = 2 * ( yz + wx ); + mat._33 = 1 - 2 * ( xx + yy ); + + mat._14 = mat._24 = mat._34 = 0.0f; + mat._41 = mat._42 = mat._43 = 0.0f; + mat._44 = 1.0f; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_QuaternionFromMatrix() +// Desc: Converts a rotation matrix into a unit quaternion. +//----------------------------------------------------------------------------- +VOID D3DMath_QuaternionFromMatrix( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, + D3DMATRIX& mat ) +{ + if( mat._11 + mat._22 + mat._33 > 0.0f ) + { + FLOAT s = sqrtf( mat._11 + mat._22 + mat._33 + mat._44 ); + + x = (mat._23-mat._32) / (2*s); + y = (mat._31-mat._13) / (2*s); + z = (mat._12-mat._21) / (2*s); + w = 0.5f * s; + } + else + { + + + } + FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z; + FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z; + FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z; + + mat._11 = 1 - 2 * ( yy + zz ); + mat._12 = 2 * ( xy - wz ); + mat._13 = 2 * ( xz + wy ); + + mat._21 = 2 * ( xy + wz ); + mat._22 = 1 - 2 * ( xx + zz ); + mat._23 = 2 * ( yz - wx ); + + mat._31 = 2 * ( xz - wy ); + mat._32 = 2 * ( yz + wx ); + mat._33 = 1 - 2 * ( xx + yy ); + + mat._14 = mat._24 = mat._34 = 0.0f; + mat._41 = mat._42 = mat._43 = 0.0f; + mat._44 = 1.0f; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_QuaternionMultiply() +// Desc: Mulitples two quaternions together as in {Q} = {A} * {B}. +//----------------------------------------------------------------------------- +VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, + FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, + FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw ) +{ + FLOAT Dx = Ax*Bw + Ay*Bz - Az*By + Aw*Bx; + FLOAT Dy = -Ax*Bz + Ay*Bw + Az*Bx + Aw*By; + FLOAT Dz = Ax*By - Ay*Bx + Az*Bw + Aw*Bz; + FLOAT Dw = -Ax*Bx - Ay*By - Az*Bz + Aw*Bw; + + Qx = Dx; Qy = Dy; Qz = Dz; Qw = Dw; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DMath_SlerpQuaternions() +// Desc: Compute a quaternion which is the spherical linear interpolation +// between two other quaternions by dvFraction. +//----------------------------------------------------------------------------- +VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, + FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, + FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw, + FLOAT fAlpha ) +{ + // Compute dot product (equal to cosine of the angle between quaternions) + FLOAT fCosTheta = Ax*Bx + Ay*By + Az*Bz + Aw*Bw; + + // Check angle to see if quaternions are in opposite hemispheres + if( fCosTheta < 0.0f ) + { + // If so, flip one of the quaterions + fCosTheta = -fCosTheta; + Bx = -Bx; By = -By; Bz = -Bz; Bw = -Bw; + } + + // Set factors to do linear interpolation, as a special case where the + // quaternions are close together. + FLOAT fBeta = 1.0f - fAlpha; + + // If the quaternions aren't close, proceed with spherical interpolation + if( 1.0f - fCosTheta > 0.001f ) + { + FLOAT fTheta = acosf( fCosTheta ); + + fBeta = sinf( fTheta*fBeta ) / sinf( fTheta); + fAlpha = sinf( fTheta*fAlpha ) / sinf( fTheta); + } + + // Do the interpolation + Qx = fBeta*Ax + fAlpha*Bx; + Qy = fBeta*Ay + fAlpha*By; + Qz = fBeta*Az + fAlpha*Bz; + Qw = fBeta*Aw + fAlpha*Bw; +} + + + + diff --git a/src/old/d3dmath.h b/src/old/d3dmath.h index 5d95290..6e98e18 100644 --- a/src/old/d3dmath.h +++ b/src/old/d3dmath.h @@ -1,107 +1,107 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DMath.h -// -// Desc: Math functions and shortcuts for Direct3D programming. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- - -#pragma once - -#include -#include - - -//----------------------------------------------------------------------------- -// Useful Math constants -//----------------------------------------------------------------------------- -const FLOAT g_PI = 3.14159265358979323846f; // Pi -const FLOAT g_2_PI = 6.28318530717958623200f; // 2 * Pi -const FLOAT g_PI_DIV_2 = 1.57079632679489655800f; // Pi / 2 -const FLOAT g_PI_DIV_4 = 0.78539816339744827900f; // Pi / 4 -const FLOAT g_INV_PI = 0.31830988618379069122f; // 1 / Pi -const FLOAT g_DEGTORAD = 0.01745329251994329547f; // Degrees to Radians -const FLOAT g_RADTODEG = 57.29577951308232286465f; // Radians to Degrees -const FLOAT g_HUGE = 1.0e+38f; // Huge number for FLOAT -const FLOAT g_EPSILON = 1.0e-5f; // Tolerance for FLOATs - - - - -//----------------------------------------------------------------------------- -// Fuzzy compares (within tolerance) -//----------------------------------------------------------------------------- -//>>> func.h IsZero() -inline bool D3DMath_IsZero( FLOAT a, FLOAT fTol = g_EPSILON ) -{ return ( a <= 0.0f ) ? ( a >= -fTol ) : ( a <= fTol ); } - - - - -//----------------------------------------------------------------------------- -// Matrix functions -//----------------------------------------------------------------------------- -//>>> matrix.h MultiplyMatrices() -VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b ); -//>>> matrix.h Matrix::Invert() -HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a ); - - - - -//----------------------------------------------------------------------------- -// Vector functions -//----------------------------------------------------------------------------- - -//>>> matrix.h MatrixVectorMultiply() -HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc, - D3DMATRIX& mat); -// TODO -HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc, - D3DMATRIX& mat ); - - - - -//----------------------------------------------------------------------------- -// Quaternion functions -//----------------------------------------------------------------------------- - -// UNUSED - - -VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, - D3DVECTOR& v, FLOAT fTheta ); -VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta, - FLOAT x, FLOAT y, FLOAT z, FLOAT w ); -VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, - FLOAT fYaw, FLOAT fPitch, FLOAT fRoll ); -VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z, - FLOAT w ); -VOID D3DMath_QuaternionFromMatrix( FLOAT &x, FLOAT &y, FLOAT &z, FLOAT &w, - D3DMATRIX& mat ); -VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, - FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, - FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw ); -VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, - FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, - FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw, - FLOAT fAlpha ); - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DMath.h +// +// Desc: Math functions and shortcuts for Direct3D programming. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include + + +//----------------------------------------------------------------------------- +// Useful Math constants +//----------------------------------------------------------------------------- +const FLOAT g_PI = 3.14159265358979323846f; // Pi +const FLOAT g_2_PI = 6.28318530717958623200f; // 2 * Pi +const FLOAT g_PI_DIV_2 = 1.57079632679489655800f; // Pi / 2 +const FLOAT g_PI_DIV_4 = 0.78539816339744827900f; // Pi / 4 +const FLOAT g_INV_PI = 0.31830988618379069122f; // 1 / Pi +const FLOAT g_DEGTORAD = 0.01745329251994329547f; // Degrees to Radians +const FLOAT g_RADTODEG = 57.29577951308232286465f; // Radians to Degrees +const FLOAT g_HUGE = 1.0e+38f; // Huge number for FLOAT +const FLOAT g_EPSILON = 1.0e-5f; // Tolerance for FLOATs + + + + +//----------------------------------------------------------------------------- +// Fuzzy compares (within tolerance) +//----------------------------------------------------------------------------- +//>>> func.h IsZero() +inline bool D3DMath_IsZero( FLOAT a, FLOAT fTol = g_EPSILON ) +{ return ( a <= 0.0f ) ? ( a >= -fTol ) : ( a <= fTol ); } + + + + +//----------------------------------------------------------------------------- +// Matrix functions +//----------------------------------------------------------------------------- +//>>> matrix.h MultiplyMatrices() +VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b ); +//>>> matrix.h Matrix::Invert() +HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a ); + + + + +//----------------------------------------------------------------------------- +// Vector functions +//----------------------------------------------------------------------------- + +//>>> matrix.h MatrixVectorMultiply() +HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc, + D3DMATRIX& mat); +// TODO +HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc, + D3DMATRIX& mat ); + + + + +//----------------------------------------------------------------------------- +// Quaternion functions +//----------------------------------------------------------------------------- + +// UNUSED + + +VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, + D3DVECTOR& v, FLOAT fTheta ); +VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta, + FLOAT x, FLOAT y, FLOAT z, FLOAT w ); +VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w, + FLOAT fYaw, FLOAT fPitch, FLOAT fRoll ); +VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z, + FLOAT w ); +VOID D3DMath_QuaternionFromMatrix( FLOAT &x, FLOAT &y, FLOAT &z, FLOAT &w, + D3DMATRIX& mat ); +VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, + FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, + FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw ); +VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw, + FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw, + FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw, + FLOAT fAlpha ); + + diff --git a/src/old/d3dres.h b/src/old/d3dres.h index 79ba76e..0259d86 100644 --- a/src/old/d3dres.h +++ b/src/old/d3dres.h @@ -1,55 +1,55 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DRes.h -// -// Desc: Resource definitions required by the CD3DApplication class. -// Any application using the CD3DApplication class must include resources -// with the following identifiers. -// -// Copyright (c) 1999 Microsoft Corporation. All rights reserved. -//----------------------------------------------------------------------------- - -#pragma once - -#define IDI_MAIN_ICON 101 // Application icon -#define IDR_MAIN_ACCEL 113 // Keyboard accelerator -#define IDR_MENU 141 // Application menu -#define IDR_POPUP 142 // Popup menu -#define IDD_ABOUT 143 // About dialog box -#define IDD_CHANGEDEVICE 144 // "Change Device" dialog box -#define IDC_CURSORHAND 149 -#define IDC_CURSORSCROLLL 150 -#define IDC_CURSORSCROLLR 151 -#define IDC_CURSORSCROLLU 152 -#define IDC_CURSORSCROLLD 153 -#define IDC_CURSORTARGET 154 - -#define IDC_DEVICE_COMBO 1000 // Device combobox for "Change Device" dlg -#define IDC_MODE_COMBO 1001 // Mode combobox for "Change Device" dlg -#define IDC_WINDOWED_CHECKBOX 1012 // Checkbox for windowed-mode -#define IDC_STEREO_CHECKBOX 1013 // Checkbox for stereo modes -#define IDC_FULLSCREEN_TEXT 1014 // Group box text label - -#define IDM_ABOUT 40001 // Command to invoke About dlg -#define IDM_CHANGEDEVICE 40002 // Command to invoke "Change Device" dlg -#define IDM_TOGGLEFULLSCREEN 40003 // Command to toggle fullscreen mode -#define IDM_TOGGLESTART 40004 // Command to toggle frame animation -#define IDM_SINGLESTEP 40005 // Command to single step frame animation -#define IDM_EXIT 40006 // Command to exit the application - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DRes.h +// +// Desc: Resource definitions required by the CD3DApplication class. +// Any application using the CD3DApplication class must include resources +// with the following identifiers. +// +// Copyright (c) 1999 Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#pragma once + +#define IDI_MAIN_ICON 101 // Application icon +#define IDR_MAIN_ACCEL 113 // Keyboard accelerator +#define IDR_MENU 141 // Application menu +#define IDR_POPUP 142 // Popup menu +#define IDD_ABOUT 143 // About dialog box +#define IDD_CHANGEDEVICE 144 // "Change Device" dialog box +#define IDC_CURSORHAND 149 +#define IDC_CURSORSCROLLL 150 +#define IDC_CURSORSCROLLR 151 +#define IDC_CURSORSCROLLU 152 +#define IDC_CURSORSCROLLD 153 +#define IDC_CURSORTARGET 154 + +#define IDC_DEVICE_COMBO 1000 // Device combobox for "Change Device" dlg +#define IDC_MODE_COMBO 1001 // Mode combobox for "Change Device" dlg +#define IDC_WINDOWED_CHECKBOX 1012 // Checkbox for windowed-mode +#define IDC_STEREO_CHECKBOX 1013 // Checkbox for stereo modes +#define IDC_FULLSCREEN_TEXT 1014 // Group box text label + +#define IDM_ABOUT 40001 // Command to invoke About dlg +#define IDM_CHANGEDEVICE 40002 // Command to invoke "Change Device" dlg +#define IDM_TOGGLEFULLSCREEN 40003 // Command to toggle fullscreen mode +#define IDM_TOGGLESTART 40004 // Command to toggle frame animation +#define IDM_SINGLESTEP 40005 // Command to single step frame animation +#define IDM_EXIT 40006 // Command to exit the application + + diff --git a/src/old/d3dtextr.cpp b/src/old/d3dtextr.cpp index 39be603..f035e65 100644 --- a/src/old/d3dtextr.cpp +++ b/src/old/d3dtextr.cpp @@ -1,1081 +1,1081 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DTextr.cpp -// -// Desc: Functions to manage textures, including creating (loading from a -// file), restoring lost surfaces, invalidating, and destroying. -// -// Note: the implementation of these fucntions maintain an internal list -// of loaded textures. After creation, individual textures are referenced -// via their ASCII names. -// -// Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- -#include -#include -#include -using std::min; -#include "old/d3dtextr.h" -#include "old/d3dutil.h" -#include "common/language.h" -#include "common/misc.h" - - - - -//----------------------------------------------------------------------------- -// Macros, function prototypes and static variable -//----------------------------------------------------------------------------- -static TCHAR g_strTexturePath[512] = _T(""); // Path for files -static bool g_bDebugMode = false; - - - -void D3DTextr_SetDebugMode(bool bDebug) -{ - g_bDebugMode = bDebug; -} - - - -//----------------------------------------------------------------------------- -// Name: TextureContainer -// Desc: Linked list structure to hold info per texture -//----------------------------------------------------------------------------- -struct TextureContainer -{ - TextureContainer* m_pNext; // Linked list ptr - - TCHAR m_strName[80]; // Name of texture (doubles as image filename) - DWORD m_dwWidth; - DWORD m_dwHeight; - DWORD m_dwStage; // Texture stage (for multitexture devices) - DWORD m_dwBPP; - DWORD m_dwFlags; - bool m_bHasAlpha; - - LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture - HBITMAP m_hbmBitmap; // Bitmap containing texture image - DWORD* m_pRGBAData; - -public: - HRESULT LoadImageData(); - HRESULT LoadBitmapFile( TCHAR* strPathname ); - HRESULT LoadTargaFile( TCHAR* strPathname, TCHAR* strFilename ); - HRESULT Restore( LPDIRECT3DDEVICE7 pd3dDevice ); - HRESULT CopyBitmapToSurface(); - HRESULT CopyRGBADataToSurface(); - - TextureContainer( TCHAR* strName, DWORD dwStage, DWORD dwFlags ); - ~TextureContainer(); -}; - -// Local list of textures -static TextureContainer* g_ptcTextureList = NULL; - - - - -//----------------------------------------------------------------------------- -// Name: CD3DTextureManager -// Desc: Class used to automatically construct and destruct the static -// texture engine class. -//----------------------------------------------------------------------------- -class CD3DTextureManager -{ -public: - CD3DTextureManager() {} - ~CD3DTextureManager() { if( g_ptcTextureList ) delete g_ptcTextureList; } -}; - -// Global instance -CD3DTextureManager g_StaticTextureEngine; - - - - -//----------------------------------------------------------------------------- -// Name: struct TEXTURESEARCHINFO -// Desc: Structure used to search for texture formats -//----------------------------------------------------------------------------- -struct TEXTURESEARCHINFO -{ - DWORD dwDesiredBPP; // Input for texture format search - bool bUseAlpha; - bool bUsePalette; - bool bFoundGoodFormat; - - DDPIXELFORMAT* pddpf; // Output of texture format search -}; - - - - -//----------------------------------------------------------------------------- -// Name: TextureSearchCallback() -// Desc: Enumeration callback routine to find a best-matching texture format. -// The param data is the DDPIXELFORMAT of the best-so-far matching -// texture. Note: the desired BPP is passed in the dwSize field, and the -// default BPP is passed in the dwFlags field. -//----------------------------------------------------------------------------- -static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf, - VOID* param ) -{ - if( NULL==pddpf || NULL==param ) - return DDENUMRET_OK; - - TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param; - - // Skip any funky modes - if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) ) - return DDENUMRET_OK; - - // Check for palettized formats - if( ptsi->bUsePalette ) - { - if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) ) - return DDENUMRET_OK; - - // Accept the first 8-bit palettized format we get - memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) ); - ptsi->bFoundGoodFormat = true; - return DDENUMRET_CANCEL; - } - - // Else, skip any paletized formats (all modes under 16bpp) - if( pddpf->dwRGBBitCount < 16 ) - return DDENUMRET_OK; - - // Skip any FourCC formats - if( pddpf->dwFourCC != 0 ) - return DDENUMRET_OK; - - // Skip any ARGB 4444 formats (which are best used for pre-authored - // content designed speciafically for an ARGB 4444 format). - if( pddpf->dwRGBAlphaBitMask == 0x0000f000 ) - return DDENUMRET_OK; - - // Make sure current alpha format agrees with requested format type - if( (ptsi->bUseAlpha==true) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) ) - return DDENUMRET_OK; - if( (ptsi->bUseAlpha==false) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) ) - return DDENUMRET_OK; - - // Check if we found a good match - if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP ) - { - memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) ); - ptsi->bFoundGoodFormat = true; - return DDENUMRET_CANCEL; - } - - return DDENUMRET_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: FindTexture() -// Desc: Searches the internal list of textures for a texture specified by -// its name. Returns the structure associated with that texture. -//----------------------------------------------------------------------------- -static TextureContainer* FindTexture( TCHAR* strTextureName ) -{ - TextureContainer* ptcTexture = g_ptcTextureList; - - while( ptcTexture ) - { - if( !lstrcmpi( strTextureName, ptcTexture->m_strName ) ) - return ptcTexture; - ptcTexture = ptcTexture->m_pNext; - } - - return NULL; -} - - - - -//----------------------------------------------------------------------------- -// Name: TextureContainer() -// Desc: Constructor for a texture object -//----------------------------------------------------------------------------- -TextureContainer::TextureContainer( TCHAR* strName, DWORD dwStage, - DWORD dwFlags ) -{ - lstrcpy( m_strName, strName ); - m_dwWidth = 0; - m_dwHeight = 0; - m_dwStage = dwStage; - m_dwBPP = 0; - m_dwFlags = dwFlags; - m_bHasAlpha = 0; - - m_pddsSurface = NULL; - m_hbmBitmap = NULL; - m_pRGBAData = NULL; - - // Add the texture to the head of the global texture list - m_pNext = g_ptcTextureList; - g_ptcTextureList = this; - -} - - - - -//----------------------------------------------------------------------------- -// Name: ~TextureContainer() -// Desc: Destructs the contents of the texture container -//----------------------------------------------------------------------------- -TextureContainer::~TextureContainer() -{ - SAFE_RELEASE( m_pddsSurface ); - SAFE_DELETE( m_pRGBAData ); - DeleteObject( m_hbmBitmap ); - - // Remove the texture container from the global list - if( g_ptcTextureList == this ) - g_ptcTextureList = m_pNext; - else - { - for( TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext ) - if( ptc->m_pNext == this ) - ptc->m_pNext = m_pNext; - } -} - - - - -//----------------------------------------------------------------------------- -// Name: LoadImageData() -// Desc: Loads the texture map's image data -//----------------------------------------------------------------------------- -HRESULT TextureContainer::LoadImageData() -{ - TCHAR* strExtension; - TCHAR strMetaname[256]; - TCHAR strFilename[256]; - - if ( g_bDebugMode ) - { - if ( _tcsrchr( m_strName, _T('\\') ) == 0 ) - { - lstrcpy( strMetaname, "" ); - lstrcpy( strFilename, g_strTexturePath ); - lstrcat( strFilename, m_strName ); - } - else - { - lstrcpy( strMetaname, "" ); - lstrcpy( strFilename, m_strName ); - } - } - else - { - if ( _tcsrchr( m_strName, _T('\\') ) == 0 ) - { -#if _SCHOOL - lstrcpy( strMetaname, "ceebot1.dat" ); -#else - lstrcpy( strMetaname, "colobot1.dat" ); -#endif - lstrcpy( strFilename, m_strName ); - } - else - { - lstrcpy( strMetaname, "" ); - lstrcpy( strFilename, m_strName ); - } - } - - if ( !g_metafile.IsExist(strMetaname, strFilename) ) - { - return DDERR_NOTFOUND; - } - - // Get the filename extension - if ( NULL == ( strExtension = _tcsrchr( m_strName, _T('.') ) ) ) - { - return DDERR_UNSUPPORTED; - } - - // Load bitmap files - if ( strMetaname[0] == 0 && !lstrcmpi( strExtension, _T(".bmp") ) ) - { - return LoadBitmapFile( strFilename ); - } - - // Load targa files - if ( !lstrcmpi( strExtension, _T(".tga") ) ) - { - return LoadTargaFile( strMetaname, strFilename ); - } - - // Can add code here to check for other file formats before failing - return DDERR_UNSUPPORTED; -} - - - - -//----------------------------------------------------------------------------- -// Name: LoadBitmapFile() -// Desc: Loads data from a .bmp file, and stores it in a bitmap structure. -//----------------------------------------------------------------------------- -HRESULT TextureContainer::LoadBitmapFile( TCHAR* strPathname ) -{ - // Try to load the bitmap as a file - m_hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname, IMAGE_BITMAP, 0, 0, - LR_LOADFROMFILE|LR_CREATEDIBSECTION ); - if( m_hbmBitmap ) - return S_OK; - - return DDERR_NOTFOUND; -} - - - - -//----------------------------------------------------------------------------- -// Name: LoadTargaFile() -// Desc: Loads RGBA data from a .tga file, and stores it in allocated memory -// for the specified texture container -//----------------------------------------------------------------------------- -HRESULT TextureContainer::LoadTargaFile( TCHAR* strMetaname, TCHAR* strFilename ) -{ - if( g_metafile.Open(strMetaname, strFilename) != 0 ) - return E_FAIL; - - struct TargaHeader - { - BYTE IDLength; - BYTE ColormapType; - BYTE ImageType; - BYTE ColormapSpecification[5]; - WORD XOrigin; - WORD YOrigin; - WORD ImageWidth; - WORD ImageHeight; - BYTE PixelDepth; - BYTE ImageDescriptor; - } tga; - - g_metafile.Read(&tga, sizeof(TargaHeader)); - - // Only true color, non-mapped images are supported - if( ( 0 != tga.ColormapType ) || - ( tga.ImageType != 10 && tga.ImageType != 2 ) ) - { - g_metafile.Close(); - return E_FAIL; - } - - // Skip the ID field. The first byte of the header is the length of this field - if( tga.IDLength ) - { - g_metafile.Seek(tga.IDLength); - } - - m_dwWidth = tga.ImageWidth; - m_dwHeight = tga.ImageHeight; - m_dwBPP = tga.PixelDepth; - m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight]; - - if( m_pRGBAData == NULL ) - { - g_metafile.Close(); - return E_FAIL; - } - - for( DWORD y=0; yGetCaps( &ddDesc) ) ) - return E_FAIL; - - // Setup the new surface desc - DDSURFACEDESC2 ddsd; - D3DUtil_InitSurfaceDesc( ddsd ); - ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH| - DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE; - ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; - ddsd.dwTextureStage = m_dwStage; - ddsd.dwWidth = m_dwWidth; - ddsd.dwHeight = m_dwHeight; - - // Turn on texture management for hardware devices - if( ddDesc.deviceGUID == IID_IDirect3DHALDevice ) - ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; - else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice ) - ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; - else - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - - // Adjust width and height to be powers of 2, if the device requires it - if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ) - { - for( ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1 ); - for( ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 ); - } - - // Limit max texture sizes, if the driver can't handle large textures - DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth; - DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight; - ddsd.dwWidth = min( ddsd.dwWidth, ( dwMaxWidth ? dwMaxWidth : 256 ) ); - ddsd.dwHeight = min( ddsd.dwHeight, ( dwMaxHeight ? dwMaxHeight : 256 ) ); - - // Make the texture square, if the driver requires it - if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY ) - { - if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth; - else ddsd.dwWidth = ddsd.dwHeight; - } - - // Setup the structure to be used for texture enumration. - TEXTURESEARCHINFO tsi; - tsi.bFoundGoodFormat = false; - tsi.pddpf = &ddsd.ddpfPixelFormat; - tsi.dwDesiredBPP = m_dwBPP; - tsi.bUsePalette = ( m_dwBPP <= 8 ); - tsi.bUseAlpha = m_bHasAlpha; - if( m_dwFlags & D3DTEXTR_16BITSPERPIXEL ) - tsi.dwDesiredBPP = 16; - else if( m_dwFlags & D3DTEXTR_32BITSPERPIXEL ) - tsi.dwDesiredBPP = 32; - - if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) ) - { - if( tsi.bUsePalette ) - { - if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE ) - { - tsi.bUseAlpha = true; - tsi.bUsePalette = true; - } - else - { - tsi.bUseAlpha = true; - tsi.bUsePalette = false; - } - } - } - - // Enumerate the texture formats, and find the closest device-supported - // texture pixel format - pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi ); - - // If we couldn't find a format, let's try a default format - if( false == tsi.bFoundGoodFormat ) - { - tsi.bUsePalette = false; - tsi.dwDesiredBPP = 16; - pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi ); - - // If we still fail, we cannot create this texture - if( false == tsi.bFoundGoodFormat ) - return E_FAIL; - } - - // Get the DirectDraw interface for creating surfaces - LPDIRECTDRAW7 pDD; - LPDIRECTDRAWSURFACE7 pddsRender; - pd3dDevice->GetRenderTarget( &pddsRender ); - pddsRender->GetDDInterface( (VOID**)&pDD ); - pddsRender->Release(); - - // Create a new surface for the texture - HRESULT hr = pDD->CreateSurface( &ddsd, &m_pddsSurface, NULL ); - - // Done with DDraw - pDD->Release(); - - if( FAILED(hr) ) - return hr; - - // For bitmap-based textures, copy the bitmap image. - if( m_hbmBitmap ) - return CopyBitmapToSurface(); - - if( m_pRGBAData ) - return CopyRGBADataToSurface(); - - // At this point, code can be added to handle other file formats (such as - // .dds files, .jpg files, etc.). - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: CopyBitmapToSurface() -// Desc: Copies the image of a bitmap into a surface -//----------------------------------------------------------------------------- -HRESULT TextureContainer::CopyBitmapToSurface() -{ - // Get a DDraw object to create a temporary surface - LPDIRECTDRAW7 pDD; - m_pddsSurface->GetDDInterface( (VOID**)&pDD ); - - // Get the bitmap structure (to extract width, height, and bpp) - BITMAP bm; - GetObject( m_hbmBitmap, sizeof(BITMAP), &bm ); - - // Setup the new surface desc - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - m_pddsSurface->GetSurfaceDesc( &ddsd ); - ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| - DDSD_TEXTURESTAGE; - ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; - ddsd.ddsCaps.dwCaps2 = 0L; - ddsd.dwWidth = bm.bmWidth; - ddsd.dwHeight = bm.bmHeight; - - // Create a new surface for the texture - LPDIRECTDRAWSURFACE7 pddsTempSurface; - HRESULT hr; - if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) ) - { - pDD->Release(); - return hr; - } - - // Get a DC for the bitmap - HDC hdcBitmap = CreateCompatibleDC( NULL ); - if( NULL == hdcBitmap ) - { - pddsTempSurface->Release(); - pDD->Release(); - return hr; - } - SelectObject( hdcBitmap, m_hbmBitmap ); - - // Handle palettized textures. Need to attach a palette - if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) - { - LPDIRECTDRAWPALETTE pPalette; - DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256; - DWORD pe[256]; - WORD wNumColors = GetDIBColorTable( hdcBitmap, 0, 256, (RGBQUAD*)pe ); - - // Create the color table - for( WORD i=0; iCreatePalette( dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL ); - pddsTempSurface->SetPalette( pPalette ); - m_pddsSurface->SetPalette( pPalette ); - SAFE_RELEASE( pPalette ); - } - - // Copy the bitmap image to the surface. - HDC hdcSurface; - if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) ) - { - BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, - SRCCOPY ); - pddsTempSurface->ReleaseDC( hdcSurface ); - } - DeleteDC( hdcBitmap ); - - // Copy the temp surface to the real texture surface - m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL ); - - // Done with the temp surface - pddsTempSurface->Release(); - - // For textures with real alpha (not palettized), set transparent bits - if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask ) - { - if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) ) - { - // Lock the texture surface - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) == - DDERR_WASSTILLDRAWING ); - - DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; - DWORD dwRGBMask = ( ddsd.ddpfPixelFormat.dwRBitMask | - ddsd.ddpfPixelFormat.dwGBitMask | - ddsd.ddpfPixelFormat.dwBBitMask ); - DWORD dwColorkey = 0x00000000; // Colorkey on black - if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE ) - dwColorkey = dwRGBMask; // Colorkey on white - - // Add an opaque alpha value to each non-colorkeyed pixel - for( DWORD y=0; yUnlock( NULL ); - } - } - - pDD->Release(); - - return S_OK;; -} - - - - -//----------------------------------------------------------------------------- -// Name: CopyRGBADataToSurface() -// Desc: Invalidates the current texture objects and rebuilds new ones -// using the new device. -//----------------------------------------------------------------------------- -HRESULT TextureContainer::CopyRGBADataToSurface() -{ - // Get a DDraw object to create a temporary surface - LPDIRECTDRAW7 pDD; - m_pddsSurface->GetDDInterface( (VOID**)&pDD ); - - // Setup the new surface desc - DDSURFACEDESC2 ddsd; - ddsd.dwSize = sizeof(ddsd); - m_pddsSurface->GetSurfaceDesc( &ddsd ); - ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| - DDSD_TEXTURESTAGE; - ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; - ddsd.ddsCaps.dwCaps2 = 0L; - ddsd.dwWidth = m_dwWidth; - ddsd.dwHeight = m_dwHeight; - - // Create a new surface for the texture - LPDIRECTDRAWSURFACE7 pddsTempSurface; - HRESULT hr; - if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) ) - { - pDD->Release(); - return NULL; - } - - while( pddsTempSurface->Lock( NULL, &ddsd, 0, 0 ) == DDERR_WASSTILLDRAWING ); - DWORD lPitch = ddsd.lPitch; - BYTE* pBytes = (BYTE*)ddsd.lpSurface; - - DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask; - DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask; - DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask; - DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; - - DWORD dwRShiftL = 8, dwRShiftR = 0; - DWORD dwGShiftL = 8, dwGShiftR = 0; - DWORD dwBShiftL = 8, dwBShiftR = 0; - DWORD dwAShiftL = 8, dwAShiftR = 0; - - DWORD dwMask; - for( dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwRShiftR++; - for( ; dwMask; dwMask>>=1 ) dwRShiftL--; - - for( dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwGShiftR++; - for( ; dwMask; dwMask>>=1 ) dwGShiftL--; - - for( dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwBShiftR++; - for( ; dwMask; dwMask>>=1 ) dwBShiftL--; - - for( dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwAShiftR++; - for( ; dwMask; dwMask>>=1 ) dwAShiftL--; - - for( DWORD y=0; y>24)&0x000000ff); - BYTE g = (BYTE)((dwPixel>>16)&0x000000ff); - BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff); - BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff); - - DWORD dr = ((r>>(dwRShiftL))<>(dwGShiftL))<>(dwBShiftL))<>(dwAShiftL))<Unlock(0); - - // Copy the temp surface to the real texture surface - m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL ); - - // Done with the temp objects - pddsTempSurface->Release(); - pDD->Release(); - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_SetTexturePath() -// Desc: Enumeration callback routine to find a best-matching texture format. -//----------------------------------------------------------------------------- -VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath ) -{ - if( NULL == strTexturePath ) - strTexturePath = _T(""); - lstrcpy( g_strTexturePath, strTexturePath ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_CreateTextureFromFile() -// Desc: Is passed a filename and creates a local Bitmap from that file. -// The texture can not be used until it is restored, however. -//----------------------------------------------------------------------------- -HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage, - DWORD dwFlags ) -{ - // Check parameters - if( NULL == strName ) - return E_INVALIDARG; - - // Check first to see if the texture is already loaded - if( NULL != FindTexture( strName ) ) - return S_OK; - - // Allocate and add the texture to the linked list of textures; - TextureContainer* ptcTexture = new TextureContainer( strName, dwStage, - dwFlags ); - if( NULL == ptcTexture ) - return E_OUTOFMEMORY; - - // Create a bitmap and load the texture file into it, - if( FAILED( ptcTexture->LoadImageData() ) ) - { - delete ptcTexture; - return E_FAIL; - } - - // Save the image's dimensions - if( ptcTexture->m_hbmBitmap ) - { - BITMAP bm; - GetObject( ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm ); - ptcTexture->m_dwWidth = (DWORD)bm.bmWidth; - ptcTexture->m_dwHeight = (DWORD)bm.bmHeight; - ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_CreateEmptyTexture() -// Desc: Creates an empty texture. -//----------------------------------------------------------------------------- -HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth, - DWORD dwHeight, DWORD dwStage, - DWORD dwFlags ) -{ - // Check parameters - if( NULL == strName ) - return E_INVALIDARG; - - // Check first to see if the texture is already loaded - if( NULL != FindTexture( strName ) ) - return E_FAIL; - - // Allocate and add the texture to the linked list of textures; - TextureContainer* ptcTexture = new TextureContainer( strName, dwStage, - dwFlags ); - if( NULL == ptcTexture ) - return E_OUTOFMEMORY; - - // Save dimensions - ptcTexture->m_dwWidth = dwWidth; - ptcTexture->m_dwHeight = dwHeight; - ptcTexture->m_dwBPP = 16; - if( ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL ) - ptcTexture->m_dwBPP = 32; - - // Save alpha usage flag - if( dwFlags & D3DTEXTR_CREATEWITHALPHA ) - ptcTexture->m_bHasAlpha = true; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_Restore() -// Desc: Invalidates the current texture objects and rebuilds new ones -// using the new device. -//----------------------------------------------------------------------------- -HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice ) -{ - TextureContainer* ptcTexture = FindTexture( strName ); - if( NULL == ptcTexture ) - return DDERR_NOTFOUND; - - // Restore the texture (this recreates the new surface for this device). - return ptcTexture->Restore( pd3dDevice ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_RestoreAllTextures() -// Desc: This function is called when a mode is changed. It updates all -// texture objects to be valid with the new device. -//----------------------------------------------------------------------------- -HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice ) -{ - TextureContainer* ptcTexture = g_ptcTextureList; - - while( ptcTexture ) - { - D3DTextr_Restore( ptcTexture->m_strName, pd3dDevice ); - ptcTexture = ptcTexture->m_pNext; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_Invalidate() -// Desc: Used to bump a texture out of (video) memory, this function -// actually destroys the d3dtexture and ddsurface of the texture -//----------------------------------------------------------------------------- -HRESULT D3DTextr_Invalidate( TCHAR* strName ) -{ - TextureContainer* ptcTexture = FindTexture( strName ); - if( NULL == ptcTexture ) - return DDERR_NOTFOUND; - - SAFE_RELEASE( ptcTexture->m_pddsSurface ); - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_InvalidateAllTextures() -// Desc: This function is called when a mode is changed. It invalidates -// all texture objects so their device can be safely released. -//----------------------------------------------------------------------------- -HRESULT D3DTextr_InvalidateAllTextures() -{ - TextureContainer* ptcTexture = g_ptcTextureList; - - while( ptcTexture ) - { - SAFE_RELEASE( ptcTexture->m_pddsSurface ); - ptcTexture = ptcTexture->m_pNext; - } - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_DestroyTexture() -// Desc: Frees the resources for the specified texture container -//----------------------------------------------------------------------------- -HRESULT D3DTextr_DestroyTexture( TCHAR* strName ) -{ - TextureContainer* ptcTexture = FindTexture( strName ); - - SAFE_DELETE( ptcTexture ); - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DTextr_GetSurface() -// Desc: Returns a pointer to a d3dSurface from the name of the texture -//----------------------------------------------------------------------------- -LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName ) -{ - TextureContainer* ptcTexture = FindTexture( strName ); - - return ptcTexture ? ptcTexture->m_pddsSurface : NULL; -} - - - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DTextr.cpp +// +// Desc: Functions to manage textures, including creating (loading from a +// file), restoring lost surfaces, invalidating, and destroying. +// +// Note: the implementation of these fucntions maintain an internal list +// of loaded textures. After creation, individual textures are referenced +// via their ASCII names. +// +// Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- +#include +#include +#include +using std::min; +#include "old/d3dtextr.h" +#include "old/d3dutil.h" +#include "common/language.h" +#include "common/misc.h" + + + + +//----------------------------------------------------------------------------- +// Macros, function prototypes and static variable +//----------------------------------------------------------------------------- +static TCHAR g_strTexturePath[512] = _T(""); // Path for files +static bool g_bDebugMode = false; + + + +void D3DTextr_SetDebugMode(bool bDebug) +{ + g_bDebugMode = bDebug; +} + + + +//----------------------------------------------------------------------------- +// Name: TextureContainer +// Desc: Linked list structure to hold info per texture +//----------------------------------------------------------------------------- +struct TextureContainer +{ + TextureContainer* m_pNext; // Linked list ptr + + TCHAR m_strName[80]; // Name of texture (doubles as image filename) + DWORD m_dwWidth; + DWORD m_dwHeight; + DWORD m_dwStage; // Texture stage (for multitexture devices) + DWORD m_dwBPP; + DWORD m_dwFlags; + bool m_bHasAlpha; + + LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture + HBITMAP m_hbmBitmap; // Bitmap containing texture image + DWORD* m_pRGBAData; + +public: + HRESULT LoadImageData(); + HRESULT LoadBitmapFile( TCHAR* strPathname ); + HRESULT LoadTargaFile( TCHAR* strPathname, TCHAR* strFilename ); + HRESULT Restore( LPDIRECT3DDEVICE7 pd3dDevice ); + HRESULT CopyBitmapToSurface(); + HRESULT CopyRGBADataToSurface(); + + TextureContainer( TCHAR* strName, DWORD dwStage, DWORD dwFlags ); + ~TextureContainer(); +}; + +// Local list of textures +static TextureContainer* g_ptcTextureList = NULL; + + + + +//----------------------------------------------------------------------------- +// Name: CD3DTextureManager +// Desc: Class used to automatically construct and destruct the static +// texture engine class. +//----------------------------------------------------------------------------- +class CD3DTextureManager +{ +public: + CD3DTextureManager() {} + ~CD3DTextureManager() { if( g_ptcTextureList ) delete g_ptcTextureList; } +}; + +// Global instance +CD3DTextureManager g_StaticTextureEngine; + + + + +//----------------------------------------------------------------------------- +// Name: struct TEXTURESEARCHINFO +// Desc: Structure used to search for texture formats +//----------------------------------------------------------------------------- +struct TEXTURESEARCHINFO +{ + DWORD dwDesiredBPP; // Input for texture format search + bool bUseAlpha; + bool bUsePalette; + bool bFoundGoodFormat; + + DDPIXELFORMAT* pddpf; // Output of texture format search +}; + + + + +//----------------------------------------------------------------------------- +// Name: TextureSearchCallback() +// Desc: Enumeration callback routine to find a best-matching texture format. +// The param data is the DDPIXELFORMAT of the best-so-far matching +// texture. Note: the desired BPP is passed in the dwSize field, and the +// default BPP is passed in the dwFlags field. +//----------------------------------------------------------------------------- +static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf, + VOID* param ) +{ + if( NULL==pddpf || NULL==param ) + return DDENUMRET_OK; + + TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param; + + // Skip any funky modes + if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) ) + return DDENUMRET_OK; + + // Check for palettized formats + if( ptsi->bUsePalette ) + { + if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) ) + return DDENUMRET_OK; + + // Accept the first 8-bit palettized format we get + memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) ); + ptsi->bFoundGoodFormat = true; + return DDENUMRET_CANCEL; + } + + // Else, skip any paletized formats (all modes under 16bpp) + if( pddpf->dwRGBBitCount < 16 ) + return DDENUMRET_OK; + + // Skip any FourCC formats + if( pddpf->dwFourCC != 0 ) + return DDENUMRET_OK; + + // Skip any ARGB 4444 formats (which are best used for pre-authored + // content designed speciafically for an ARGB 4444 format). + if( pddpf->dwRGBAlphaBitMask == 0x0000f000 ) + return DDENUMRET_OK; + + // Make sure current alpha format agrees with requested format type + if( (ptsi->bUseAlpha==true) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) ) + return DDENUMRET_OK; + if( (ptsi->bUseAlpha==false) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) ) + return DDENUMRET_OK; + + // Check if we found a good match + if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP ) + { + memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) ); + ptsi->bFoundGoodFormat = true; + return DDENUMRET_CANCEL; + } + + return DDENUMRET_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: FindTexture() +// Desc: Searches the internal list of textures for a texture specified by +// its name. Returns the structure associated with that texture. +//----------------------------------------------------------------------------- +static TextureContainer* FindTexture( TCHAR* strTextureName ) +{ + TextureContainer* ptcTexture = g_ptcTextureList; + + while( ptcTexture ) + { + if( !lstrcmpi( strTextureName, ptcTexture->m_strName ) ) + return ptcTexture; + ptcTexture = ptcTexture->m_pNext; + } + + return NULL; +} + + + + +//----------------------------------------------------------------------------- +// Name: TextureContainer() +// Desc: Constructor for a texture object +//----------------------------------------------------------------------------- +TextureContainer::TextureContainer( TCHAR* strName, DWORD dwStage, + DWORD dwFlags ) +{ + lstrcpy( m_strName, strName ); + m_dwWidth = 0; + m_dwHeight = 0; + m_dwStage = dwStage; + m_dwBPP = 0; + m_dwFlags = dwFlags; + m_bHasAlpha = 0; + + m_pddsSurface = NULL; + m_hbmBitmap = NULL; + m_pRGBAData = NULL; + + // Add the texture to the head of the global texture list + m_pNext = g_ptcTextureList; + g_ptcTextureList = this; + +} + + + + +//----------------------------------------------------------------------------- +// Name: ~TextureContainer() +// Desc: Destructs the contents of the texture container +//----------------------------------------------------------------------------- +TextureContainer::~TextureContainer() +{ + SAFE_RELEASE( m_pddsSurface ); + SAFE_DELETE( m_pRGBAData ); + DeleteObject( m_hbmBitmap ); + + // Remove the texture container from the global list + if( g_ptcTextureList == this ) + g_ptcTextureList = m_pNext; + else + { + for( TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext ) + if( ptc->m_pNext == this ) + ptc->m_pNext = m_pNext; + } +} + + + + +//----------------------------------------------------------------------------- +// Name: LoadImageData() +// Desc: Loads the texture map's image data +//----------------------------------------------------------------------------- +HRESULT TextureContainer::LoadImageData() +{ + TCHAR* strExtension; + TCHAR strMetaname[256]; + TCHAR strFilename[256]; + + if ( g_bDebugMode ) + { + if ( _tcsrchr( m_strName, _T('\\') ) == 0 ) + { + lstrcpy( strMetaname, "" ); + lstrcpy( strFilename, g_strTexturePath ); + lstrcat( strFilename, m_strName ); + } + else + { + lstrcpy( strMetaname, "" ); + lstrcpy( strFilename, m_strName ); + } + } + else + { + if ( _tcsrchr( m_strName, _T('\\') ) == 0 ) + { +#if _SCHOOL + lstrcpy( strMetaname, "ceebot1.dat" ); +#else + lstrcpy( strMetaname, "colobot1.dat" ); +#endif + lstrcpy( strFilename, m_strName ); + } + else + { + lstrcpy( strMetaname, "" ); + lstrcpy( strFilename, m_strName ); + } + } + + if ( !g_metafile.IsExist(strMetaname, strFilename) ) + { + return DDERR_NOTFOUND; + } + + // Get the filename extension + if ( NULL == ( strExtension = _tcsrchr( m_strName, _T('.') ) ) ) + { + return DDERR_UNSUPPORTED; + } + + // Load bitmap files + if ( strMetaname[0] == 0 && !lstrcmpi( strExtension, _T(".bmp") ) ) + { + return LoadBitmapFile( strFilename ); + } + + // Load targa files + if ( !lstrcmpi( strExtension, _T(".tga") ) ) + { + return LoadTargaFile( strMetaname, strFilename ); + } + + // Can add code here to check for other file formats before failing + return DDERR_UNSUPPORTED; +} + + + + +//----------------------------------------------------------------------------- +// Name: LoadBitmapFile() +// Desc: Loads data from a .bmp file, and stores it in a bitmap structure. +//----------------------------------------------------------------------------- +HRESULT TextureContainer::LoadBitmapFile( TCHAR* strPathname ) +{ + // Try to load the bitmap as a file + m_hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname, IMAGE_BITMAP, 0, 0, + LR_LOADFROMFILE|LR_CREATEDIBSECTION ); + if( m_hbmBitmap ) + return S_OK; + + return DDERR_NOTFOUND; +} + + + + +//----------------------------------------------------------------------------- +// Name: LoadTargaFile() +// Desc: Loads RGBA data from a .tga file, and stores it in allocated memory +// for the specified texture container +//----------------------------------------------------------------------------- +HRESULT TextureContainer::LoadTargaFile( TCHAR* strMetaname, TCHAR* strFilename ) +{ + if( g_metafile.Open(strMetaname, strFilename) != 0 ) + return E_FAIL; + + struct TargaHeader + { + BYTE IDLength; + BYTE ColormapType; + BYTE ImageType; + BYTE ColormapSpecification[5]; + WORD XOrigin; + WORD YOrigin; + WORD ImageWidth; + WORD ImageHeight; + BYTE PixelDepth; + BYTE ImageDescriptor; + } tga; + + g_metafile.Read(&tga, sizeof(TargaHeader)); + + // Only true color, non-mapped images are supported + if( ( 0 != tga.ColormapType ) || + ( tga.ImageType != 10 && tga.ImageType != 2 ) ) + { + g_metafile.Close(); + return E_FAIL; + } + + // Skip the ID field. The first byte of the header is the length of this field + if( tga.IDLength ) + { + g_metafile.Seek(tga.IDLength); + } + + m_dwWidth = tga.ImageWidth; + m_dwHeight = tga.ImageHeight; + m_dwBPP = tga.PixelDepth; + m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight]; + + if( m_pRGBAData == NULL ) + { + g_metafile.Close(); + return E_FAIL; + } + + for( DWORD y=0; yGetCaps( &ddDesc) ) ) + return E_FAIL; + + // Setup the new surface desc + DDSURFACEDESC2 ddsd; + D3DUtil_InitSurfaceDesc( ddsd ); + ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH| + DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE; + ddsd.dwTextureStage = m_dwStage; + ddsd.dwWidth = m_dwWidth; + ddsd.dwHeight = m_dwHeight; + + // Turn on texture management for hardware devices + if( ddDesc.deviceGUID == IID_IDirect3DHALDevice ) + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; + else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice ) + ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE; + else + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + // Adjust width and height to be powers of 2, if the device requires it + if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ) + { + for( ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1 ); + for( ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 ); + } + + // Limit max texture sizes, if the driver can't handle large textures + DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth; + DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight; + ddsd.dwWidth = min( ddsd.dwWidth, ( dwMaxWidth ? dwMaxWidth : 256 ) ); + ddsd.dwHeight = min( ddsd.dwHeight, ( dwMaxHeight ? dwMaxHeight : 256 ) ); + + // Make the texture square, if the driver requires it + if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY ) + { + if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth; + else ddsd.dwWidth = ddsd.dwHeight; + } + + // Setup the structure to be used for texture enumration. + TEXTURESEARCHINFO tsi; + tsi.bFoundGoodFormat = false; + tsi.pddpf = &ddsd.ddpfPixelFormat; + tsi.dwDesiredBPP = m_dwBPP; + tsi.bUsePalette = ( m_dwBPP <= 8 ); + tsi.bUseAlpha = m_bHasAlpha; + if( m_dwFlags & D3DTEXTR_16BITSPERPIXEL ) + tsi.dwDesiredBPP = 16; + else if( m_dwFlags & D3DTEXTR_32BITSPERPIXEL ) + tsi.dwDesiredBPP = 32; + + if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) ) + { + if( tsi.bUsePalette ) + { + if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE ) + { + tsi.bUseAlpha = true; + tsi.bUsePalette = true; + } + else + { + tsi.bUseAlpha = true; + tsi.bUsePalette = false; + } + } + } + + // Enumerate the texture formats, and find the closest device-supported + // texture pixel format + pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi ); + + // If we couldn't find a format, let's try a default format + if( false == tsi.bFoundGoodFormat ) + { + tsi.bUsePalette = false; + tsi.dwDesiredBPP = 16; + pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi ); + + // If we still fail, we cannot create this texture + if( false == tsi.bFoundGoodFormat ) + return E_FAIL; + } + + // Get the DirectDraw interface for creating surfaces + LPDIRECTDRAW7 pDD; + LPDIRECTDRAWSURFACE7 pddsRender; + pd3dDevice->GetRenderTarget( &pddsRender ); + pddsRender->GetDDInterface( (VOID**)&pDD ); + pddsRender->Release(); + + // Create a new surface for the texture + HRESULT hr = pDD->CreateSurface( &ddsd, &m_pddsSurface, NULL ); + + // Done with DDraw + pDD->Release(); + + if( FAILED(hr) ) + return hr; + + // For bitmap-based textures, copy the bitmap image. + if( m_hbmBitmap ) + return CopyBitmapToSurface(); + + if( m_pRGBAData ) + return CopyRGBADataToSurface(); + + // At this point, code can be added to handle other file formats (such as + // .dds files, .jpg files, etc.). + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: CopyBitmapToSurface() +// Desc: Copies the image of a bitmap into a surface +//----------------------------------------------------------------------------- +HRESULT TextureContainer::CopyBitmapToSurface() +{ + // Get a DDraw object to create a temporary surface + LPDIRECTDRAW7 pDD; + m_pddsSurface->GetDDInterface( (VOID**)&pDD ); + + // Get the bitmap structure (to extract width, height, and bpp) + BITMAP bm; + GetObject( m_hbmBitmap, sizeof(BITMAP), &bm ); + + // Setup the new surface desc + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + m_pddsSurface->GetSurfaceDesc( &ddsd ); + ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| + DDSD_TEXTURESTAGE; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; + ddsd.ddsCaps.dwCaps2 = 0L; + ddsd.dwWidth = bm.bmWidth; + ddsd.dwHeight = bm.bmHeight; + + // Create a new surface for the texture + LPDIRECTDRAWSURFACE7 pddsTempSurface; + HRESULT hr; + if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) ) + { + pDD->Release(); + return hr; + } + + // Get a DC for the bitmap + HDC hdcBitmap = CreateCompatibleDC( NULL ); + if( NULL == hdcBitmap ) + { + pddsTempSurface->Release(); + pDD->Release(); + return hr; + } + SelectObject( hdcBitmap, m_hbmBitmap ); + + // Handle palettized textures. Need to attach a palette + if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) + { + LPDIRECTDRAWPALETTE pPalette; + DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256; + DWORD pe[256]; + WORD wNumColors = GetDIBColorTable( hdcBitmap, 0, 256, (RGBQUAD*)pe ); + + // Create the color table + for( WORD i=0; iCreatePalette( dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL ); + pddsTempSurface->SetPalette( pPalette ); + m_pddsSurface->SetPalette( pPalette ); + SAFE_RELEASE( pPalette ); + } + + // Copy the bitmap image to the surface. + HDC hdcSurface; + if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) ) + { + BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0, + SRCCOPY ); + pddsTempSurface->ReleaseDC( hdcSurface ); + } + DeleteDC( hdcBitmap ); + + // Copy the temp surface to the real texture surface + m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL ); + + // Done with the temp surface + pddsTempSurface->Release(); + + // For textures with real alpha (not palettized), set transparent bits + if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask ) + { + if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) ) + { + // Lock the texture surface + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) == + DDERR_WASSTILLDRAWING ); + + DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + DWORD dwRGBMask = ( ddsd.ddpfPixelFormat.dwRBitMask | + ddsd.ddpfPixelFormat.dwGBitMask | + ddsd.ddpfPixelFormat.dwBBitMask ); + DWORD dwColorkey = 0x00000000; // Colorkey on black + if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE ) + dwColorkey = dwRGBMask; // Colorkey on white + + // Add an opaque alpha value to each non-colorkeyed pixel + for( DWORD y=0; yUnlock( NULL ); + } + } + + pDD->Release(); + + return S_OK;; +} + + + + +//----------------------------------------------------------------------------- +// Name: CopyRGBADataToSurface() +// Desc: Invalidates the current texture objects and rebuilds new ones +// using the new device. +//----------------------------------------------------------------------------- +HRESULT TextureContainer::CopyRGBADataToSurface() +{ + // Get a DDraw object to create a temporary surface + LPDIRECTDRAW7 pDD; + m_pddsSurface->GetDDInterface( (VOID**)&pDD ); + + // Setup the new surface desc + DDSURFACEDESC2 ddsd; + ddsd.dwSize = sizeof(ddsd); + m_pddsSurface->GetSurfaceDesc( &ddsd ); + ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT| + DDSD_TEXTURESTAGE; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY; + ddsd.ddsCaps.dwCaps2 = 0L; + ddsd.dwWidth = m_dwWidth; + ddsd.dwHeight = m_dwHeight; + + // Create a new surface for the texture + LPDIRECTDRAWSURFACE7 pddsTempSurface; + HRESULT hr; + if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) ) + { + pDD->Release(); + return NULL; + } + + while( pddsTempSurface->Lock( NULL, &ddsd, 0, 0 ) == DDERR_WASSTILLDRAWING ); + DWORD lPitch = ddsd.lPitch; + BYTE* pBytes = (BYTE*)ddsd.lpSurface; + + DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask; + DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask; + DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask; + DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask; + + DWORD dwRShiftL = 8, dwRShiftR = 0; + DWORD dwGShiftL = 8, dwGShiftR = 0; + DWORD dwBShiftL = 8, dwBShiftR = 0; + DWORD dwAShiftL = 8, dwAShiftR = 0; + + DWORD dwMask; + for( dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwRShiftR++; + for( ; dwMask; dwMask>>=1 ) dwRShiftL--; + + for( dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwGShiftR++; + for( ; dwMask; dwMask>>=1 ) dwGShiftL--; + + for( dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwBShiftR++; + for( ; dwMask; dwMask>>=1 ) dwBShiftL--; + + for( dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwAShiftR++; + for( ; dwMask; dwMask>>=1 ) dwAShiftL--; + + for( DWORD y=0; y>24)&0x000000ff); + BYTE g = (BYTE)((dwPixel>>16)&0x000000ff); + BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff); + BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff); + + DWORD dr = ((r>>(dwRShiftL))<>(dwGShiftL))<>(dwBShiftL))<>(dwAShiftL))<Unlock(0); + + // Copy the temp surface to the real texture surface + m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL ); + + // Done with the temp objects + pddsTempSurface->Release(); + pDD->Release(); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_SetTexturePath() +// Desc: Enumeration callback routine to find a best-matching texture format. +//----------------------------------------------------------------------------- +VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath ) +{ + if( NULL == strTexturePath ) + strTexturePath = _T(""); + lstrcpy( g_strTexturePath, strTexturePath ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_CreateTextureFromFile() +// Desc: Is passed a filename and creates a local Bitmap from that file. +// The texture can not be used until it is restored, however. +//----------------------------------------------------------------------------- +HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage, + DWORD dwFlags ) +{ + // Check parameters + if( NULL == strName ) + return E_INVALIDARG; + + // Check first to see if the texture is already loaded + if( NULL != FindTexture( strName ) ) + return S_OK; + + // Allocate and add the texture to the linked list of textures; + TextureContainer* ptcTexture = new TextureContainer( strName, dwStage, + dwFlags ); + if( NULL == ptcTexture ) + return E_OUTOFMEMORY; + + // Create a bitmap and load the texture file into it, + if( FAILED( ptcTexture->LoadImageData() ) ) + { + delete ptcTexture; + return E_FAIL; + } + + // Save the image's dimensions + if( ptcTexture->m_hbmBitmap ) + { + BITMAP bm; + GetObject( ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm ); + ptcTexture->m_dwWidth = (DWORD)bm.bmWidth; + ptcTexture->m_dwHeight = (DWORD)bm.bmHeight; + ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_CreateEmptyTexture() +// Desc: Creates an empty texture. +//----------------------------------------------------------------------------- +HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth, + DWORD dwHeight, DWORD dwStage, + DWORD dwFlags ) +{ + // Check parameters + if( NULL == strName ) + return E_INVALIDARG; + + // Check first to see if the texture is already loaded + if( NULL != FindTexture( strName ) ) + return E_FAIL; + + // Allocate and add the texture to the linked list of textures; + TextureContainer* ptcTexture = new TextureContainer( strName, dwStage, + dwFlags ); + if( NULL == ptcTexture ) + return E_OUTOFMEMORY; + + // Save dimensions + ptcTexture->m_dwWidth = dwWidth; + ptcTexture->m_dwHeight = dwHeight; + ptcTexture->m_dwBPP = 16; + if( ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL ) + ptcTexture->m_dwBPP = 32; + + // Save alpha usage flag + if( dwFlags & D3DTEXTR_CREATEWITHALPHA ) + ptcTexture->m_bHasAlpha = true; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_Restore() +// Desc: Invalidates the current texture objects and rebuilds new ones +// using the new device. +//----------------------------------------------------------------------------- +HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice ) +{ + TextureContainer* ptcTexture = FindTexture( strName ); + if( NULL == ptcTexture ) + return DDERR_NOTFOUND; + + // Restore the texture (this recreates the new surface for this device). + return ptcTexture->Restore( pd3dDevice ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_RestoreAllTextures() +// Desc: This function is called when a mode is changed. It updates all +// texture objects to be valid with the new device. +//----------------------------------------------------------------------------- +HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice ) +{ + TextureContainer* ptcTexture = g_ptcTextureList; + + while( ptcTexture ) + { + D3DTextr_Restore( ptcTexture->m_strName, pd3dDevice ); + ptcTexture = ptcTexture->m_pNext; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_Invalidate() +// Desc: Used to bump a texture out of (video) memory, this function +// actually destroys the d3dtexture and ddsurface of the texture +//----------------------------------------------------------------------------- +HRESULT D3DTextr_Invalidate( TCHAR* strName ) +{ + TextureContainer* ptcTexture = FindTexture( strName ); + if( NULL == ptcTexture ) + return DDERR_NOTFOUND; + + SAFE_RELEASE( ptcTexture->m_pddsSurface ); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_InvalidateAllTextures() +// Desc: This function is called when a mode is changed. It invalidates +// all texture objects so their device can be safely released. +//----------------------------------------------------------------------------- +HRESULT D3DTextr_InvalidateAllTextures() +{ + TextureContainer* ptcTexture = g_ptcTextureList; + + while( ptcTexture ) + { + SAFE_RELEASE( ptcTexture->m_pddsSurface ); + ptcTexture = ptcTexture->m_pNext; + } + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_DestroyTexture() +// Desc: Frees the resources for the specified texture container +//----------------------------------------------------------------------------- +HRESULT D3DTextr_DestroyTexture( TCHAR* strName ) +{ + TextureContainer* ptcTexture = FindTexture( strName ); + + SAFE_DELETE( ptcTexture ); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DTextr_GetSurface() +// Desc: Returns a pointer to a d3dSurface from the name of the texture +//----------------------------------------------------------------------------- +LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName ) +{ + TextureContainer* ptcTexture = FindTexture( strName ); + + return ptcTexture ? ptcTexture->m_pddsSurface : NULL; +} + + + + + diff --git a/src/old/d3dtextr.h b/src/old/d3dtextr.h index 842fa58..ec0dc47 100644 --- a/src/old/d3dtextr.h +++ b/src/old/d3dtextr.h @@ -1,79 +1,79 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DTextr.h -// -// Desc: Functions to manage textures, including creating (loading from a -// file), restoring lost surfaces, invalidating, and destroying. -// -// Note: the implementation of these fucntions maintain an internal list -// of loaded textures. After creation, individual textures are referenced -// via their ASCII names. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- - -#pragma once - -#include -#include - - - - -//----------------------------------------------------------------------------- -// Access functions for loaded textures. Note: these functions search -// an internal list of the textures, and use the texture associated with the -// ASCII name. -//----------------------------------------------------------------------------- -LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName ); - - - - -//----------------------------------------------------------------------------- -// Texture invalidation and restoration functions -//----------------------------------------------------------------------------- -HRESULT D3DTextr_Invalidate( TCHAR* strName ); -HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice ); -HRESULT D3DTextr_InvalidateAllTextures(); -HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice ); - - - - -//----------------------------------------------------------------------------- -// Texture creation and deletion functions -//----------------------------------------------------------------------------- -#define D3DTEXTR_TRANSPARENTWHITE 0x00000001 -#define D3DTEXTR_TRANSPARENTBLACK 0x00000002 -#define D3DTEXTR_32BITSPERPIXEL 0x00000004 -#define D3DTEXTR_16BITSPERPIXEL 0x00000008 -#define D3DTEXTR_CREATEWITHALPHA 0x00000010 - - -HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage=0L, - DWORD dwFlags=0L ); -HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth, - DWORD dwHeight, DWORD dwStage, - DWORD dwFlags ); -HRESULT D3DTextr_DestroyTexture( TCHAR* strName ); -VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath ); - -void D3DTextr_SetDebugMode(bool bDebug); - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DTextr.h +// +// Desc: Functions to manage textures, including creating (loading from a +// file), restoring lost surfaces, invalidating, and destroying. +// +// Note: the implementation of these fucntions maintain an internal list +// of loaded textures. After creation, individual textures are referenced +// via their ASCII names. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include + + + + +//----------------------------------------------------------------------------- +// Access functions for loaded textures. Note: these functions search +// an internal list of the textures, and use the texture associated with the +// ASCII name. +//----------------------------------------------------------------------------- +LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName ); + + + + +//----------------------------------------------------------------------------- +// Texture invalidation and restoration functions +//----------------------------------------------------------------------------- +HRESULT D3DTextr_Invalidate( TCHAR* strName ); +HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice ); +HRESULT D3DTextr_InvalidateAllTextures(); +HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice ); + + + + +//----------------------------------------------------------------------------- +// Texture creation and deletion functions +//----------------------------------------------------------------------------- +#define D3DTEXTR_TRANSPARENTWHITE 0x00000001 +#define D3DTEXTR_TRANSPARENTBLACK 0x00000002 +#define D3DTEXTR_32BITSPERPIXEL 0x00000004 +#define D3DTEXTR_16BITSPERPIXEL 0x00000008 +#define D3DTEXTR_CREATEWITHALPHA 0x00000010 + + +HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage=0L, + DWORD dwFlags=0L ); +HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth, + DWORD dwHeight, DWORD dwStage, + DWORD dwFlags ); +HRESULT D3DTextr_DestroyTexture( TCHAR* strName ); +VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath ); + +void D3DTextr_SetDebugMode(bool bDebug); + + diff --git a/src/old/d3dutil.cpp b/src/old/d3dutil.cpp index d8fd03e..bd4c7ac 100644 --- a/src/old/d3dutil.cpp +++ b/src/old/d3dutil.cpp @@ -1,325 +1,325 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DUtil.cpp -// -// Desc: Shortcut macros and functions for using DX objects -// -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- -#include -#include -#include -#include "old/d3dutil.h" - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_GetDXSDKMediaPath() -// Desc: Returns the DirectX SDK media path, as stored in the system registry -// during the SDK install. -//----------------------------------------------------------------------------- -const TCHAR* D3DUtil_GetDXSDKMediaPath() -{ - static TCHAR strNull[2] = _T(""); - static TCHAR strPath[512]; - HKEY key; - DWORD type, size = 512; - - // Open the appropriate registry key - LONG result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - _T("Software\\Microsoft\\DirectX"), - 0, KEY_READ, &key ); - if( ERROR_SUCCESS != result ) - return strNull; - - result = RegQueryValueEx( key, _T("DXSDK Samples Path"), NULL, - &type, (BYTE*)strPath, &size ); - RegCloseKey( key ); - - if( ERROR_SUCCESS != result ) - return strNull; - - lstrcat( strPath, _T("\\D3DIM\\Media\\") ); - - return strPath; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_InitSurfaceDesc() -// Desc: Helper function called to build a DDSURFACEDESC2 structure, -// typically before calling CreateSurface() or GetSurfaceDesc() -//----------------------------------------------------------------------------- -VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags, - DWORD dwCaps ) -{ - ZeroMemory( &ddsd, sizeof(ddsd) ); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = dwFlags; - ddsd.ddsCaps.dwCaps = dwCaps; - ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_InitMaterial() -// Desc: Helper function called to build a D3DMATERIAL7 structure -//----------------------------------------------------------------------------- -VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r, FLOAT g, FLOAT b, - FLOAT a ) -{ - ZeroMemory( &mtrl, sizeof(D3DMATERIAL7) ); - mtrl.dcvDiffuse.r = mtrl.dcvAmbient.r = r; - mtrl.dcvDiffuse.g = mtrl.dcvAmbient.g = g; - mtrl.dcvDiffuse.b = mtrl.dcvAmbient.b = b; - mtrl.dcvDiffuse.a = mtrl.dcvAmbient.a = a; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_InitLight() -// Desc: Initializes a D3DLIGHT7 structure -//----------------------------------------------------------------------------- -VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType, - FLOAT x, FLOAT y, FLOAT z ) -{ - ZeroMemory( &light, sizeof(D3DLIGHT7) ); - light.dltType = ltType; - light.dcvDiffuse.r = 1.0f; - light.dcvDiffuse.g = 1.0f; - light.dcvDiffuse.b = 1.0f; - light.dcvSpecular = light.dcvDiffuse; - light.dvPosition.x = light.dvDirection.x = x; - light.dvPosition.y = light.dvDirection.y = y; - light.dvPosition.z = light.dvDirection.z = z; - light.dvAttenuation0 = 1.0f; - light.dvRange = D3DLIGHT_RANGE_MAX; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetViewMatrix() -// Desc: Given an eye point, a lookat point, and an up vector, this -// function builds a 4x4 view matrix. -//----------------------------------------------------------------------------- -HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, - D3DVECTOR& vAt, D3DVECTOR& vWorldUp ) -{ - // Get the z basis vector, which points straight ahead. This is the - // difference from the eyepoint to the lookat point. - D3DVECTOR vView = vAt - vFrom; - - FLOAT fLength = Magnitude( vView ); - if( fLength < 1e-6f ) - return E_INVALIDARG; - - // Normalize the z basis vector - vView /= fLength; - - // Get the dot product, and calculate the projection of the z basis - // vector onto the up vector. The projection is the y basis vector. - FLOAT fDotProduct = DotProduct( vWorldUp, vView ); - - D3DVECTOR vUp = vWorldUp - fDotProduct * vView; - - // If this vector has near-zero length because the input specified a - // bogus up vector, let's try a default up vector - if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) - { - vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; - - // If we still have near-zero length, resort to a different axis. - if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) - { - vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; - - if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) - return E_INVALIDARG; - } - } - - // Normalize the y basis vector - vUp /= fLength; - - // The x basis vector is found simply with the cross product of the y - // and z basis vectors - D3DVECTOR vRight = CrossProduct( vUp, vView ); - - // Start building the matrix. The first three rows contains the basis - // vectors used to rotate the view to point at the lookat point - D3DUtil_SetIdentityMatrix( mat ); - mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; - mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; - mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; - - // Do the translation values (rotations are still about the eyepoint) - mat._41 = - DotProduct( vFrom, vRight ); - mat._42 = - DotProduct( vFrom, vUp ); - mat._43 = - DotProduct( vFrom, vView ); - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetProjectionMatrix() -// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built -// from the field-of-view (fov, in y), aspect ratio, near plane (D), -// and far plane (F). Note that the projection matrix is normalized for -// element [3][4] to be 1.0. This is performed so that W-based range fog -// will work correctly. -//----------------------------------------------------------------------------- -HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect, - FLOAT fNearPlane, FLOAT fFarPlane ) -{ - if( fabs(fFarPlane-fNearPlane) < 0.01f ) - return E_INVALIDARG; - if( fabs(sin(fFOV/2)) < 0.01f ) - return E_INVALIDARG; - - FLOAT w = fAspect * ( cosf(fFOV/2)/sinf(fFOV/2) ); - FLOAT h = 1.0f * ( cosf(fFOV/2)/sinf(fFOV/2) ); - FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane ); - - ZeroMemory( &mat, sizeof(D3DMATRIX) ); - mat._11 = w; - mat._22 = h; - mat._33 = Q; - mat._34 = 1.0f; - mat._43 = -Q*fNearPlane; - - return S_OK; -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetRotateXMatrix() -// Desc: Create Rotation matrix about X axis -//----------------------------------------------------------------------------- -VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ) -{ - D3DUtil_SetIdentityMatrix( mat ); - mat._22 = cosf( fRads ); - mat._23 = sinf( fRads ); - mat._32 = -sinf( fRads ); - mat._33 = cosf( fRads ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetRotateYMatrix() -// Desc: Create Rotation matrix about Y axis -//----------------------------------------------------------------------------- -VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ) -{ - D3DUtil_SetIdentityMatrix( mat ); - mat._11 = cosf( fRads ); - mat._13 = -sinf( fRads ); - mat._31 = sinf( fRads ); - mat._33 = cosf( fRads ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetRotateZMatrix() -// Desc: Create Rotation matrix about Z axis -//----------------------------------------------------------------------------- -VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ) -{ - D3DUtil_SetIdentityMatrix( mat ); - mat._11 = cosf( fRads ); - mat._12 = sinf( fRads ); - mat._21 = -sinf( fRads ); - mat._22 = cosf( fRads ); -} - - - - -//----------------------------------------------------------------------------- -// Name: D3DUtil_SetRotationMatrix -// Desc: Create a Rotation matrix about vector direction -//----------------------------------------------------------------------------- -VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, FLOAT fRads ) -{ - FLOAT fCos = cosf( fRads ); - FLOAT fSin = sinf( fRads ); - D3DVECTOR v = Normalize( vDir ); - - mat._11 = ( v.x * v.x ) * ( 1.0f - fCos ) + fCos; - mat._12 = ( v.x * v.y ) * ( 1.0f - fCos ) - (v.z * fSin); - mat._13 = ( v.x * v.z ) * ( 1.0f - fCos ) + (v.y * fSin); - - mat._21 = ( v.y * v.x ) * ( 1.0f - fCos ) + (v.z * fSin); - mat._22 = ( v.y * v.y ) * ( 1.0f - fCos ) + fCos ; - mat._23 = ( v.y * v.z ) * ( 1.0f - fCos ) - (v.x * fSin); - - mat._31 = ( v.z * v.x ) * ( 1.0f - fCos ) - (v.y * fSin); - mat._32 = ( v.z * v.y ) * ( 1.0f - fCos ) + (v.x * fSin); - mat._33 = ( v.z * v.z ) * ( 1.0f - fCos ) + fCos; - - mat._14 = mat._24 = mat._34 = 0.0f; - mat._41 = mat._42 = mat._43 = 0.0f; - mat._44 = 1.0f; -} - - - - -//----------------------------------------------------------------------------- -// Name: _DbgOut() -// Desc: Outputs a message to the debug stream -//----------------------------------------------------------------------------- -HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg ) -{ - TCHAR buffer[256]; - wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine ); - OutputDebugString( buffer ); - OutputDebugString( strMsg ); - - if( hr ) - { - wsprintf( buffer, _T("(hr=%08lx)\n"), hr ); - OutputDebugString( buffer ); - } - - OutputDebugString( _T("\n") ); - - return hr; -} - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DUtil.cpp +// +// Desc: Shortcut macros and functions for using DX objects +// +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- +#include +#include +#include +#include "old/d3dutil.h" + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_GetDXSDKMediaPath() +// Desc: Returns the DirectX SDK media path, as stored in the system registry +// during the SDK install. +//----------------------------------------------------------------------------- +const TCHAR* D3DUtil_GetDXSDKMediaPath() +{ + static TCHAR strNull[2] = _T(""); + static TCHAR strPath[512]; + HKEY key; + DWORD type, size = 512; + + // Open the appropriate registry key + LONG result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, + _T("Software\\Microsoft\\DirectX"), + 0, KEY_READ, &key ); + if( ERROR_SUCCESS != result ) + return strNull; + + result = RegQueryValueEx( key, _T("DXSDK Samples Path"), NULL, + &type, (BYTE*)strPath, &size ); + RegCloseKey( key ); + + if( ERROR_SUCCESS != result ) + return strNull; + + lstrcat( strPath, _T("\\D3DIM\\Media\\") ); + + return strPath; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitSurfaceDesc() +// Desc: Helper function called to build a DDSURFACEDESC2 structure, +// typically before calling CreateSurface() or GetSurfaceDesc() +//----------------------------------------------------------------------------- +VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags, + DWORD dwCaps ) +{ + ZeroMemory( &ddsd, sizeof(ddsd) ); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = dwFlags; + ddsd.ddsCaps.dwCaps = dwCaps; + ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitMaterial() +// Desc: Helper function called to build a D3DMATERIAL7 structure +//----------------------------------------------------------------------------- +VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r, FLOAT g, FLOAT b, + FLOAT a ) +{ + ZeroMemory( &mtrl, sizeof(D3DMATERIAL7) ); + mtrl.dcvDiffuse.r = mtrl.dcvAmbient.r = r; + mtrl.dcvDiffuse.g = mtrl.dcvAmbient.g = g; + mtrl.dcvDiffuse.b = mtrl.dcvAmbient.b = b; + mtrl.dcvDiffuse.a = mtrl.dcvAmbient.a = a; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_InitLight() +// Desc: Initializes a D3DLIGHT7 structure +//----------------------------------------------------------------------------- +VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType, + FLOAT x, FLOAT y, FLOAT z ) +{ + ZeroMemory( &light, sizeof(D3DLIGHT7) ); + light.dltType = ltType; + light.dcvDiffuse.r = 1.0f; + light.dcvDiffuse.g = 1.0f; + light.dcvDiffuse.b = 1.0f; + light.dcvSpecular = light.dcvDiffuse; + light.dvPosition.x = light.dvDirection.x = x; + light.dvPosition.y = light.dvDirection.y = y; + light.dvPosition.z = light.dvDirection.z = z; + light.dvAttenuation0 = 1.0f; + light.dvRange = D3DLIGHT_RANGE_MAX; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetViewMatrix() +// Desc: Given an eye point, a lookat point, and an up vector, this +// function builds a 4x4 view matrix. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, + D3DVECTOR& vAt, D3DVECTOR& vWorldUp ) +{ + // Get the z basis vector, which points straight ahead. This is the + // difference from the eyepoint to the lookat point. + D3DVECTOR vView = vAt - vFrom; + + FLOAT fLength = Magnitude( vView ); + if( fLength < 1e-6f ) + return E_INVALIDARG; + + // Normalize the z basis vector + vView /= fLength; + + // Get the dot product, and calculate the projection of the z basis + // vector onto the up vector. The projection is the y basis vector. + FLOAT fDotProduct = DotProduct( vWorldUp, vView ); + + D3DVECTOR vUp = vWorldUp - fDotProduct * vView; + + // If this vector has near-zero length because the input specified a + // bogus up vector, let's try a default up vector + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + { + vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; + + // If we still have near-zero length, resort to a different axis. + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + { + vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; + + if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) + return E_INVALIDARG; + } + } + + // Normalize the y basis vector + vUp /= fLength; + + // The x basis vector is found simply with the cross product of the y + // and z basis vectors + D3DVECTOR vRight = CrossProduct( vUp, vView ); + + // Start building the matrix. The first three rows contains the basis + // vectors used to rotate the view to point at the lookat point + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; + mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; + mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; + + // Do the translation values (rotations are still about the eyepoint) + mat._41 = - DotProduct( vFrom, vRight ); + mat._42 = - DotProduct( vFrom, vUp ); + mat._43 = - DotProduct( vFrom, vView ); + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetProjectionMatrix() +// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built +// from the field-of-view (fov, in y), aspect ratio, near plane (D), +// and far plane (F). Note that the projection matrix is normalized for +// element [3][4] to be 1.0. This is performed so that W-based range fog +// will work correctly. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect, + FLOAT fNearPlane, FLOAT fFarPlane ) +{ + if( fabs(fFarPlane-fNearPlane) < 0.01f ) + return E_INVALIDARG; + if( fabs(sin(fFOV/2)) < 0.01f ) + return E_INVALIDARG; + + FLOAT w = fAspect * ( cosf(fFOV/2)/sinf(fFOV/2) ); + FLOAT h = 1.0f * ( cosf(fFOV/2)/sinf(fFOV/2) ); + FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane ); + + ZeroMemory( &mat, sizeof(D3DMATRIX) ); + mat._11 = w; + mat._22 = h; + mat._33 = Q; + mat._34 = 1.0f; + mat._43 = -Q*fNearPlane; + + return S_OK; +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateXMatrix() +// Desc: Create Rotation matrix about X axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._22 = cosf( fRads ); + mat._23 = sinf( fRads ); + mat._32 = -sinf( fRads ); + mat._33 = cosf( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateYMatrix() +// Desc: Create Rotation matrix about Y axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = cosf( fRads ); + mat._13 = -sinf( fRads ); + mat._31 = sinf( fRads ); + mat._33 = cosf( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotateZMatrix() +// Desc: Create Rotation matrix about Z axis +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ) +{ + D3DUtil_SetIdentityMatrix( mat ); + mat._11 = cosf( fRads ); + mat._12 = sinf( fRads ); + mat._21 = -sinf( fRads ); + mat._22 = cosf( fRads ); +} + + + + +//----------------------------------------------------------------------------- +// Name: D3DUtil_SetRotationMatrix +// Desc: Create a Rotation matrix about vector direction +//----------------------------------------------------------------------------- +VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, FLOAT fRads ) +{ + FLOAT fCos = cosf( fRads ); + FLOAT fSin = sinf( fRads ); + D3DVECTOR v = Normalize( vDir ); + + mat._11 = ( v.x * v.x ) * ( 1.0f - fCos ) + fCos; + mat._12 = ( v.x * v.y ) * ( 1.0f - fCos ) - (v.z * fSin); + mat._13 = ( v.x * v.z ) * ( 1.0f - fCos ) + (v.y * fSin); + + mat._21 = ( v.y * v.x ) * ( 1.0f - fCos ) + (v.z * fSin); + mat._22 = ( v.y * v.y ) * ( 1.0f - fCos ) + fCos ; + mat._23 = ( v.y * v.z ) * ( 1.0f - fCos ) - (v.x * fSin); + + mat._31 = ( v.z * v.x ) * ( 1.0f - fCos ) - (v.y * fSin); + mat._32 = ( v.z * v.y ) * ( 1.0f - fCos ) + (v.x * fSin); + mat._33 = ( v.z * v.z ) * ( 1.0f - fCos ) + fCos; + + mat._14 = mat._24 = mat._34 = 0.0f; + mat._41 = mat._42 = mat._43 = 0.0f; + mat._44 = 1.0f; +} + + + + +//----------------------------------------------------------------------------- +// Name: _DbgOut() +// Desc: Outputs a message to the debug stream +//----------------------------------------------------------------------------- +HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg ) +{ + TCHAR buffer[256]; + wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine ); + OutputDebugString( buffer ); + OutputDebugString( strMsg ); + + if( hr ) + { + wsprintf( buffer, _T("(hr=%08lx)\n"), hr ); + OutputDebugString( buffer ); + } + + OutputDebugString( _T("\n") ); + + return hr; +} + + + diff --git a/src/old/d3dutil.h b/src/old/d3dutil.h index 8fe88c9..369c7db 100644 --- a/src/old/d3dutil.h +++ b/src/old/d3dutil.h @@ -1,113 +1,113 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -//----------------------------------------------------------------------------- -// File: D3DUtil.h -// -// Desc: Helper functions and typing shortcuts for Direct3D programming. -// -// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved -//----------------------------------------------------------------------------- - -#pragma once - -#include -#include - - - - -//----------------------------------------------------------------------------- -// Miscellaneous helper functions -//----------------------------------------------------------------------------- -const TCHAR* D3DUtil_GetDXSDKMediaPath(); - -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } - - - - -//----------------------------------------------------------------------------- -// Short cut functions for creating and using DX structures -//----------------------------------------------------------------------------- -VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC7& ddDevDesc ); -VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags=0, - DWORD dwCaps=0 ); -VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r=0.0f, FLOAT g=0.0f, - FLOAT b=0.0f, FLOAT a=1.0f ); -VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType, - FLOAT x=0.0f, FLOAT y=0.0f, FLOAT z=0.0f ); - - - - -//----------------------------------------------------------------------------- -// D3D Matrix functions. For performance reasons, some functions are inline. -//----------------------------------------------------------------------------- -HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, - D3DVECTOR& vAt, D3DVECTOR& vUp ); -HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV = 1.570795f, - FLOAT fAspect = 1.0f, - FLOAT fNearPlane = 1.0f, - FLOAT fFarPlane = 1000.0f ); - -inline VOID D3DUtil_SetIdentityMatrix( D3DMATRIX& m ) -{ - m._12 = m._13 = m._14 = m._21 = m._23 = m._24 = 0.0f; - m._31 = m._32 = m._34 = m._41 = m._42 = m._43 = 0.0f; - m._11 = m._22 = m._33 = m._44 = 1.0f; -} - -inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty, - FLOAT tz ) -{ D3DUtil_SetIdentityMatrix( m ); m._41 = tx; m._42 = ty; m._43 = tz; } - -inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, D3DVECTOR& v ) -{ D3DUtil_SetTranslateMatrix( m, v.x, v.y, v.z ); } - -inline VOID D3DUtil_SetScaleMatrix( D3DMATRIX& m, FLOAT sx, FLOAT sy, - FLOAT sz ) -{ D3DUtil_SetIdentityMatrix( m ); m._11 = sx; m._22 = sy; m._33 = sz; } - -inline VOID SetScaleMatrix( D3DMATRIX& m, D3DVECTOR& v ) -{ D3DUtil_SetScaleMatrix( m, v.x, v.y, v.z ); } - -VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ); -VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ); -VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ); -VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, - FLOAT fRads ); - - - - -//----------------------------------------------------------------------------- -// Debug printing support -//----------------------------------------------------------------------------- - -HRESULT _DbgOut( TCHAR*, DWORD, HRESULT, TCHAR* ); - -#if defined(DEBUG) | defined(_DEBUG) - #define DEBUG_MSG(str) _DbgOut( __FILE__, (DWORD)__LINE__, 0, str ) - #define DEBUG_ERR(hr,str) _DbgOut( __FILE__, (DWORD)__LINE__, hr, str ) -#else - #define DEBUG_MSG(str) (0L) - #define DEBUG_ERR(hr,str) (hr) -#endif - - - +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +//----------------------------------------------------------------------------- +// File: D3DUtil.h +// +// Desc: Helper functions and typing shortcuts for Direct3D programming. +// +// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved +//----------------------------------------------------------------------------- + +#pragma once + +#include +#include + + + + +//----------------------------------------------------------------------------- +// Miscellaneous helper functions +//----------------------------------------------------------------------------- +const TCHAR* D3DUtil_GetDXSDKMediaPath(); + +#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } + + + + +//----------------------------------------------------------------------------- +// Short cut functions for creating and using DX structures +//----------------------------------------------------------------------------- +VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC7& ddDevDesc ); +VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags=0, + DWORD dwCaps=0 ); +VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r=0.0f, FLOAT g=0.0f, + FLOAT b=0.0f, FLOAT a=1.0f ); +VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType, + FLOAT x=0.0f, FLOAT y=0.0f, FLOAT z=0.0f ); + + + + +//----------------------------------------------------------------------------- +// D3D Matrix functions. For performance reasons, some functions are inline. +//----------------------------------------------------------------------------- +HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, + D3DVECTOR& vAt, D3DVECTOR& vUp ); +HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV = 1.570795f, + FLOAT fAspect = 1.0f, + FLOAT fNearPlane = 1.0f, + FLOAT fFarPlane = 1000.0f ); + +inline VOID D3DUtil_SetIdentityMatrix( D3DMATRIX& m ) +{ + m._12 = m._13 = m._14 = m._21 = m._23 = m._24 = 0.0f; + m._31 = m._32 = m._34 = m._41 = m._42 = m._43 = 0.0f; + m._11 = m._22 = m._33 = m._44 = 1.0f; +} + +inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty, + FLOAT tz ) +{ D3DUtil_SetIdentityMatrix( m ); m._41 = tx; m._42 = ty; m._43 = tz; } + +inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, D3DVECTOR& v ) +{ D3DUtil_SetTranslateMatrix( m, v.x, v.y, v.z ); } + +inline VOID D3DUtil_SetScaleMatrix( D3DMATRIX& m, FLOAT sx, FLOAT sy, + FLOAT sz ) +{ D3DUtil_SetIdentityMatrix( m ); m._11 = sx; m._22 = sy; m._33 = sz; } + +inline VOID SetScaleMatrix( D3DMATRIX& m, D3DVECTOR& v ) +{ D3DUtil_SetScaleMatrix( m, v.x, v.y, v.z ); } + +VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads ); +VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, + FLOAT fRads ); + + + + +//----------------------------------------------------------------------------- +// Debug printing support +//----------------------------------------------------------------------------- + +HRESULT _DbgOut( TCHAR*, DWORD, HRESULT, TCHAR* ); + +#if defined(DEBUG) | defined(_DEBUG) + #define DEBUG_MSG(str) _DbgOut( __FILE__, (DWORD)__LINE__, 0, str ) + #define DEBUG_ERR(hr,str) _DbgOut( __FILE__, (DWORD)__LINE__, hr, str ) +#else + #define DEBUG_MSG(str) (0L) + #define DEBUG_ERR(hr,str) (hr) +#endif + + + diff --git a/src/old/joystick.cpp b/src/old/joystick.cpp index c08a252..3415047 100644 --- a/src/old/joystick.cpp +++ b/src/old/joystick.cpp @@ -1,244 +1,244 @@ -// * 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/. - -// joystick.cpp - -#define DIRECTINPUT_VERSION 0x0700 - -#include -#include -#include - -#include "old/joystick.h" - - - - -// Global variables. - -LPDIRECTINPUT7 g_pDI = NULL; -LPDIRECTINPUTDEVICE2 g_pJoystick = NULL; -DIDEVCAPS g_diDevCaps; - - - - - -// Called once for each enumerated joystick. If we find one, create a -// device interface on it so we can play with it. - -bool CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ) -{ - HRESULT hr; - - // Obtain an interface to the enumerated joystick. - hr = g_pDI->CreateDeviceEx( pdidInstance->guidInstance, IID_IDirectInputDevice2, - (VOID**)&g_pJoystick, NULL ); - - // If it failed, then we can't use this joystick. (Maybe the user unplugged - // it while we were in the middle of enumerating it.) - if( FAILED(hr) ) - return DIENUM_CONTINUE; - - - // Stop enumeration. Note: we're just taking the first joystick we get. You - // could store all the enumerated joysticks and let the user pick. - return DIENUM_STOP; -} - - -// Callback function for enumerating the axes on a joystick. - -bool CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) -{ - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis - diprg.lMin = -1000; - diprg.lMax = +1000; - - // Set the range for the axis - if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) - return DIENUM_STOP; - -#ifndef __MINGW32__ // FIXME Doesn't work under MinGW - // Set the UI to reflect what axes the joystick supports - switch( pdidoi->dwOfs ) - { - case DIJOFS_X: - OutputDebugString("EnumAxesCallback -x\n"); - break; - case DIJOFS_Y: - OutputDebugString("EnumAxesCallback -y\n"); - break; - case DIJOFS_Z: - OutputDebugString("EnumAxesCallback -z\n"); - break; - case DIJOFS_RX: - OutputDebugString("EnumAxesCallback -rx\n"); - break; - case DIJOFS_RY: - OutputDebugString("EnumAxesCallback -ry\n"); - break; - case DIJOFS_RZ: - OutputDebugString("EnumAxesCallback -rz\n"); - break; - case DIJOFS_SLIDER(0): - OutputDebugString("EnumAxesCallback -s0\n"); - break; - case DIJOFS_SLIDER(1): - OutputDebugString("EnumAxesCallback -s1\n"); - break; - } -#endif - - return DIENUM_CONTINUE; -} - - -// Initialize the DirectInput variables. - -bool InitDirectInput(HINSTANCE hInst, HWND hWnd) -{ - HRESULT hr; - - // Register with the DirectInput subsystem and get a pointer - // to a IDirectInput interface we can use. -#ifndef __MINGW32__ // FIXME Doesn't work under MinGW - hr = DirectInputCreateEx( hInst, DIRECTINPUT_VERSION,IID_IDirectInput7, (LPVOID*)&g_pDI, NULL ); - if( FAILED(hr) ) return false; -#else - return false; -#endif - - // Look for a simple joystick we can use for this sample program. - hr = g_pDI->EnumDevices( DIDEVTYPE_JOYSTICK, EnumJoysticksCallback, - NULL, DIEDFL_ATTACHEDONLY ); - if( FAILED(hr) ) return false; - - // Make sure we got a joystick - if( NULL == g_pJoystick ) - { -//? MessageBox( NULL, "Joystick not found", "DInput Sample", -//? MB_ICONERROR | MB_OK ); - return false; - } - - // Set the data format to "simple joystick" - a predefined data format - // - // A data format specifies which controls on a device we are interested in, - // and how they should be reported. This tells DInput that we will be - // passing a DIJOYSTATE structure to IDirectInputDevice::GetDeviceState(). - hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ); - if( FAILED(hr) ) return false; - - // Set the cooperative level to let DInput know how this device should - // interact with the system and with other DInput applications. - hr = g_pJoystick->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE|DISCL_FOREGROUND ); - if( FAILED(hr) ) return false; - - // Determine how many axis the joystick has (so we don't error out setting - // properties for unavailable axis) - g_diDevCaps.dwSize = sizeof(DIDEVCAPS); - hr = g_pJoystick->GetCapabilities(&g_diDevCaps); - if( FAILED(hr) ) return false; - - - // Enumerate the axes of the joyctick and set the range of each axis. Note: - // we could just use the defaults, but we're just trying to show an example - // of enumerating device objects (axes, buttons, etc.). - g_pJoystick->EnumObjects( EnumAxesCallback, (VOID*)g_pJoystick, DIDFT_AXIS ); - - return true; -} - -// Acquire or unacquire the keyboard, depending on if the app is active -// Input device must be acquired before the GetDeviceState is called. - -bool SetAcquire(bool bActive) -{ - if ( g_pJoystick ) - { - if( bActive ) g_pJoystick->Acquire(); - else g_pJoystick->Unacquire(); - } - return true; -} - - -// Get the input device's state and display it. - -bool UpdateInputState( DIJOYSTATE &js ) -{ - HRESULT hr; - - if ( g_pJoystick ) - { - do - { - // Poll the device to read the current state - hr = g_pJoystick->Poll(); - if ( FAILED(hr) ) return false; - - // Get the input's device state - hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ); - - if( hr == DIERR_INPUTLOST ) - { - // DInput is telling us that the input stream has been - // interrupted. We aren't tracking any state between polls, so - // we don't have any special reset that needs to be done. We - // just re-acquire and try again. - hr = g_pJoystick->Acquire(); - if ( FAILED(hr) ) return false; - } - } - while ( DIERR_INPUTLOST == hr ); - if ( FAILED(hr) ) return false; - } - return true; -} - - -// Initialize the DirectInput variables. - -bool FreeDirectInput() -{ - // Unacquire and release any DirectInputDevice objects. - if( NULL != g_pJoystick ) - { - // Unacquire the device one last time just in case - // the app tried to exit while the device is still acquired. - g_pJoystick->Unacquire(); - g_pJoystick->Release(); - g_pJoystick = NULL; - } - - - // Release any DirectInput objects. - if( g_pDI ) - { - g_pDI->Release(); - g_pDI = NULL; - } - - return true; -} - +// * 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/. + +// joystick.cpp + +#define DIRECTINPUT_VERSION 0x0700 + +#include +#include +#include + +#include "old/joystick.h" + + + + +// Global variables. + +LPDIRECTINPUT7 g_pDI = NULL; +LPDIRECTINPUTDEVICE2 g_pJoystick = NULL; +DIDEVCAPS g_diDevCaps; + + + + + +// Called once for each enumerated joystick. If we find one, create a +// device interface on it so we can play with it. + +bool CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, + VOID* pContext ) +{ + HRESULT hr; + + // Obtain an interface to the enumerated joystick. + hr = g_pDI->CreateDeviceEx( pdidInstance->guidInstance, IID_IDirectInputDevice2, + (VOID**)&g_pJoystick, NULL ); + + // If it failed, then we can't use this joystick. (Maybe the user unplugged + // it while we were in the middle of enumerating it.) + if( FAILED(hr) ) + return DIENUM_CONTINUE; + + + // Stop enumeration. Note: we're just taking the first joystick we get. You + // could store all the enumerated joysticks and let the user pick. + return DIENUM_STOP; +} + + +// Callback function for enumerating the axes on a joystick. + +bool CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) +{ + DIPROPRANGE diprg; + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis + diprg.lMin = -1000; + diprg.lMax = +1000; + + // Set the range for the axis + if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) + return DIENUM_STOP; + +#ifndef __MINGW32__ // FIXME Doesn't work under MinGW + // Set the UI to reflect what axes the joystick supports + switch( pdidoi->dwOfs ) + { + case DIJOFS_X: + OutputDebugString("EnumAxesCallback -x\n"); + break; + case DIJOFS_Y: + OutputDebugString("EnumAxesCallback -y\n"); + break; + case DIJOFS_Z: + OutputDebugString("EnumAxesCallback -z\n"); + break; + case DIJOFS_RX: + OutputDebugString("EnumAxesCallback -rx\n"); + break; + case DIJOFS_RY: + OutputDebugString("EnumAxesCallback -ry\n"); + break; + case DIJOFS_RZ: + OutputDebugString("EnumAxesCallback -rz\n"); + break; + case DIJOFS_SLIDER(0): + OutputDebugString("EnumAxesCallback -s0\n"); + break; + case DIJOFS_SLIDER(1): + OutputDebugString("EnumAxesCallback -s1\n"); + break; + } +#endif + + return DIENUM_CONTINUE; +} + + +// Initialize the DirectInput variables. + +bool InitDirectInput(HINSTANCE hInst, HWND hWnd) +{ + HRESULT hr; + + // Register with the DirectInput subsystem and get a pointer + // to a IDirectInput interface we can use. +#ifndef __MINGW32__ // FIXME Doesn't work under MinGW + hr = DirectInputCreateEx( hInst, DIRECTINPUT_VERSION,IID_IDirectInput7, (LPVOID*)&g_pDI, NULL ); + if( FAILED(hr) ) return false; +#else + return false; +#endif + + // Look for a simple joystick we can use for this sample program. + hr = g_pDI->EnumDevices( DIDEVTYPE_JOYSTICK, EnumJoysticksCallback, + NULL, DIEDFL_ATTACHEDONLY ); + if( FAILED(hr) ) return false; + + // Make sure we got a joystick + if( NULL == g_pJoystick ) + { +//? MessageBox( NULL, "Joystick not found", "DInput Sample", +//? MB_ICONERROR | MB_OK ); + return false; + } + + // Set the data format to "simple joystick" - a predefined data format + // + // A data format specifies which controls on a device we are interested in, + // and how they should be reported. This tells DInput that we will be + // passing a DIJOYSTATE structure to IDirectInputDevice::GetDeviceState(). + hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ); + if( FAILED(hr) ) return false; + + // Set the cooperative level to let DInput know how this device should + // interact with the system and with other DInput applications. + hr = g_pJoystick->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE|DISCL_FOREGROUND ); + if( FAILED(hr) ) return false; + + // Determine how many axis the joystick has (so we don't error out setting + // properties for unavailable axis) + g_diDevCaps.dwSize = sizeof(DIDEVCAPS); + hr = g_pJoystick->GetCapabilities(&g_diDevCaps); + if( FAILED(hr) ) return false; + + + // Enumerate the axes of the joyctick and set the range of each axis. Note: + // we could just use the defaults, but we're just trying to show an example + // of enumerating device objects (axes, buttons, etc.). + g_pJoystick->EnumObjects( EnumAxesCallback, (VOID*)g_pJoystick, DIDFT_AXIS ); + + return true; +} + +// Acquire or unacquire the keyboard, depending on if the app is active +// Input device must be acquired before the GetDeviceState is called. + +bool SetAcquire(bool bActive) +{ + if ( g_pJoystick ) + { + if( bActive ) g_pJoystick->Acquire(); + else g_pJoystick->Unacquire(); + } + return true; +} + + +// Get the input device's state and display it. + +bool UpdateInputState( DIJOYSTATE &js ) +{ + HRESULT hr; + + if ( g_pJoystick ) + { + do + { + // Poll the device to read the current state + hr = g_pJoystick->Poll(); + if ( FAILED(hr) ) return false; + + // Get the input's device state + hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ); + + if( hr == DIERR_INPUTLOST ) + { + // DInput is telling us that the input stream has been + // interrupted. We aren't tracking any state between polls, so + // we don't have any special reset that needs to be done. We + // just re-acquire and try again. + hr = g_pJoystick->Acquire(); + if ( FAILED(hr) ) return false; + } + } + while ( DIERR_INPUTLOST == hr ); + if ( FAILED(hr) ) return false; + } + return true; +} + + +// Initialize the DirectInput variables. + +bool FreeDirectInput() +{ + // Unacquire and release any DirectInputDevice objects. + if( NULL != g_pJoystick ) + { + // Unacquire the device one last time just in case + // the app tried to exit while the device is still acquired. + g_pJoystick->Unacquire(); + g_pJoystick->Release(); + g_pJoystick = NULL; + } + + + // Release any DirectInput objects. + if( g_pDI ) + { + g_pDI->Release(); + g_pDI = NULL; + } + + return true; +} + diff --git a/src/old/joystick.h b/src/old/joystick.h index 44fd1c3..5b4e517 100644 --- a/src/old/joystick.h +++ b/src/old/joystick.h @@ -1,27 +1,27 @@ -// * 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/. - -// joystick.h - -#pragma once - - -extern bool InitDirectInput(HINSTANCE hInst, HWND hWnd); -extern bool SetAcquire(bool bActive); -extern bool UpdateInputState(DIJOYSTATE &js); -extern bool FreeDirectInput(); - - +// * 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/. + +// joystick.h + +#pragma once + + +extern bool InitDirectInput(HINSTANCE hInst, HWND hWnd); +extern bool SetAcquire(bool bActive); +extern bool UpdateInputState(DIJOYSTATE &js); +extern bool FreeDirectInput(); + + diff --git a/src/old/light.cpp b/src/old/light.cpp index 0589141..811a824 100644 --- a/src/old/light.cpp +++ b/src/old/light.cpp @@ -1,504 +1,504 @@ -// * 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/. - -// light.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dengine.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/light.h" - - - - - -// Initializes a progression. - -void ProgInit(LightProg &p, float value) -{ - p.starting = value; - p.ending = value; - p.current = value; - p.progress = 0.0f; - p.speed = 100.0f; -} - -// Makes evolve a progression. - -void ProgFrame(LightProg &p, float rTime) -{ - if ( p.speed < 100.0f ) - { - if ( p.progress < 1.0f ) - { - p.progress += p.speed*rTime; - if ( p.progress > 1.0f ) - { - p.progress = 1.0f; - } - } - - p.current = (p.ending-p.starting)*p.progress + p.starting; - } - else - { - p.current = p.ending; - } -} - -// Change the current value. - -void ProgSet(LightProg &p, float value) -{ - p.starting = p.current; - p.ending = value; - p.progress = 0.0f; -} - - - - - -// Object's constructor. - -CLight::CLight(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_LIGHT, this); - - m_pD3DDevice = 0; - m_engine = engine; - - m_lightUsed = 0; - m_lightTable = (Light*)malloc(sizeof(Light)*D3DMAXLIGHT); - ZeroMemory(m_lightTable, sizeof(Light)*D3DMAXLIGHT); - - m_time = 0.0f; -} - -// Object's destructor. - -CLight::~CLight() -{ - free(m_lightTable); - m_iMan->DeleteInstance(CLASS_LIGHT, this); -} - - -void CLight::SetD3DDevice(LPDIRECT3DDEVICE7 device) -{ - m_pD3DDevice = device; -} - - -// Removes all the lights. - -void CLight::FlushLight() -{ - int i; - - for ( i=0 ; iLightEnable(i, false); - } - m_lightUsed = 0; -} - - -// Creates a new light. Returns its rank or -1 on error. - -int CLight::CreateLight() -{ - int i; - - for ( i=0 ; i= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].bUsed = false; - m_pD3DDevice->LightEnable(lightRank, false); - - m_lightUsed = 0; - for ( i=0 ; i= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].light = light; - - ProgInit(m_lightTable[lightRank].colorRed, m_lightTable[lightRank].light.dcvDiffuse.r); - ProgInit(m_lightTable[lightRank].colorGreen, m_lightTable[lightRank].light.dcvDiffuse.g); - ProgInit(m_lightTable[lightRank].colorBlue, m_lightTable[lightRank].light.dcvDiffuse.b); - - return true; -} - -// Gives the specifications of a light. - -bool CLight::GetLight(int lightRank, D3DLIGHT7 &light) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - light = m_lightTable[lightRank].light; - return true; -} - - -// Lights up or put out a light. - -bool CLight::LightEnable(int lightRank, bool bEnable) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].bEnable = bEnable; - return true; -} - - -// Specifies the type (TYPE *) items included in this light. -// This light does not light up so that this type of objects. - -bool CLight::SetLightIncluType(int lightRank, D3DTypeObj type) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].incluType = type; - return true; -} - -// Specifies the type (TYPE *) items excluded by this light. -// This light does not illuminate then ever these objects. - -bool CLight::SetLightExcluType(int lightRank, D3DTypeObj type) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].excluType = type; - return true; -} - - -// Management of the position of the light. - -bool CLight::SetLightPos(int lightRank, Math::Vector pos) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].light.dvPosition = VEC_TO_D3DVEC(pos); - return true; -} - -Math::Vector CLight::RetLightPos(int lightRank) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return Math::Vector(0.0f, 0.0f, 0.0f); - - return D3DVEC_TO_VEC(m_lightTable[lightRank].light.dvPosition); -} - - -// Management direction of the light. - -bool CLight::SetLightDir(int lightRank, Math::Vector dir) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].light.dvDirection = VEC_TO_D3DVEC(dir); - return true; -} - -Math::Vector CLight::RetLightDir(int lightRank) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return Math::Vector(0.0f, 0.0f, 0.0f); - - return D3DVEC_TO_VEC(m_lightTable[lightRank].light.dvDirection); -} - - -// Specifies the rate of change. - -bool CLight::SetLightIntensitySpeed(int lightRank, float speed) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].intensity.speed = speed; - return true; -} - -// Management of the intensity of light. - -bool CLight::SetLightIntensity(int lightRank, float value) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - ProgSet(m_lightTable[lightRank].intensity, value); - return true; -} - -float CLight::RetLightIntensity(int lightRank) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return 0.0f; - - return m_lightTable[lightRank].intensity.current; -} - - -// Specifies the rate of change. - -bool CLight::SetLightColorSpeed(int lightRank, float speed) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - m_lightTable[lightRank].colorRed.speed = speed; - m_lightTable[lightRank].colorGreen.speed = speed; - m_lightTable[lightRank].colorBlue.speed = speed; - return true; -} - -// Color management for light. - -bool CLight::SetLightColor(int lightRank, D3DCOLORVALUE color) -{ - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; - - ProgSet(m_lightTable[lightRank].colorRed, color.r); - ProgSet(m_lightTable[lightRank].colorGreen, color.g); - ProgSet(m_lightTable[lightRank].colorBlue, color.b); - return true; -} - -D3DCOLORVALUE CLight::RetLightColor(int lightRank) -{ - D3DCOLORVALUE color; - - if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) - { - color.r = 0.5f; - color.g = 0.5f; - color.b = 0.5f; - color.a = 0.5f; - return color; - } - - color.r = m_lightTable[lightRank].colorRed.current; - color.g = m_lightTable[lightRank].colorGreen.current; - color.b = m_lightTable[lightRank].colorBlue.current; - return color; -} - - -// Adjusts the color of all lights. - -void CLight::AdaptLightColor(D3DCOLORVALUE color, float factor) -{ - D3DCOLORVALUE value; - int i; - - for ( i=0 ; iRetPause() ) return; - - m_time += rTime; - - for ( i=0 ; iRetEyePt()-m_engine->RetLookatPt(); - angle = Math::RotateAngle(dir.x, dir.z); - angle += Math::PI*0.5f*i; - m_lightTable[i].light.dvDirection.x = sinf(angle*2.0f); - m_lightTable[i].light.dvDirection.z = cosf(angle*2.0f); - } - } -} - - -// Updates all the lights. - -void CLight::LightUpdate() -{ - bool bEnable; - float value; - int i; - - for ( i=0 ; iSetLight(i, &m_lightTable[i].light); - m_pD3DDevice->LightEnable(i, bEnable); - } - else - { - m_lightTable[i].light.dcvDiffuse.r = 0.0f; - m_lightTable[i].light.dcvDiffuse.g = 0.0f; - m_lightTable[i].light.dcvDiffuse.b = 0.0f; - - m_pD3DDevice->LightEnable(i, bEnable); - } - } -} - -// Updates the lights for a given type. - -void CLight::LightUpdate(D3DTypeObj type) -{ - bool bEnable; - int i; - - for ( i=0 ; iLightEnable(i, bEnable); - } - - if ( m_lightTable[i].excluType != TYPENULL ) - { - bEnable = (m_lightTable[i].excluType != type); - m_pD3DDevice->LightEnable(i, bEnable); - } - } -} - - +// * 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/. + +// light.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dengine.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/light.h" + + + + + +// Initializes a progression. + +void ProgInit(LightProg &p, float value) +{ + p.starting = value; + p.ending = value; + p.current = value; + p.progress = 0.0f; + p.speed = 100.0f; +} + +// Makes evolve a progression. + +void ProgFrame(LightProg &p, float rTime) +{ + if ( p.speed < 100.0f ) + { + if ( p.progress < 1.0f ) + { + p.progress += p.speed*rTime; + if ( p.progress > 1.0f ) + { + p.progress = 1.0f; + } + } + + p.current = (p.ending-p.starting)*p.progress + p.starting; + } + else + { + p.current = p.ending; + } +} + +// Change the current value. + +void ProgSet(LightProg &p, float value) +{ + p.starting = p.current; + p.ending = value; + p.progress = 0.0f; +} + + + + + +// Object's constructor. + +CLight::CLight(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_LIGHT, this); + + m_pD3DDevice = 0; + m_engine = engine; + + m_lightUsed = 0; + m_lightTable = (Light*)malloc(sizeof(Light)*D3DMAXLIGHT); + ZeroMemory(m_lightTable, sizeof(Light)*D3DMAXLIGHT); + + m_time = 0.0f; +} + +// Object's destructor. + +CLight::~CLight() +{ + free(m_lightTable); + m_iMan->DeleteInstance(CLASS_LIGHT, this); +} + + +void CLight::SetD3DDevice(LPDIRECT3DDEVICE7 device) +{ + m_pD3DDevice = device; +} + + +// Removes all the lights. + +void CLight::FlushLight() +{ + int i; + + for ( i=0 ; iLightEnable(i, false); + } + m_lightUsed = 0; +} + + +// Creates a new light. Returns its rank or -1 on error. + +int CLight::CreateLight() +{ + int i; + + for ( i=0 ; i= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].bUsed = false; + m_pD3DDevice->LightEnable(lightRank, false); + + m_lightUsed = 0; + for ( i=0 ; i= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].light = light; + + ProgInit(m_lightTable[lightRank].colorRed, m_lightTable[lightRank].light.dcvDiffuse.r); + ProgInit(m_lightTable[lightRank].colorGreen, m_lightTable[lightRank].light.dcvDiffuse.g); + ProgInit(m_lightTable[lightRank].colorBlue, m_lightTable[lightRank].light.dcvDiffuse.b); + + return true; +} + +// Gives the specifications of a light. + +bool CLight::GetLight(int lightRank, D3DLIGHT7 &light) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + light = m_lightTable[lightRank].light; + return true; +} + + +// Lights up or put out a light. + +bool CLight::LightEnable(int lightRank, bool bEnable) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].bEnable = bEnable; + return true; +} + + +// Specifies the type (TYPE *) items included in this light. +// This light does not light up so that this type of objects. + +bool CLight::SetLightIncluType(int lightRank, D3DTypeObj type) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].incluType = type; + return true; +} + +// Specifies the type (TYPE *) items excluded by this light. +// This light does not illuminate then ever these objects. + +bool CLight::SetLightExcluType(int lightRank, D3DTypeObj type) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].excluType = type; + return true; +} + + +// Management of the position of the light. + +bool CLight::SetLightPos(int lightRank, Math::Vector pos) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].light.dvPosition = VEC_TO_D3DVEC(pos); + return true; +} + +Math::Vector CLight::RetLightPos(int lightRank) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return Math::Vector(0.0f, 0.0f, 0.0f); + + return D3DVEC_TO_VEC(m_lightTable[lightRank].light.dvPosition); +} + + +// Management direction of the light. + +bool CLight::SetLightDir(int lightRank, Math::Vector dir) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].light.dvDirection = VEC_TO_D3DVEC(dir); + return true; +} + +Math::Vector CLight::RetLightDir(int lightRank) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return Math::Vector(0.0f, 0.0f, 0.0f); + + return D3DVEC_TO_VEC(m_lightTable[lightRank].light.dvDirection); +} + + +// Specifies the rate of change. + +bool CLight::SetLightIntensitySpeed(int lightRank, float speed) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].intensity.speed = speed; + return true; +} + +// Management of the intensity of light. + +bool CLight::SetLightIntensity(int lightRank, float value) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + ProgSet(m_lightTable[lightRank].intensity, value); + return true; +} + +float CLight::RetLightIntensity(int lightRank) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return 0.0f; + + return m_lightTable[lightRank].intensity.current; +} + + +// Specifies the rate of change. + +bool CLight::SetLightColorSpeed(int lightRank, float speed) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + m_lightTable[lightRank].colorRed.speed = speed; + m_lightTable[lightRank].colorGreen.speed = speed; + m_lightTable[lightRank].colorBlue.speed = speed; + return true; +} + +// Color management for light. + +bool CLight::SetLightColor(int lightRank, D3DCOLORVALUE color) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return false; + + ProgSet(m_lightTable[lightRank].colorRed, color.r); + ProgSet(m_lightTable[lightRank].colorGreen, color.g); + ProgSet(m_lightTable[lightRank].colorBlue, color.b); + return true; +} + +D3DCOLORVALUE CLight::RetLightColor(int lightRank) +{ + D3DCOLORVALUE color; + + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) + { + color.r = 0.5f; + color.g = 0.5f; + color.b = 0.5f; + color.a = 0.5f; + return color; + } + + color.r = m_lightTable[lightRank].colorRed.current; + color.g = m_lightTable[lightRank].colorGreen.current; + color.b = m_lightTable[lightRank].colorBlue.current; + return color; +} + + +// Adjusts the color of all lights. + +void CLight::AdaptLightColor(D3DCOLORVALUE color, float factor) +{ + D3DCOLORVALUE value; + int i; + + for ( i=0 ; iRetPause() ) return; + + m_time += rTime; + + for ( i=0 ; iRetEyePt()-m_engine->RetLookatPt(); + angle = Math::RotateAngle(dir.x, dir.z); + angle += Math::PI*0.5f*i; + m_lightTable[i].light.dvDirection.x = sinf(angle*2.0f); + m_lightTable[i].light.dvDirection.z = cosf(angle*2.0f); + } + } +} + + +// Updates all the lights. + +void CLight::LightUpdate() +{ + bool bEnable; + float value; + int i; + + for ( i=0 ; iSetLight(i, &m_lightTable[i].light); + m_pD3DDevice->LightEnable(i, bEnable); + } + else + { + m_lightTable[i].light.dcvDiffuse.r = 0.0f; + m_lightTable[i].light.dcvDiffuse.g = 0.0f; + m_lightTable[i].light.dcvDiffuse.b = 0.0f; + + m_pD3DDevice->LightEnable(i, bEnable); + } + } +} + +// Updates the lights for a given type. + +void CLight::LightUpdate(D3DTypeObj type) +{ + bool bEnable; + int i; + + for ( i=0 ; iLightEnable(i, bEnable); + } + + if ( m_lightTable[i].excluType != TYPENULL ) + { + bEnable = (m_lightTable[i].excluType != type); + m_pD3DDevice->LightEnable(i, bEnable); + } + } +} + + diff --git a/src/old/light.h b/src/old/light.h index 8291ca9..49e4e7d 100644 --- a/src/old/light.h +++ b/src/old/light.h @@ -1,109 +1,109 @@ -// * 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/. - -// light.h - -#pragma once - - -#include "old/d3dengine.h" -#include "graphics/common/color.h" - - -class CInstanceManager; -class CD3DEngine; - - -const int D3DMAXLIGHT = 100; - - -struct LightProg -{ - float starting; - float ending; - float current; - float progress; - float speed; -}; - - -struct Light -{ - char bUsed; // true -> light exists - char bEnable; // true -> light turned on - - D3DTypeObj incluType; // type of all objects included - D3DTypeObj excluType; // type of all objects excluded - - D3DLIGHT7 light; // configuration of the light - - LightProg intensity; // intensity (0 .. 1) - LightProg colorRed; - LightProg colorGreen; - LightProg colorBlue; -}; - - - -class CLight -{ -public: - CLight(CInstanceManager *iMan, CD3DEngine* engine); - virtual ~CLight(); - - void SetD3DDevice(LPDIRECT3DDEVICE7 device); - - void FlushLight(); - int CreateLight(); - bool DeleteLight(int lightRank); - bool SetLight(int lightRank, const D3DLIGHT7 &light); - bool GetLight(int lightRank, D3DLIGHT7 &light); - bool LightEnable(int lightRank, bool bEnable); - - bool SetLightIncluType(int lightRank, D3DTypeObj type); - bool SetLightExcluType(int lightRank, D3DTypeObj type); - - bool SetLightPos(int lightRank, Math::Vector pos); - Math::Vector RetLightPos(int lightRank); - - bool SetLightDir(int lightRank, Math::Vector dir); - Math::Vector RetLightDir(int lightRank); - - bool SetLightIntensitySpeed(int lightRank, float speed); - bool SetLightIntensity(int lightRank, float value); - float RetLightIntensity(int lightRank); - void AdaptLightColor(D3DCOLORVALUE color, float factor); - - bool SetLightColorSpeed(int lightRank, float speed); - bool SetLightColor(int lightRank, D3DCOLORVALUE color); - D3DCOLORVALUE RetLightColor(int lightRank); - - void FrameLight(float rTime); - void LightUpdate(); - void LightUpdate(D3DTypeObj type); - -protected: - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - LPDIRECT3DDEVICE7 m_pD3DDevice; - - float m_time; - int m_lightUsed; - Light* m_lightTable; -}; - +// * 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/. + +// light.h + +#pragma once + + +#include "old/d3dengine.h" +#include "graphics/common/color.h" + + +class CInstanceManager; +class CD3DEngine; + + +const int D3DMAXLIGHT = 100; + + +struct LightProg +{ + float starting; + float ending; + float current; + float progress; + float speed; +}; + + +struct Light +{ + char bUsed; // true -> light exists + char bEnable; // true -> light turned on + + D3DTypeObj incluType; // type of all objects included + D3DTypeObj excluType; // type of all objects excluded + + D3DLIGHT7 light; // configuration of the light + + LightProg intensity; // intensity (0 .. 1) + LightProg colorRed; + LightProg colorGreen; + LightProg colorBlue; +}; + + + +class CLight +{ +public: + CLight(CInstanceManager *iMan, CD3DEngine* engine); + virtual ~CLight(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + + void FlushLight(); + int CreateLight(); + bool DeleteLight(int lightRank); + bool SetLight(int lightRank, const D3DLIGHT7 &light); + bool GetLight(int lightRank, D3DLIGHT7 &light); + bool LightEnable(int lightRank, bool bEnable); + + bool SetLightIncluType(int lightRank, D3DTypeObj type); + bool SetLightExcluType(int lightRank, D3DTypeObj type); + + bool SetLightPos(int lightRank, Math::Vector pos); + Math::Vector RetLightPos(int lightRank); + + bool SetLightDir(int lightRank, Math::Vector dir); + Math::Vector RetLightDir(int lightRank); + + bool SetLightIntensitySpeed(int lightRank, float speed); + bool SetLightIntensity(int lightRank, float value); + float RetLightIntensity(int lightRank); + void AdaptLightColor(D3DCOLORVALUE color, float factor); + + bool SetLightColorSpeed(int lightRank, float speed); + bool SetLightColor(int lightRank, D3DCOLORVALUE color); + D3DCOLORVALUE RetLightColor(int lightRank); + + void FrameLight(float rTime); + void LightUpdate(); + void LightUpdate(D3DTypeObj type); + +protected: + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + LPDIRECT3DDEVICE7 m_pD3DDevice; + + float m_time; + int m_lightUsed; + Light* m_lightTable; +}; + diff --git a/src/old/math3d.cpp b/src/old/math3d.cpp index 3b5f9dd..5282ac1 100644 --- a/src/old/math3d.cpp +++ b/src/old/math3d.cpp @@ -1,1197 +1,1197 @@ -// * 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/. - -// math3d.cpp - -#define STRICT -#define D3D_OVERLOADS - -#include -#include -#include - -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "old/math3d.h" - - -// Old defines -#define MATH3D_PI 3.14159265358979323846f -#define MATH3D_CHOUIA 1e-6f -#define MATH3D_BEAUCOUP 1e6f - - -// Old FPOINT struct -struct FPOINT -{ - float x; - float y; - - FPOINT() { } - FPOINT(float _x, float _y) - { - x = _x; - y = _y; - } -}; - - -// === Functions already replaced by new implementation === - -//>>> func.h IsEqual() -bool IsEqual(float a, float b); - -//>>> func.h Min() -float Min(float a, float b); -float Min(float a, float b, float c); -float Min(float a, float b, float c, float d); -float Min(float a, float b, float c, float d, float e); - -//>>> func.h Max() -float Max(float a, float b); -float Max(float a, float b, float c); -float Max(float a, float b, float c, float d); -float Max(float a, float b, float c, float d, float e); - -//>>> func.h Norm() -float Norm(float a); -//>>> fabs() -float Abs(float a); - -//>>> func.h Swap() -void Swap(int &a, int &b); -//>>> func.h Swap() -void Swap(float &a, float &b); -//>>> point.h Swap() -void Swap(FPOINT &a, FPOINT &b); - -//>>> func.h Mod() -float Mod(float a, float m); -//>>> func.h NormAngle() -float NormAngle(float angle); -//>>> func.h TestAngle() -bool TestAngle(float angle, float min, float max); - -//>>> geometry.h RotateAngle() -float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2); - -//>>> func.h Direction() -float Direction(float a, float g); - -//>>> geometry.h RotatePoint() -FPOINT RotatePoint(FPOINT center, float angle, FPOINT p); -//>>> geometry.h RotatePoint() -FPOINT RotatePoint(float angle, FPOINT p); -//>>> geometry.h RotatePoint() -FPOINT RotatePoint(float angle, float dist); -//>>> geometry.h RotateAngle() -float RotateAngle(float x, float y); -//>>> geometry.h RotatePoint() -void RotatePoint(float cx, float cy, float angle, float &px, float &py); - -//>>> geometry.h IsInsideTriangle() -bool IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p); - -//>>> point.h Distance() -float Length(FPOINT a, FPOINT b); - -//>>> point.h Point::Length() -float Length(float x, float y); - -//>>> func.h Rand() -float Rand(); -//>>> func.h Neutral() -float Neutral(float value, float dead); - -//>>> func.h PropAngle() -float Prop(int a, int b, float p); -//>>> func.h Smooth() -float Smooth(float actual, float hope, float time); -//>>> func.h Bounce() -float Bounce(float progress, float middle=0.3f, float bounce=0.4f); - - -//>>> geometry.h SegmentPoint() -D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist); - -//>>> geometry.h Intersect() -bool Intersect(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR d, D3DVECTOR e, D3DVECTOR &i); - -//>>> geometry.h IntersectY() -bool IntersectY(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR &p); - -//>>> geometry.h RotatePoint() -void RotatePoint(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p); - -//>>> geometry.h RotatePoint2() -void RotatePoint2(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p); - -//>>> geometry.h RotateView() -D3DVECTOR RotateView(D3DVECTOR center, float angleH, float angleV, float dist); - -//>>> geometry.h LookatPoint() -D3DVECTOR LookatPoint( D3DVECTOR eye, float angleH, float angleV, float length ); - -//>>> vector.h Vector::Length() -float Length(const D3DVECTOR &u); - -//>>> vector.h Distance() -float Length(const D3DVECTOR &a, const D3DVECTOR &b); - -//>>> geometry.h DistanceProjected() -float Length2d(const D3DVECTOR &a, const D3DVECTOR &b); - -//>>> vector.h Angle() -float Angle( D3DVECTOR u, D3DVECTOR v ); - -//>>> vector.h CrossProduct() -D3DVECTOR Cross( D3DVECTOR u, D3DVECTOR v ); - -//>>> geometry.h NormalToPlane() -D3DVECTOR ComputeNormal( D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3 ); - -//>>> geometry.h Transform() -D3DVECTOR Transform(const D3DMATRIX &m, D3DVECTOR p); - -//>>> geometry.h Projection() -D3DVECTOR Projection(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &p); - -//>>> geometry.h DistanceToPlane() -float DistancePlanPoint(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &c, const D3DVECTOR &p); - -//>>> geometry.h IsSamePlane() -bool IsSamePlane(D3DVECTOR *plan1, D3DVECTOR *plan2); - -//>>> geometry.h LoadRotationXZYMatrix() -void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle); - -//>>> geometry.h LoadRotationZXYMatrix() -void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle); - - - -// UNUSED -float MidPoint(FPOINT a, FPOINT b, float px); - -// UNUSED -bool LineFunction(FPOINT p1, FPOINT p2, float &a, float &b); - - - - -// Returns true if two numbers are nearly equal. - -bool IsEqual(float a, float b) -{ - return Abs(a-b) < MATH3D_CHOUIA; -} - - -// Returns the minimum value. - -float Min(float a, float b) -{ - if ( a <= b ) return a; - else return b; -} - -float Min(float a, float b, float c) -{ - return Min( Min(a,b), c ); -} - -float Min(float a, float b, float c, float d) -{ - return Min( Min(a,b), Min(c,d) ); -} - -float Min(float a, float b, float c, float d, float e) -{ - return Min( Min(a,b), Min(c,d), e ); -} - - -// Returns the maximum value. - -float Max(float a, float b) -{ - if ( a >= b ) return a; - else return b; -} - -float Max(float a, float b, float c) -{ - return Max( Max(a,b), c ); -} - -float Max(float a, float b, float c, float d) -{ - return Max( Max(a,b), Max(c,d) ); -} - -float Max(float a, float b, float c, float d, float e) -{ - return Max( Max(a,b), Max(c,d), e ); -} - - -// Returns the normalized value (0 .. 1). - -float Norm(float a) -{ - if ( a < 0.0f ) return 0.0f; - if ( a > 1.0f ) return 1.0f; - return a; -} - - -// Returns the absolute value of a number. - -float Abs(float a) -{ - return (float)fabs(a); -} - - -// Swaps two integers. - -void Swap(int &a, int &b) -{ - int c; - - c = a; - a = b; - b = c; -} - -// Swaps two real numbers. - -void Swap(float &a, float &b) -{ - float c; - - c = a; - a = b; - b = c; -} - -// Permutes two points. - -void Swap(FPOINT &a, FPOINT &b) -{ - FPOINT c; - - c = a; - a = b; - b = c; -} - -// Returns the modulo of a floating point number. -// Mod(8.1, 4) = 0.1 -// Mod(n, 1) = fractional part of n - -float Mod(float a, float m) -{ - return a - ((int)(a/m))*m; -} - -// Returns a normalized angle, that is in other words between 0 and 2 * MATH3D_PI. - -float NormAngle(float angle) -{ - angle = Mod(angle, MATH3D_PI*2.0f); - if ( angle < 0.0f ) - { - return MATH3D_PI*2.0f + angle; - } - else - { - return angle; - } -} - -// Test if a angle is between two terminals. - -bool TestAngle(float angle, float min, float max) -{ - angle = NormAngle(angle); - min = NormAngle(min); - max = NormAngle(max); - - if ( min > max ) - { - return ( angle <= max || angle >= min ); - } - else - { - return ( angle >= min && angle <= max ); - } -} - - -// Calculates the angle to rotate the angle a to the angle g. -// A positive angle is counterclockwise (CCW). - -float Direction(float a, float g) -{ - a = NormAngle(a); - g = NormAngle(g); - - if ( a < g ) - { - if ( a+MATH3D_PI*2.0f-g < g-a ) a += MATH3D_PI*2.0f; - } - else - { - if ( g+MATH3D_PI*2.0f-a < a-g ) g += MATH3D_PI*2.0f; - } - return (g-a); -} - - -// Rotates a point around a center. -// The angle is in radians. -// A positive angle is counterclockwise (CCW). - -FPOINT RotatePoint(FPOINT center, float angle, FPOINT p) -{ - FPOINT a, b; - - a.x = p.x-center.x; - a.y = p.y-center.y; - - b.x = a.x*cosf(angle) - a.y*sinf(angle); - b.y = a.x*sinf(angle) + a.y*cosf(angle); - - b.x += center.x; - b.y += center.y; - return b; -} - -// Rotates a point around the origin. -// The angle is in radians. -// A positive angle is counterclockwise (CCW). - -FPOINT RotatePoint(float angle, FPOINT p) -{ - FPOINT a; - - a.x = p.x*cosf(angle) - p.y*sinf(angle); - a.y = p.x*sinf(angle) + p.y*cosf(angle); - - return a; -} - -// Rotates a vector (dist, 0). -// The angle is in radians. -// A positive angle is counterclockwise (CCW). - -FPOINT RotatePoint(float angle, float dist) -{ - FPOINT a; - - a.x = dist*cosf(angle); - a.y = dist*sinf(angle); - - return a; -} - -// Calculates the angle of a right triangle. -// The angle is counterclockwise (CCW), between 0 and 2 * MATH3D_PI. -// For an angle clockwise (CW), just go ahead. -// -// ^ -// | -// y o----o -// | / | -// |/)a | -// ----o----o--> -// | x -// | - -float RotateAngle(float x, float y) -{ -#if 1 - if ( x == 0.0f && y == 0.0f ) return 0.0f; - - if ( x >= 0.0f ) - { - if ( y >= 0.0f ) - { - if ( x > y ) return atanf(y/x); - else return MATH3D_PI*0.5f - atanf(x/y); - } - else - { - if ( x > -y ) return MATH3D_PI*2.0f + atanf(y/x); - else return MATH3D_PI*1.5f - atanf(x/y); - } - } - else - { - if ( y >= 0.0f ) - { - if ( -x > y ) return MATH3D_PI*1.0f + atanf(y/x); - else return MATH3D_PI*0.5f - atanf(x/y); - } - else - { - if ( -x > -y ) return MATH3D_PI*1.0f + atanf(y/x); - else return MATH3D_PI*1.5f - atanf(x/y); - } - } -#else - float angle; - - if ( x == 0.0f ) - { - if ( y > 0.0f ) - { - return 90.0f*MATH3D_PI/180.0f; - } - else - { - return 270.0f*MATH3D_PI/180.0f; - } - } - else - { - angle = atanf(y/x); - if ( x < 0.0f ) - { - angle += MATH3D_PI; - } - return angle; - } -#endif -} - -// Calculates the angle between two points and one center. -// The angle is in radians. -// A positive angle is counterclockwise (CCW). - -float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2) -{ - float a1, a2, a; - - if ( p1.x == center.x && - p1.y == center.y ) return 0; - - if ( p2.x == center.x && - p2.y == center.y ) return 0; - - a1 = asinf((p1.y-center.y)/Length(p1,center)); - a2 = asinf((p2.y-center.y)/Length(p2,center)); - - if ( p1.x < center.x ) a1 = MATH3D_PI-a1; - if ( p2.x < center.x ) a2 = MATH3D_PI-a2; - - a = a2-a1; - if ( a < 0 ) a += MATH3D_PI*2; - return a; -} - -// Returns py up on the line ab. - -float MidPoint(FPOINT a, FPOINT b, float px) -{ - if ( Abs(a.x-b.x) < MATH3D_CHOUIA ) - { - if ( a.y < b.y ) return MATH3D_BEAUCOUP; - else return -MATH3D_BEAUCOUP; - } - return (b.y-a.y)*(px-a.x)/(b.x-a.x)+a.y; -} - -// Advance "dist" along the segment p1-p2. - -D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist) -{ - return p1+Normalize(p2-p1)*dist; -} - -// Check if a point is inside a triangle. - -bool IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p) -{ - float n, m; - - if ( p.x < a.x && p.x < b.x && p.x < c.x ) return false; - if ( p.x > a.x && p.x > b.x && p.x > c.x ) return false; - if ( p.y < a.y && p.y < b.y && p.y < c.y ) return false; - if ( p.y > a.y && p.y > b.y && p.y > c.y ) return false; - - if ( a.x > b.x ) Swap(a,b); - if ( a.x > c.x ) Swap(a,c); - if ( c.x < a.x ) Swap(c,a); - if ( c.x < b.x ) Swap(c,b); - - n = MidPoint(a, b, p.x); - m = MidPoint(a, c, p.x); - if ( (n>p.y||p.y>m) && (np.y||p.y>m) && (n= 100 ) break; - } - } - - sum.x = 0; - sum.y = 0; - sum.z = 0; - for ( j=0 ; j 0.1f || - Abs(n1.y-n2.y) > 0.1f || - Abs(n1.z-n2.z) > 0.1f ) return false; - - dist = DistancePlanPoint(plan1[0], plan1[1], plan1[2], plan2[0]); - if ( dist > 0.1f ) return false; - - return true; -} - - -// Calculates the matrix to make three rotations in the X, Y and Z -// >>>>>> OPTIMIZING!!! - -void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle) -{ - D3DMATRIX temp; - - D3DUtil_SetRotateXMatrix(temp, angle.x); - D3DUtil_SetRotateZMatrix(mat, angle.z); - D3DMath_MatrixMultiply(mat, mat, temp); - D3DUtil_SetRotateYMatrix(temp, angle.y); - D3DMath_MatrixMultiply(mat, mat, temp); // X-Z-Y -} - -// Calculates the matrix to make three rotations in the order Z, X and Y. -// >>>>>> OPTIMIZING!!! - -void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle) -{ - D3DMATRIX temp; - - D3DUtil_SetRotateZMatrix(temp, angle.z); - D3DUtil_SetRotateXMatrix(mat, angle.x); - D3DMath_MatrixMultiply(mat, mat, temp); - D3DUtil_SetRotateYMatrix(temp, angle.y); - D3DMath_MatrixMultiply(mat, mat, temp); // Z-X-Y -} - - -// Returns a random value between 0 and 1. - -float Rand() -{ - return (float)rand()/RAND_MAX; -} - - -// Managing the dead zone of a joystick. - -// in: -1 0 1 -// --|-------|----o----|-------|--> -// <----> -// dead -// out: -1 0 0 1 - -float Neutral(float value, float dead) -{ - if ( Abs(value) <= dead ) - { - return 0.0f; - } - else - { - if ( value > 0.0f ) return (value-dead)/(1.0f-dead); - else return (value+dead)/(1.0f-dead); - } -} - - -// Calculates a value (radians) proportional between a and b (degrees). - -float Prop(int a, int b, float p) -{ - float aa, bb; - - aa = (float)a*MATH3D_PI/180.0f; - bb = (float)b*MATH3D_PI/180.0f; - - return aa+p*(bb-aa); -} - -// Gently advanced a desired value from its current value. -// Over time, the greater the progression is rapid. - -float Smooth(float actual, float hope, float time) -{ - float futur; - - futur = actual + (hope-actual)*time; - - if ( hope > actual ) - { - if ( futur > hope ) futur = hope; - } - if ( hope < actual ) - { - if ( futur < hope ) futur = hope; - } - - return futur; -} - - -// Bounces any movement. - -// out -// | -// 1+------o-------o--- -// | o | o o | | bounce -// | o | o---|--- -// | o | | -// | o | | -// -o------|-------+----> progress -// 0| | 1 -// |<---->|middle - -float Bounce(float progress, float middle, float bounce) -{ - if ( progress < middle ) - { - progress = progress/middle; // 0..1 - return 0.5f+sinf(progress*MATH3D_PI-MATH3D_PI/2.0f)/2.0f; - } - else - { - progress = (progress-middle)/(1.0f-middle); // 0..1 - return (1.0f-bounce/2.0f)+sinf((0.5f+progress*2.0f)*MATH3D_PI)*(bounce/2.0f); - } -} - - -// Returns the color corresponding D3DCOLOR. - -D3DCOLOR RetColor(float intensity) -{ - D3DCOLOR color; - - if ( intensity <= 0.0f ) return 0x00000000; - if ( intensity >= 1.0f ) return 0xffffffff; - - color = (int)(intensity*255.0f)<<24; - color |= (int)(intensity*255.0f)<<16; - color |= (int)(intensity*255.0f)<<8; - color |= (int)(intensity*255.0f); - - return color; -} - -// Returns the color corresponding D3DCOLOR. - -D3DCOLOR RetColor(D3DCOLORVALUE intensity) -{ - D3DCOLOR color; - - color = (int)(intensity.a*255.0f)<<24; - color |= (int)(intensity.r*255.0f)<<16; - color |= (int)(intensity.g*255.0f)<<8; - color |= (int)(intensity.b*255.0f); - - return color; -} - -// Returns the color corresponding D3DCOLORVALUE. - -D3DCOLORVALUE RetColor(D3DCOLOR intensity) -{ - D3DCOLORVALUE color; - - color.r = (float)((intensity>>16)&0xff)/256.0f; - color.g = (float)((intensity>>8 )&0xff)/256.0f; - color.b = (float)((intensity>>0 )&0xff)/256.0f; - color.a = (float)((intensity>>24)&0xff)/256.0f; - - return color; -} - - -// RGB to HSV conversion. - -void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest) -{ - float min, max, delta; - - min = Min(src.r, src.g, src.b); - max = Max(src.r, src.g, src.b); - - dest.v = max; // intensity - - if ( max == 0.0f ) - { - dest.s = 0.0f; // saturation - dest.h = 0.0f; // undefined color! - } - else - { - delta = max-min; - dest.s = delta/max; // saturation - - if ( src.r == max ) // between yellow & magenta - { - dest.h = (src.g-src.b)/delta; - } - else if ( src.g == max ) // between cyan & yellow - { - dest.h = 2.0f+(src.b-src.r)/delta; - } - else // between magenta & cyan - { - dest.h = 4.0f+(src.r-src.g)/delta; - } - - dest.h *= 60.0f; // in degrees - if ( dest.h < 0.0f ) dest.h += 360.0f; - dest.h /= 360.0f; // 0..1 - } -} - -// HSV to RGB conversion. - -void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest) -{ - int i; - float f,v,p,q,t; - - src.h = Norm(src.h)*360.0f; - src.s = Norm(src.s); - src.v = Norm(src.v); - - if ( src.s == 0.0f ) // zero saturation? - { - dest.r = src.v; - dest.g = src.v; - dest.b = src.v; // gray - } - else - { - if ( src.h == 360.0f ) src.h = 0.0f; - src.h /= 60.0f; - i = (int)src.h; // integer part (0 .. 5) - f = src.h-i; // fractional part - - v = src.v; - p = src.v*(1.0f-src.s); - q = src.v*(1.0f-(src.s*f)); - t = src.v*(1.0f-(src.s*(1.0f-f))); - - switch (i) - { - case 0: dest.r=v; dest.g=t; dest.b=p; break; - case 1: dest.r=q; dest.g=v; dest.b=p; break; - case 2: dest.r=p; dest.g=v; dest.b=t; break; - case 3: dest.r=p; dest.g=q; dest.b=v; break; - case 4: dest.r=t; dest.g=p; dest.b=v; break; - case 5: dest.r=v; dest.g=p; dest.b=q; break; - } - } -} - +// * 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/. + +// math3d.cpp + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "old/math3d.h" + + +// Old defines +#define MATH3D_PI 3.14159265358979323846f +#define MATH3D_CHOUIA 1e-6f +#define MATH3D_BEAUCOUP 1e6f + + +// Old FPOINT struct +struct FPOINT +{ + float x; + float y; + + FPOINT() { } + FPOINT(float _x, float _y) + { + x = _x; + y = _y; + } +}; + + +// === Functions already replaced by new implementation === + +//>>> func.h IsEqual() +bool IsEqual(float a, float b); + +//>>> func.h Min() +float Min(float a, float b); +float Min(float a, float b, float c); +float Min(float a, float b, float c, float d); +float Min(float a, float b, float c, float d, float e); + +//>>> func.h Max() +float Max(float a, float b); +float Max(float a, float b, float c); +float Max(float a, float b, float c, float d); +float Max(float a, float b, float c, float d, float e); + +//>>> func.h Norm() +float Norm(float a); +//>>> fabs() +float Abs(float a); + +//>>> func.h Swap() +void Swap(int &a, int &b); +//>>> func.h Swap() +void Swap(float &a, float &b); +//>>> point.h Swap() +void Swap(FPOINT &a, FPOINT &b); + +//>>> func.h Mod() +float Mod(float a, float m); +//>>> func.h NormAngle() +float NormAngle(float angle); +//>>> func.h TestAngle() +bool TestAngle(float angle, float min, float max); + +//>>> geometry.h RotateAngle() +float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2); + +//>>> func.h Direction() +float Direction(float a, float g); + +//>>> geometry.h RotatePoint() +FPOINT RotatePoint(FPOINT center, float angle, FPOINT p); +//>>> geometry.h RotatePoint() +FPOINT RotatePoint(float angle, FPOINT p); +//>>> geometry.h RotatePoint() +FPOINT RotatePoint(float angle, float dist); +//>>> geometry.h RotateAngle() +float RotateAngle(float x, float y); +//>>> geometry.h RotatePoint() +void RotatePoint(float cx, float cy, float angle, float &px, float &py); + +//>>> geometry.h IsInsideTriangle() +bool IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p); + +//>>> point.h Distance() +float Length(FPOINT a, FPOINT b); + +//>>> point.h Point::Length() +float Length(float x, float y); + +//>>> func.h Rand() +float Rand(); +//>>> func.h Neutral() +float Neutral(float value, float dead); + +//>>> func.h PropAngle() +float Prop(int a, int b, float p); +//>>> func.h Smooth() +float Smooth(float actual, float hope, float time); +//>>> func.h Bounce() +float Bounce(float progress, float middle=0.3f, float bounce=0.4f); + + +//>>> geometry.h SegmentPoint() +D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist); + +//>>> geometry.h Intersect() +bool Intersect(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR d, D3DVECTOR e, D3DVECTOR &i); + +//>>> geometry.h IntersectY() +bool IntersectY(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR &p); + +//>>> geometry.h RotatePoint() +void RotatePoint(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p); + +//>>> geometry.h RotatePoint2() +void RotatePoint2(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p); + +//>>> geometry.h RotateView() +D3DVECTOR RotateView(D3DVECTOR center, float angleH, float angleV, float dist); + +//>>> geometry.h LookatPoint() +D3DVECTOR LookatPoint( D3DVECTOR eye, float angleH, float angleV, float length ); + +//>>> vector.h Vector::Length() +float Length(const D3DVECTOR &u); + +//>>> vector.h Distance() +float Length(const D3DVECTOR &a, const D3DVECTOR &b); + +//>>> geometry.h DistanceProjected() +float Length2d(const D3DVECTOR &a, const D3DVECTOR &b); + +//>>> vector.h Angle() +float Angle( D3DVECTOR u, D3DVECTOR v ); + +//>>> vector.h CrossProduct() +D3DVECTOR Cross( D3DVECTOR u, D3DVECTOR v ); + +//>>> geometry.h NormalToPlane() +D3DVECTOR ComputeNormal( D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3 ); + +//>>> geometry.h Transform() +D3DVECTOR Transform(const D3DMATRIX &m, D3DVECTOR p); + +//>>> geometry.h Projection() +D3DVECTOR Projection(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &p); + +//>>> geometry.h DistanceToPlane() +float DistancePlanPoint(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &c, const D3DVECTOR &p); + +//>>> geometry.h IsSamePlane() +bool IsSamePlane(D3DVECTOR *plan1, D3DVECTOR *plan2); + +//>>> geometry.h LoadRotationXZYMatrix() +void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle); + +//>>> geometry.h LoadRotationZXYMatrix() +void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle); + + + +// UNUSED +float MidPoint(FPOINT a, FPOINT b, float px); + +// UNUSED +bool LineFunction(FPOINT p1, FPOINT p2, float &a, float &b); + + + + +// Returns true if two numbers are nearly equal. + +bool IsEqual(float a, float b) +{ + return Abs(a-b) < MATH3D_CHOUIA; +} + + +// Returns the minimum value. + +float Min(float a, float b) +{ + if ( a <= b ) return a; + else return b; +} + +float Min(float a, float b, float c) +{ + return Min( Min(a,b), c ); +} + +float Min(float a, float b, float c, float d) +{ + return Min( Min(a,b), Min(c,d) ); +} + +float Min(float a, float b, float c, float d, float e) +{ + return Min( Min(a,b), Min(c,d), e ); +} + + +// Returns the maximum value. + +float Max(float a, float b) +{ + if ( a >= b ) return a; + else return b; +} + +float Max(float a, float b, float c) +{ + return Max( Max(a,b), c ); +} + +float Max(float a, float b, float c, float d) +{ + return Max( Max(a,b), Max(c,d) ); +} + +float Max(float a, float b, float c, float d, float e) +{ + return Max( Max(a,b), Max(c,d), e ); +} + + +// Returns the normalized value (0 .. 1). + +float Norm(float a) +{ + if ( a < 0.0f ) return 0.0f; + if ( a > 1.0f ) return 1.0f; + return a; +} + + +// Returns the absolute value of a number. + +float Abs(float a) +{ + return (float)fabs(a); +} + + +// Swaps two integers. + +void Swap(int &a, int &b) +{ + int c; + + c = a; + a = b; + b = c; +} + +// Swaps two real numbers. + +void Swap(float &a, float &b) +{ + float c; + + c = a; + a = b; + b = c; +} + +// Permutes two points. + +void Swap(FPOINT &a, FPOINT &b) +{ + FPOINT c; + + c = a; + a = b; + b = c; +} + +// Returns the modulo of a floating point number. +// Mod(8.1, 4) = 0.1 +// Mod(n, 1) = fractional part of n + +float Mod(float a, float m) +{ + return a - ((int)(a/m))*m; +} + +// Returns a normalized angle, that is in other words between 0 and 2 * MATH3D_PI. + +float NormAngle(float angle) +{ + angle = Mod(angle, MATH3D_PI*2.0f); + if ( angle < 0.0f ) + { + return MATH3D_PI*2.0f + angle; + } + else + { + return angle; + } +} + +// Test if a angle is between two terminals. + +bool TestAngle(float angle, float min, float max) +{ + angle = NormAngle(angle); + min = NormAngle(min); + max = NormAngle(max); + + if ( min > max ) + { + return ( angle <= max || angle >= min ); + } + else + { + return ( angle >= min && angle <= max ); + } +} + + +// Calculates the angle to rotate the angle a to the angle g. +// A positive angle is counterclockwise (CCW). + +float Direction(float a, float g) +{ + a = NormAngle(a); + g = NormAngle(g); + + if ( a < g ) + { + if ( a+MATH3D_PI*2.0f-g < g-a ) a += MATH3D_PI*2.0f; + } + else + { + if ( g+MATH3D_PI*2.0f-a < a-g ) g += MATH3D_PI*2.0f; + } + return (g-a); +} + + +// Rotates a point around a center. +// The angle is in radians. +// A positive angle is counterclockwise (CCW). + +FPOINT RotatePoint(FPOINT center, float angle, FPOINT p) +{ + FPOINT a, b; + + a.x = p.x-center.x; + a.y = p.y-center.y; + + b.x = a.x*cosf(angle) - a.y*sinf(angle); + b.y = a.x*sinf(angle) + a.y*cosf(angle); + + b.x += center.x; + b.y += center.y; + return b; +} + +// Rotates a point around the origin. +// The angle is in radians. +// A positive angle is counterclockwise (CCW). + +FPOINT RotatePoint(float angle, FPOINT p) +{ + FPOINT a; + + a.x = p.x*cosf(angle) - p.y*sinf(angle); + a.y = p.x*sinf(angle) + p.y*cosf(angle); + + return a; +} + +// Rotates a vector (dist, 0). +// The angle is in radians. +// A positive angle is counterclockwise (CCW). + +FPOINT RotatePoint(float angle, float dist) +{ + FPOINT a; + + a.x = dist*cosf(angle); + a.y = dist*sinf(angle); + + return a; +} + +// Calculates the angle of a right triangle. +// The angle is counterclockwise (CCW), between 0 and 2 * MATH3D_PI. +// For an angle clockwise (CW), just go ahead. +// +// ^ +// | +// y o----o +// | / | +// |/)a | +// ----o----o--> +// | x +// | + +float RotateAngle(float x, float y) +{ +#if 1 + if ( x == 0.0f && y == 0.0f ) return 0.0f; + + if ( x >= 0.0f ) + { + if ( y >= 0.0f ) + { + if ( x > y ) return atanf(y/x); + else return MATH3D_PI*0.5f - atanf(x/y); + } + else + { + if ( x > -y ) return MATH3D_PI*2.0f + atanf(y/x); + else return MATH3D_PI*1.5f - atanf(x/y); + } + } + else + { + if ( y >= 0.0f ) + { + if ( -x > y ) return MATH3D_PI*1.0f + atanf(y/x); + else return MATH3D_PI*0.5f - atanf(x/y); + } + else + { + if ( -x > -y ) return MATH3D_PI*1.0f + atanf(y/x); + else return MATH3D_PI*1.5f - atanf(x/y); + } + } +#else + float angle; + + if ( x == 0.0f ) + { + if ( y > 0.0f ) + { + return 90.0f*MATH3D_PI/180.0f; + } + else + { + return 270.0f*MATH3D_PI/180.0f; + } + } + else + { + angle = atanf(y/x); + if ( x < 0.0f ) + { + angle += MATH3D_PI; + } + return angle; + } +#endif +} + +// Calculates the angle between two points and one center. +// The angle is in radians. +// A positive angle is counterclockwise (CCW). + +float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2) +{ + float a1, a2, a; + + if ( p1.x == center.x && + p1.y == center.y ) return 0; + + if ( p2.x == center.x && + p2.y == center.y ) return 0; + + a1 = asinf((p1.y-center.y)/Length(p1,center)); + a2 = asinf((p2.y-center.y)/Length(p2,center)); + + if ( p1.x < center.x ) a1 = MATH3D_PI-a1; + if ( p2.x < center.x ) a2 = MATH3D_PI-a2; + + a = a2-a1; + if ( a < 0 ) a += MATH3D_PI*2; + return a; +} + +// Returns py up on the line ab. + +float MidPoint(FPOINT a, FPOINT b, float px) +{ + if ( Abs(a.x-b.x) < MATH3D_CHOUIA ) + { + if ( a.y < b.y ) return MATH3D_BEAUCOUP; + else return -MATH3D_BEAUCOUP; + } + return (b.y-a.y)*(px-a.x)/(b.x-a.x)+a.y; +} + +// Advance "dist" along the segment p1-p2. + +D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist) +{ + return p1+Normalize(p2-p1)*dist; +} + +// Check if a point is inside a triangle. + +bool IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p) +{ + float n, m; + + if ( p.x < a.x && p.x < b.x && p.x < c.x ) return false; + if ( p.x > a.x && p.x > b.x && p.x > c.x ) return false; + if ( p.y < a.y && p.y < b.y && p.y < c.y ) return false; + if ( p.y > a.y && p.y > b.y && p.y > c.y ) return false; + + if ( a.x > b.x ) Swap(a,b); + if ( a.x > c.x ) Swap(a,c); + if ( c.x < a.x ) Swap(c,a); + if ( c.x < b.x ) Swap(c,b); + + n = MidPoint(a, b, p.x); + m = MidPoint(a, c, p.x); + if ( (n>p.y||p.y>m) && (np.y||p.y>m) && (n= 100 ) break; + } + } + + sum.x = 0; + sum.y = 0; + sum.z = 0; + for ( j=0 ; j 0.1f || + Abs(n1.y-n2.y) > 0.1f || + Abs(n1.z-n2.z) > 0.1f ) return false; + + dist = DistancePlanPoint(plan1[0], plan1[1], plan1[2], plan2[0]); + if ( dist > 0.1f ) return false; + + return true; +} + + +// Calculates the matrix to make three rotations in the X, Y and Z +// >>>>>> OPTIMIZING!!! + +void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle) +{ + D3DMATRIX temp; + + D3DUtil_SetRotateXMatrix(temp, angle.x); + D3DUtil_SetRotateZMatrix(mat, angle.z); + D3DMath_MatrixMultiply(mat, mat, temp); + D3DUtil_SetRotateYMatrix(temp, angle.y); + D3DMath_MatrixMultiply(mat, mat, temp); // X-Z-Y +} + +// Calculates the matrix to make three rotations in the order Z, X and Y. +// >>>>>> OPTIMIZING!!! + +void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle) +{ + D3DMATRIX temp; + + D3DUtil_SetRotateZMatrix(temp, angle.z); + D3DUtil_SetRotateXMatrix(mat, angle.x); + D3DMath_MatrixMultiply(mat, mat, temp); + D3DUtil_SetRotateYMatrix(temp, angle.y); + D3DMath_MatrixMultiply(mat, mat, temp); // Z-X-Y +} + + +// Returns a random value between 0 and 1. + +float Rand() +{ + return (float)rand()/RAND_MAX; +} + + +// Managing the dead zone of a joystick. + +// in: -1 0 1 +// --|-------|----o----|-------|--> +// <----> +// dead +// out: -1 0 0 1 + +float Neutral(float value, float dead) +{ + if ( Abs(value) <= dead ) + { + return 0.0f; + } + else + { + if ( value > 0.0f ) return (value-dead)/(1.0f-dead); + else return (value+dead)/(1.0f-dead); + } +} + + +// Calculates a value (radians) proportional between a and b (degrees). + +float Prop(int a, int b, float p) +{ + float aa, bb; + + aa = (float)a*MATH3D_PI/180.0f; + bb = (float)b*MATH3D_PI/180.0f; + + return aa+p*(bb-aa); +} + +// Gently advanced a desired value from its current value. +// Over time, the greater the progression is rapid. + +float Smooth(float actual, float hope, float time) +{ + float futur; + + futur = actual + (hope-actual)*time; + + if ( hope > actual ) + { + if ( futur > hope ) futur = hope; + } + if ( hope < actual ) + { + if ( futur < hope ) futur = hope; + } + + return futur; +} + + +// Bounces any movement. + +// out +// | +// 1+------o-------o--- +// | o | o o | | bounce +// | o | o---|--- +// | o | | +// | o | | +// -o------|-------+----> progress +// 0| | 1 +// |<---->|middle + +float Bounce(float progress, float middle, float bounce) +{ + if ( progress < middle ) + { + progress = progress/middle; // 0..1 + return 0.5f+sinf(progress*MATH3D_PI-MATH3D_PI/2.0f)/2.0f; + } + else + { + progress = (progress-middle)/(1.0f-middle); // 0..1 + return (1.0f-bounce/2.0f)+sinf((0.5f+progress*2.0f)*MATH3D_PI)*(bounce/2.0f); + } +} + + +// Returns the color corresponding D3DCOLOR. + +D3DCOLOR RetColor(float intensity) +{ + D3DCOLOR color; + + if ( intensity <= 0.0f ) return 0x00000000; + if ( intensity >= 1.0f ) return 0xffffffff; + + color = (int)(intensity*255.0f)<<24; + color |= (int)(intensity*255.0f)<<16; + color |= (int)(intensity*255.0f)<<8; + color |= (int)(intensity*255.0f); + + return color; +} + +// Returns the color corresponding D3DCOLOR. + +D3DCOLOR RetColor(D3DCOLORVALUE intensity) +{ + D3DCOLOR color; + + color = (int)(intensity.a*255.0f)<<24; + color |= (int)(intensity.r*255.0f)<<16; + color |= (int)(intensity.g*255.0f)<<8; + color |= (int)(intensity.b*255.0f); + + return color; +} + +// Returns the color corresponding D3DCOLORVALUE. + +D3DCOLORVALUE RetColor(D3DCOLOR intensity) +{ + D3DCOLORVALUE color; + + color.r = (float)((intensity>>16)&0xff)/256.0f; + color.g = (float)((intensity>>8 )&0xff)/256.0f; + color.b = (float)((intensity>>0 )&0xff)/256.0f; + color.a = (float)((intensity>>24)&0xff)/256.0f; + + return color; +} + + +// RGB to HSV conversion. + +void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest) +{ + float min, max, delta; + + min = Min(src.r, src.g, src.b); + max = Max(src.r, src.g, src.b); + + dest.v = max; // intensity + + if ( max == 0.0f ) + { + dest.s = 0.0f; // saturation + dest.h = 0.0f; // undefined color! + } + else + { + delta = max-min; + dest.s = delta/max; // saturation + + if ( src.r == max ) // between yellow & magenta + { + dest.h = (src.g-src.b)/delta; + } + else if ( src.g == max ) // between cyan & yellow + { + dest.h = 2.0f+(src.b-src.r)/delta; + } + else // between magenta & cyan + { + dest.h = 4.0f+(src.r-src.g)/delta; + } + + dest.h *= 60.0f; // in degrees + if ( dest.h < 0.0f ) dest.h += 360.0f; + dest.h /= 360.0f; // 0..1 + } +} + +// HSV to RGB conversion. + +void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest) +{ + int i; + float f,v,p,q,t; + + src.h = Norm(src.h)*360.0f; + src.s = Norm(src.s); + src.v = Norm(src.v); + + if ( src.s == 0.0f ) // zero saturation? + { + dest.r = src.v; + dest.g = src.v; + dest.b = src.v; // gray + } + else + { + if ( src.h == 360.0f ) src.h = 0.0f; + src.h /= 60.0f; + i = (int)src.h; // integer part (0 .. 5) + f = src.h-i; // fractional part + + v = src.v; + p = src.v*(1.0f-src.s); + q = src.v*(1.0f-(src.s*f)); + t = src.v*(1.0f-(src.s*(1.0f-f))); + + switch (i) + { + case 0: dest.r=v; dest.g=t; dest.b=p; break; + case 1: dest.r=q; dest.g=v; dest.b=p; break; + case 2: dest.r=p; dest.g=v; dest.b=t; break; + case 3: dest.r=p; dest.g=q; dest.b=v; break; + case 4: dest.r=t; dest.g=p; dest.b=v; break; + case 5: dest.r=v; dest.g=p; dest.b=q; break; + } + } +} + diff --git a/src/old/math3d.h b/src/old/math3d.h index 5ef6f43..54bc5ea 100644 --- a/src/old/math3d.h +++ b/src/old/math3d.h @@ -1,48 +1,48 @@ -// * 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/. - -// math3d.h - -#pragma once - - -#include - -#include "common/struct.h" - - -// TODO -void MappingObject( D3DVERTEX2* pVertices, int nb, float scale ); - -// TODO -void SmoothObject( D3DVERTEX2* pVertices, int nb ); - -// TODO -D3DCOLOR RetColor(float intensity); - -// TODO -D3DCOLOR RetColor(D3DCOLORVALUE intensity); - -// TODO -D3DCOLORVALUE RetColor(D3DCOLOR intensity); - -// TODO -void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest); - -// TODO -void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest); - - +// * 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/. + +// math3d.h + +#pragma once + + +#include + +#include "common/struct.h" + + +// TODO +void MappingObject( D3DVERTEX2* pVertices, int nb, float scale ); + +// TODO +void SmoothObject( D3DVERTEX2* pVertices, int nb ); + +// TODO +D3DCOLOR RetColor(float intensity); + +// TODO +D3DCOLOR RetColor(D3DCOLORVALUE intensity); + +// TODO +D3DCOLORVALUE RetColor(D3DCOLOR intensity); + +// TODO +void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest); + +// TODO +void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest); + + diff --git a/src/old/model.cpp b/src/old/model.cpp index 23ea6f5..987a870 100644 --- a/src/old/model.cpp +++ b/src/old/model.cpp @@ -1,3228 +1,3228 @@ -// * 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/. - -// model.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/water.h" -#include "object/robotmain.h" -#include "ui/interface.h" -#include "ui/edit.h" -#include "ui/button.h" -#include "script/cmdtoken.h" -#include "old/modfile.h" -#include "old/model.h" - - - -const int MAX_COLORS = 9; - -static float table_color[MAX_COLORS*3] = -{ - 1.0f, 1.0f, 1.0f, // white - 1.0f, 0.0f, 0.0f, // red - 0.0f, 1.0f, 0.0f, // green - 0.0f, 0.6f, 1.0f, // blue - 1.0f, 1.0f, 0.0f, // yellow - 0.0f, 1.0f, 1.0f, // cyan - 1.0f, 0.0f, 1.0f, // magenta - 0.3f, 0.3f, 0.3f, // grey - 0.0f, 0.0f, 0.0f, // black -}; - - -const int MAX_STATES = 10; - -static int table_state[MAX_STATES] = -{ - D3DSTATENORMAL, - D3DSTATEPART1, - D3DSTATEPART2, - D3DSTATEPART3, - D3DSTATEPART4, - D3DSTATE2FACE, // #5 - D3DSTATETTw, - D3DSTATETTb, - D3DSTATETTw|D3DSTATE2FACE, // #8 - D3DSTATETTb|D3DSTATE2FACE, // #9 -}; - - -const int MAX_NAMES = 23; - - - - -// Object's constructor. - -CModel::CModel(CInstanceManager* iMan) -{ - m_iMan = iMan; - - m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); - m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE); - - m_modFile = new CModFile(m_iMan); - m_triangleTable = m_modFile->RetTriangleList(); - - m_textureRank = 0; - strcpy(m_textureName, "lemt.tga"); - m_color = 0; - m_state = 0; - m_textureMode = 0; - m_textureRotate = 0; - m_bTextureMirrorX = false; - m_bTextureMirrorY = false; - m_texturePart = 0; - TexturePartUpdate(); - - m_bDisplayTransparent = false; - m_bDisplayOnlySelection = false; - InitView(); - - m_triangleSel1 = 0; - m_triangleSel2 = 0; - - m_mode = 1; - m_oper = 'P'; - - m_secondTexNum = 0; - m_secondSubdiv = 1; - m_secondOffsetU = 0; - m_secondOffsetV = 0; - - m_min = 0.0f; - m_max = 1000000.0f; -} - -// Object's destructor. - -CModel::~CModel() -{ - delete m_modFile; -} - - -// You must call this procedure before changing the model interactively. - -void CModel::StartUserAction() -{ - Event event; - Math::Point pos, dim; - CButton* pb; - - dim.x = 105.0f/640.0f; - dim.y = 18.0f/480.0f; - pos.x = 10.0f/640.0f; - pos.y = 450.0f/480.0f; - m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT1); - - dim.x = 50.0f/640.0f; - pos.x = 125.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON1); - pb->SetState(STATE_SIMPLY); - pb->SetName("Load"); - pos.x = 185.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON2); - pb->SetState(STATE_SIMPLY); - pb->SetName("Script"); - pos.x = 245.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON3); - pb->SetState(STATE_SIMPLY); - pb->SetName("Read"); - pos.x = 305.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON4); - pb->SetState(STATE_SIMPLY); - pb->SetName("Add"); - pos.x = 365.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON5); - pb->SetState(STATE_SIMPLY); - pb->SetName("Write"); - - dim.x = 50.0f/640.0f; - dim.y = 18.0f/480.0f; - pos.x = 10.0f/640.0f; - pos.y = 425.0f/480.0f; - m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT2); - pos.x = 65.0f/640.0f; - pos.y = 425.0f/480.0f; - m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT3); - pos.x = 10.0f/640.0f; - pos.y = 400.0f/480.0f; - m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT4); - pos.x = 65.0f/640.0f; - pos.y = 400.0f/480.0f; - m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT5); - - dim.x = 20.0f/640.0f; - dim.y = 20.0f/480.0f; - pos.y = 370.0f/480.0f; - pos.x = 10.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON10); - pb->SetState(STATE_SIMPLY); - pb->SetName("P"); - pos.x = 30.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON11); - pb->SetState(STATE_SIMPLY); - pb->SetName("R"); - pos.x = 50.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON12); - pb->SetState(STATE_SIMPLY); - pb->SetName("Z"); - pos.y = 350.0f/480.0f; - pos.x = 10.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON13); - pb->SetState(STATE_SIMPLY); - pb->SetName("+X"); - pos.x = 30.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON14); - pb->SetState(STATE_SIMPLY); - pb->SetName("+Y"); - pos.x = 50.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON15); - pb->SetState(STATE_SIMPLY); - pb->SetName("+Z"); - pos.y = 330.0f/480.0f; - pos.x = 10.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON16); - pb->SetState(STATE_SIMPLY); - pb->SetName("-X"); - pos.x = 30.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON17); - pb->SetState(STATE_SIMPLY); - pb->SetName("-Y"); - pos.x = 50.0f/640.0f; - pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON18); - pb->SetState(STATE_SIMPLY); - pb->SetName("-Z"); - -//? m_modFile->ReadModel("objects\\io.mod"); - DeselectAll(); - CurrentInit(); - - ZeroMemory(&event, sizeof(Event)); - EventFrame(event); - - m_engine->LoadAllTexture(); - UpdateInfoText(); -} - -// You must call this procedure after modifing the model interactively. - -void CModel::StopUserAction() -{ - m_interface->DeleteControl(EVENT_EDIT1); - m_interface->DeleteControl(EVENT_EDIT2); - m_interface->DeleteControl(EVENT_EDIT3); - m_interface->DeleteControl(EVENT_EDIT4); - m_interface->DeleteControl(EVENT_EDIT5); - m_interface->DeleteControl(EVENT_BUTTON1); - m_interface->DeleteControl(EVENT_BUTTON2); - m_interface->DeleteControl(EVENT_BUTTON3); - m_interface->DeleteControl(EVENT_BUTTON4); - m_interface->DeleteControl(EVENT_BUTTON5); - m_interface->DeleteControl(EVENT_BUTTON10); - m_interface->DeleteControl(EVENT_BUTTON11); - m_interface->DeleteControl(EVENT_BUTTON12); - m_interface->DeleteControl(EVENT_BUTTON13); - m_interface->DeleteControl(EVENT_BUTTON14); - m_interface->DeleteControl(EVENT_BUTTON15); - m_interface->DeleteControl(EVENT_BUTTON16); - m_interface->DeleteControl(EVENT_BUTTON17); - m_interface->DeleteControl(EVENT_BUTTON18); - - m_engine->SetInfoText(0, ""); - m_engine->SetInfoText(1, ""); -} - - -// Updates the​editable values for mapping textures. - -void CModel::PutTextureValues() -{ - CEdit* pe; - char s[100]; - int value; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); - if ( pe != 0 ) - { - value = (int)(m_textureSup.x*256.0f+0.5f); - sprintf(s, "%d", value); - pe->SetText(s); - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); - if ( pe != 0 ) - { - value = (int)(m_textureSup.y*256.0f+0.5f); - sprintf(s, "%d", value); - pe->SetText(s); - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); - if ( pe != 0 ) - { - value = (int)(m_textureInf.x*256.0f-0.5f); - sprintf(s, "%d", value); - pe->SetText(s); - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); - if ( pe != 0 ) - { - value = (int)(m_textureInf.y*256.0f-0.5f); - sprintf(s, "%d", value); - pe->SetText(s); - } -} - -// Takes the editable values for mapping textures. - -void CModel::GetTextureValues() -{ - CEdit* pe; - char s[100]; - int value; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); - if ( pe != 0 ) - { - pe->GetText(s, 100); - sscanf(s, "%d", &value); - m_textureSup.x = ((float)value-0.5f)/256.0f; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); - if ( pe != 0 ) - { - pe->GetText(s, 100); - sscanf(s, "%d", &value); - m_textureSup.y = ((float)value-0.5f)/256.0f; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); - if ( pe != 0 ) - { - pe->GetText(s, 100); - sscanf(s, "%d", &value); - m_textureInf.x = ((float)value+0.5f)/256.0f; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); - if ( pe != 0 ) - { - pe->GetText(s, 100); - sscanf(s, "%d", &value); - m_textureInf.y = ((float)value+0.5f)/256.0f; - } -} - - -// Gives the model name. - -void CModel::GetModelName(char *buffer) -{ - CEdit* pe; - char s[100]; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); - if ( pe == 0 ) - { - strcpy(buffer, "objects\\io.mod"); - } - else - { - pe->GetText(s, 100); - sprintf(buffer, "objects\\%s.mod", s); - } -} - -// Gives the model name. - -void CModel::GetDXFName(char *buffer) -{ - CEdit* pe; - char s[100]; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); - if ( pe == 0 ) - { - strcpy(buffer, "models\\import.dxf"); - } - else - { - pe->GetText(s, 100); - sprintf(buffer, "models\\%s.dxf", s); - } -} - -// Gives the model name. - -void CModel::GetScriptName(char *buffer) -{ - CEdit* pe; - char s[100]; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); - if ( pe == 0 ) - { - strcpy(buffer, "objects\\script.txt"); - } - else - { - pe->GetText(s, 100); - sprintf(buffer, "objects\\%s.txt", s); - } -} - -// Indicates whether the edition name has focus. - -bool CModel::IsEditFocus() -{ - CEdit* pe; - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); - if ( pe != 0 ) - { - if ( pe->RetFocus() ) return true; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); - if ( pe != 0 ) - { - if ( pe->RetFocus() ) return true; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); - if ( pe != 0 ) - { - if ( pe->RetFocus() ) return true; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); - if ( pe != 0 ) - { - if ( pe->RetFocus() ) return true; - } - - pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); - if ( pe != 0 ) - { - if ( pe->RetFocus() ) return true; - } - - return false; -} - - -// Management of an event. - -bool CModel::EventProcess(const Event &event) -{ - char s[100]; - int first, last; - - switch( event.event ) - { - case EVENT_FRAME: - EventFrame(event); - break; - - case EVENT_KEYDOWN: - if ( IsEditFocus() ) - break; - - if ( event.param == '1' ) - { - m_mode = 1; - UpdateInfoText(); - } - if ( event.param == '2' ) - { - m_mode = 2; - UpdateInfoText(); - } - if ( event.param == '3' ) - { - m_mode = 3; - UpdateInfoText(); - } - if ( event.param == VK_ADD ) // numpad? - { - if ( event.keyState & KS_SHIFT ) CurrentSelect(true); - CurrentSearchNext(+1, (event.keyState & KS_CONTROL)); - } - if ( event.param == VK_SUBTRACT ) // least numpad? - { - if ( event.keyState & KS_SHIFT ) CurrentSelect(true); - CurrentSearchNext(-1, (event.keyState & KS_CONTROL)); - } - if ( event.param == VK_NUMPAD0 ) - { - CurrentSelect(false); - } - if ( event.param == VK_DECIMAL ) - { - CurrentSelect(true); - } - if ( event.param == VK_END ) - { - DeselectAll(); - } - if ( event.param == VK_INSERT ) - { - SelectAll(); - } - if ( event.param == VK_BACK ) // Delete normal ? - { - SelectDelete(); - } - if ( event.param == VK_SPACE ) - { - m_bDisplayTransparent = !m_bDisplayTransparent; - m_bDisplayOnlySelection = false; - } - if ( event.param == 'H' ) - { - m_bDisplayOnlySelection = !m_bDisplayOnlySelection; - m_bDisplayTransparent = false; - } - if ( m_mode == 1 ) - { - if ( event.param == 'S' ) - { - SmoothSelect(); - } - if ( event.param == 'N' ) - { - PlaneSelect(); - } - if ( event.param == 'C' ) - { - ColorSelect(); - } - if ( event.param == 'V' ) - { - m_color ++; - if ( m_color >= MAX_COLORS ) m_color = 0; - UpdateInfoText(); - ColorSelect(); - } - if ( event.param == 'J' ) - { - StateSelect(); - } - if ( event.param == 'K' ) - { - m_state ++; - if ( m_state >= MAX_STATES ) m_state = 0; - UpdateInfoText(); - StateSelect(); - } - if ( event.param == 'M' ) - { - m_textureMode ++; - if ( m_textureMode > 3 ) m_textureMode = 0; - UpdateInfoText(); - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'Z' ) - { - m_textureRotate ++; - if ( m_textureRotate > 2 ) m_textureRotate = 0; - UpdateInfoText(); - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'X' ) - { - m_bTextureMirrorX = !m_bTextureMirrorX; - UpdateInfoText(); - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'Y' ) - { - m_bTextureMirrorY = !m_bTextureMirrorY; - UpdateInfoText(); - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'O' ) - { - TextureRankChange(+1); - UpdateInfoText(); - } - if ( event.param == 'P' ) - { - TexturePartChange(+1); - UpdateInfoText(); - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'T' ) - { - GetTextureValues(); - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_textureInf, m_textureSup, m_textureName); - } - if ( event.param == 'E' ) - { - Math::Point ti, ts; - ti.x = 0.00f; - ti.y = 0.00f; - ts.x = 0.00f; - ts.y = 0.00f; - MappingSelect(m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - ti, ts, ""); - } - } - if ( m_mode == 2 ) - { - if ( event.param == 'E' ) - { - m_secondTexNum = 0; - UpdateInfoText(); - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - } - if ( event.param == 'O' ) - { - m_secondTexNum ++; - if ( m_secondTexNum > 10 ) m_secondTexNum = 1; - UpdateInfoText(); - } - if ( event.param == 'T' ) - { - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - m_engine->LoadAllTexture(); - } - if ( event.param == 'U' ) - { - m_secondOffsetU += 45; - if ( m_secondOffsetU >= 360 ) m_secondOffsetU = 0; - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - UpdateInfoText(); - } - if ( event.param == 'V' ) - { - m_secondOffsetV += 45; - if ( m_secondOffsetV >= 360 ) m_secondOffsetV = 0; - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - UpdateInfoText(); - } - if ( event.param == 'X' ) - { - m_bTextureMirrorX = !m_bTextureMirrorX; - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - UpdateInfoText(); - } - if ( event.param == 'Y' ) - { - m_bTextureMirrorY = !m_bTextureMirrorY; - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - UpdateInfoText(); - } - if ( event.param == 'S' ) - { - m_secondSubdiv ++; - if ( m_secondSubdiv > 7 ) m_secondSubdiv = 1; - MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); - UpdateInfoText(); - } - } - if ( m_mode == 3 ) - { - if ( event.param == 'M' ) - { - if ( m_min == 0.0f && m_max == 1000000.0f ) - { - m_min = 0.0f; m_max = 100.0f; - } - else if ( m_min == 0.0f && m_max == 100.0f ) - { - m_min = 100.0f; m_max = 200.0f; - } - else if ( m_min == 100.0f && m_max == 200.0f ) - { - m_min = 200.0f; m_max = 1000000.0f; - } - else if ( m_min == 200.0f && m_max == 1000000.0f ) - { - m_min = 0.0f; m_max = 1000000.0f; - } - UpdateInfoText(); - } - if ( event.param == 'C' ) - { - MinMaxChange(); - } - } - break; - - case EVENT_BUTTON1: // import ? - GetDXFName(s); - m_modFile->ReadDXF(s, m_min, m_max); - DeselectAll(); - CurrentInit(); - EventFrame(event); - m_engine->LoadAllTexture(); - break; - - case EVENT_BUTTON2: // script ? - GetScriptName(s); - ReadScript(s); - DeselectAll(); - CurrentInit(); - EventFrame(event); - m_engine->LoadAllTexture(); - break; - - case EVENT_BUTTON3: // read ? - GetModelName(s); - m_modFile->ReadModel(s, true, false); // standard read with borders - DeselectAll(); - CurrentInit(); - EventFrame(event); - m_engine->LoadAllTexture(); - break; - - case EVENT_BUTTON4: // add ? - GetModelName(s); - first = m_modFile->RetTriangleUsed(); - m_modFile->AddModel(s, first, true, false); // standard read with borders - last = m_modFile->RetTriangleUsed(); - SelectZone(first, last); - EventFrame(event); - break; - - case EVENT_BUTTON5: // write ? - GetModelName(s); - DeselectAll(); - m_modFile->WriteModel(s); - break; - - case EVENT_BUTTON10: // pos ? - m_oper = 'P'; - break; - case EVENT_BUTTON11: // rotate ? - m_oper = 'R'; - break; - case EVENT_BUTTON12: // zoom ? - m_oper = 'Z'; - break; - - case EVENT_BUTTON13: // +X ? - MoveSelect(Math::Vector(1.0f, 0.0f, 0.0f)); - break; - case EVENT_BUTTON16: // -X ? - MoveSelect(Math::Vector(-1.0f, 0.0f, 0.0f)); - break; - case EVENT_BUTTON14: // +Y ? - MoveSelect(Math::Vector(0.0f, 1.0f, 0.0f)); - break; - case EVENT_BUTTON17: // -Y ? - MoveSelect(Math::Vector(0.0f, -1.0f, 0.0f)); - break; - case EVENT_BUTTON15: // +Z ? - MoveSelect(Math::Vector(0.0f, 0.0f, 1.0f)); - break; - case EVENT_BUTTON18: // -Z ? - MoveSelect(Math::Vector(0.0f, 0.0f, -1.0f)); - break; - } - - return 0; -} - - -// Drives the model. - -bool CModel::EventFrame(const Event &event) -{ - D3DMATERIAL7 matCurrent, matCurrenti, matCurrents, matTrans; - D3DMATERIAL7* pMat; - D3DVERTEX2 vertex[3]; - char texName2[20]; - int i, used, objRank, state; - - m_time += event.rTime; - - m_engine->FlushObject(); - objRank = m_engine->CreateObject(); - - ZeroMemory(&matCurrent, sizeof(D3DMATERIAL7)); - matCurrent.diffuse.r = 1.0f; - matCurrent.diffuse.g = 0.0f; - matCurrent.diffuse.b = 0.0f; // red - matCurrent.ambient.r = 0.5f; - matCurrent.ambient.g = 0.5f; - matCurrent.ambient.b = 0.5f; - - ZeroMemory(&matCurrents, sizeof(D3DMATERIAL7)); - matCurrents.diffuse.r = 1.0f; - matCurrents.diffuse.g = 1.0f; - matCurrents.diffuse.b = 0.0f; // yellow - matCurrents.ambient.r = 0.5f; - matCurrents.ambient.g = 0.5f; - matCurrents.ambient.b = 0.5f; - - ZeroMemory(&matCurrenti, sizeof(D3DMATERIAL7)); - matCurrenti.diffuse.r = 0.0f; - matCurrenti.diffuse.g = 0.0f; - matCurrenti.diffuse.b = 1.0f; // blue - matCurrenti.ambient.r = 0.5f; - matCurrenti.ambient.g = 0.5f; - matCurrenti.ambient.b = 0.5f; - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; i= m_triangleSel1 && - i <= m_triangleSel2 && - (int)(m_time*10.0f)%2 == 0 ) - { - pMat = &matCurrent; - } - else if ( m_triangleTable[i].bSelect && - (int)(m_time*10.0f)%2 == 0 ) - { - pMat = &matCurrents; - } - else - { - if ( m_bDisplayOnlySelection ) continue; - if ( m_bDisplayTransparent ) - { - matTrans = m_triangleTable[i].material; - matTrans.diffuse.a = 0.1f; // very transparent - pMat = &matTrans; - state = D3DSTATETD; - } - } - - if ( m_triangleTable[i].texNum2 == 0 ) - { - m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, - *pMat, state, - m_triangleTable[i].texName, "", - 0.0f, 1000000.0f, false); - } - else - { - sprintf(texName2, "dirty%.2d.tga", m_triangleTable[i].texNum2); - m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, - *pMat, state|D3DSTATEDUALb, - m_triangleTable[i].texName, texName2, - 0.0f, 1000000.0f, false); - } - - if ( m_bDisplayTransparent && // draws inside? - i >= m_triangleSel1 && - i <= m_triangleSel2 ) - { - vertex[0] = m_triangleTable[i].p3; - vertex[1] = m_triangleTable[i].p2; - vertex[2] = m_triangleTable[i].p1; - - m_engine->AddTriangle(objRank, vertex, 3, - matCurrenti, D3DSTATENORMAL, - m_triangleTable[i].texName, "", - 0.0f, 1000000.0f, false); - } - } - - return true; -} - - -// Gives a vertex. - -bool CModel::GetVertex(int rank, D3DVERTEX2 &vertex) -{ - if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return false; - if ( !m_triangleTable[rank/3].bUsed ) return false; - - if ( !m_triangleTable[rank/3].bSelect ) return false; - - if ( rank%3 == 0 ) - { - vertex = m_triangleTable[rank/3].p1; - return true; - } - if ( rank%3 == 1 ) - { - vertex = m_triangleTable[rank/3].p2; - return true; - } - if ( rank%3 == 2 ) - { - vertex = m_triangleTable[rank/3].p3; - return true; - } - return false; -} - -// Modifies a vertex. - -bool CModel::SetVertex(int rank, D3DVERTEX2 &vertex) -{ - if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return false; - if ( !m_triangleTable[rank/3].bUsed ) return false; - - if ( !m_triangleTable[rank/3].bSelect ) return false; - - if ( rank%3 == 0 ) - { - m_triangleTable[rank/3].p1 = vertex; - return true; - } - if ( rank%3 == 1 ) - { - m_triangleTable[rank/3].p2 = vertex; - return true; - } - if ( rank%3 == 2 ) - { - m_triangleTable[rank/3].p3 = vertex; - return true; - } - return false; -} - -// Smoothed normals selected triangles. - -void CModel::SmoothSelect() -{ - char* bDone; - int index[100]; - int used, i, j, rank; - D3DVERTEX2 vi, vj; - Math::Vector sum; - - used = m_modFile->RetTriangleUsed(); - - bDone = (char*)malloc(used*3*sizeof(char)); - for ( i=0 ; i= 100 ) break; - } - } - - sum.x = 0; - sum.y = 0; - sum.z = 0; - for ( j=0 ; jRetTriangleUsed(); - - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iReadModel(buffer, true, true); - last = m_modFile->RetTriangleUsed(); - SelectZone(0, last); - } - else - { - first = m_modFile->RetTriangleUsed(); - m_modFile->AddModel(buffer, first, true, false); - last = m_modFile->RetTriangleUsed(); - SelectZone(first, last); - } - bFirst = false; - - move = OpDir(line, "zoom"); - OperSelect(move, 'Z'); - - move = OpDir(line, "rot"); - move *= Math::PI/180.0f; // degrees -> radians - OperSelect(move, 'R'); - - move = OpDir(line, "pos"); - OperSelect(move, 'P'); - } - } - - fclose(file); -} - - - -// Computes the bbox of selected triangles. - -void CModel::BBoxCompute(Math::Vector &min, Math::Vector &max) -{ - D3DVERTEX2 vertex; - int used, i; - - min.x = 1000000.0f; - min.y = 1000000.0f; - min.z = 1000000.0f; - max.x = -1000000.0f; - max.y = -1000000.0f; - max.z = -1000000.0f; - - used = m_modFile->RetTriangleUsed(); - - for ( i=0 ; i max.x ) max.x = vertex.x; - if ( vertex.y > max.y ) max.y = vertex.y; - if ( vertex.z > max.z ) max.z = vertex.z; - } -} - -// Returns the gravity center of the selection. - -Math::Vector CModel::RetSelectCDG() -{ - Math::Vector min, max, cdg; - - BBoxCompute(min, max); - - cdg.x = (min.x+max.x)/2.0f; - cdg.y = (min.y+max.y)/2.0f; - cdg.z = (min.z+max.z)/2.0f; - - return cdg; -} - -// Returns the normal vector of the selection. - -Math::Vector CModel::RetSelectNormal() -{ - Math::Vector p1, p2, p3, n; - - p1.x = m_triangleTable[m_triangleSel1].p1.nx; - p1.y = m_triangleTable[m_triangleSel1].p1.ny; - p1.z = m_triangleTable[m_triangleSel1].p1.nz; - - p2.x = m_triangleTable[m_triangleSel1].p2.nx; - p2.y = m_triangleTable[m_triangleSel1].p2.ny; - p2.z = m_triangleTable[m_triangleSel1].p2.nz; - - p3.x = m_triangleTable[m_triangleSel1].p3.nx; - p3.y = m_triangleTable[m_triangleSel1].p3.ny; - p3.z = m_triangleTable[m_triangleSel1].p3.nz; - - n = Normalize(p1+p2+p3); - - return n; -} - -// Maps a texture onto the selected triangles. - -bool CModel::IsMappingSelectPlausible(D3DMaping D3Dmode) -{ - D3DVERTEX2 vertex[3]; - Math::Vector min, max; - Math::Point a, b, ti, ts; - float au, bu, av, bv; - int used, i, j; - - ti.x = 0.0f; - ti.y = 0.0f; - ts.x = 1.0f; - ts.y = 1.0f; - - BBoxCompute(min, max); - - if ( D3Dmode == D3DMAPPINGX ) - { - a.x = min.z; - a.y = min.y; - b.x = max.z; - b.y = max.y; - } - if ( D3Dmode == D3DMAPPINGY ) - { - a.x = min.x; - a.y = min.z; - b.x = max.x; - b.y = max.z; - } - if ( D3Dmode == D3DMAPPINGZ ) - { - a.x = min.x; - a.y = min.y; - b.x = max.x; - b.y = max.y; - } - - au = (ts.x-ti.x)/(b.x-a.x); - bu = ts.x-b.x*(ts.x-ti.x)/(b.x-a.x); - - av = (ts.y-ti.y)/(b.y-a.y); - bv = ts.y-b.y*(ts.y-ti.y)/(b.y-a.y); - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; i 1.0f ) u[j] -= 1.0f; -#else - u[j] = Math::RotateAngle(p.x, p.z)/Math::PI; -//? if ( u[j] > 1.0f ) u[j] = 2.0f-u[j]; - if ( u[j] > 1.0f ) u[j] -= 1.0f; -#endif - - v[j] = p.y/dim.y/2.0f + 0.5f; - - if ( u[j] < 0.5f ) m[j] = u[j]; - else m[j] = u[j]-1.0f; - } - - avg = (m[0]+m[1]+m[2])/3.0f; - - for ( j=0 ; j<3 ; j++ ) - { - if ( u[j] < 0.05f || u[j] > 0.95f ) - { - if ( avg > 0.0f ) u[j] = 0.0f; - else u[j] = 1.0f; - } - - vertex[j].tu = ti.x+(ts.x-ti.x)*u[j]; - vertex[j].tv = ti.y+(ts.y-ti.y)*v[j]; - - SetVertex(i*3+j, vertex[j]); - } - } - - SelectTerm(); -} - - -// Maps a secondary texture on selected triangles. - -void CModel::MappingSelect2(int texNum2, int subdiv, - int offsetU, int offsetV, - bool bMirrorX, bool bMirrorY) -{ - D3DVERTEX2 vertex; - Math::Vector min, max, center, p; - float u ,v; - int used, i; - - DefaultSelect(); - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; i 2 ) - { - MappingSelectPlane2(subdiv-3, bMirrorX, bMirrorY); - return; - } - - BBoxCompute(min, max); - center = (min+max)/2.0f; - - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; i= Math::Max(n.y, n.z) ) mode = 0; - if ( n.y >= Math::Max(n.x, n.z) ) mode = 1; - if ( n.z >= Math::Max(n.x, n.y) ) mode = 2; - } - - if ( !GetVertex(i, vertex) ) continue; - - if ( mode == 0 ) - { - vertex.tu2 = vertex.z*au.z+bu.z; - vertex.tv2 = vertex.y*av.y+bv.y; - } - if ( mode == 1 ) - { - vertex.tu2 = vertex.x*au.x+bu.x; - vertex.tv2 = vertex.z*av.z+bv.z; - } - if ( mode == 2 ) - { - vertex.tu2 = vertex.x*au.x+bu.x; - vertex.tv2 = vertex.y*av.y+bv.y; - } - - SetVertex(i, vertex); - } - - SelectTerm(); -} - - -// Seeks the next triangle. - -int CModel::SearchNext(int rank, int step) -{ - int max, i; - - max = m_modFile->RetTriangleUsed(); - - for ( i=0 ; i= max ) rank = 0; - - if ( m_triangleTable[rank].min != m_min || - m_triangleTable[rank].max != m_max ) continue; - - if ( m_triangleTable[rank].bUsed ) break; - } - return rank; -} - -// Seeks all the triangles belonging to the same plane. - -int CModel::SearchSamePlane(int first, int step) -{ - Math::Vector vFirst[3], vNext[3]; - int last, i; - - vFirst[0].x = m_triangleTable[first].p1.x; - vFirst[0].y = m_triangleTable[first].p1.y; - vFirst[0].z = m_triangleTable[first].p1.z; - vFirst[1].x = m_triangleTable[first].p2.x; - vFirst[1].y = m_triangleTable[first].p2.y; - vFirst[1].z = m_triangleTable[first].p2.z; - vFirst[2].x = m_triangleTable[first].p3.x; - vFirst[2].y = m_triangleTable[first].p3.y; - vFirst[2].z = m_triangleTable[first].p3.z; - - for ( i=0 ; i<1000 ; i++ ) - { - last = first; - first = SearchNext(first, step); - - vNext[0].x = m_triangleTable[first].p1.x; - vNext[0].y = m_triangleTable[first].p1.y; - vNext[0].z = m_triangleTable[first].p1.z; - vNext[1].x = m_triangleTable[first].p2.x; - vNext[1].y = m_triangleTable[first].p2.y; - vNext[1].z = m_triangleTable[first].p2.z; - vNext[2].x = m_triangleTable[first].p3.x; - vNext[2].y = m_triangleTable[first].p3.y; - vNext[2].z = m_triangleTable[first].p3.z; - - if ( !IsSamePlane(vFirst, vNext) ) // other plan? - { - return last; - } - } - return first; -} - -// Seeks the next triangle. - -void CModel::CurrentSearchNext(int step, bool bControl) -{ - if ( step > 0 ) // forward? - { - m_triangleSel1 = SearchNext(m_triangleSel2, step); - if ( bControl ) - { - m_triangleSel2 = m_triangleSel1; - } - else - { - m_triangleSel2 = SearchSamePlane(m_triangleSel1, step); - } - } - if ( step < 0 ) // back? - { - m_triangleSel2 = SearchNext(m_triangleSel1, step); - if ( bControl ) - { - m_triangleSel1 = m_triangleSel2; - } - else - { - m_triangleSel1 = SearchSamePlane(m_triangleSel2, step); - } - } - -#if 0 - char s[100]; - sprintf(s, "(%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f)", - m_triangleTable[m_triangleSel1].p1.x, - m_triangleTable[m_triangleSel1].p1.y, - m_triangleTable[m_triangleSel1].p1.z, - m_triangleTable[m_triangleSel1].p2.x, - m_triangleTable[m_triangleSel1].p2.y, - m_triangleTable[m_triangleSel1].p2.z, - m_triangleTable[m_triangleSel1].p3.x, - m_triangleTable[m_triangleSel1].p3.y, - m_triangleTable[m_triangleSel1].p3.z); - m_engine->SetInfoText(2, s); - sprintf(s, "(%.2f;%.2f) (%.2f;%.2f) (%.2f;%.2f)", - m_triangleTable[m_triangleSel1].p1.tu2, - m_triangleTable[m_triangleSel1].p1.tv2, - m_triangleTable[m_triangleSel1].p2.tu2, - m_triangleTable[m_triangleSel1].p2.tv2, - m_triangleTable[m_triangleSel1].p3.tu2, - m_triangleTable[m_triangleSel1].p3.tv2); - m_engine->SetInfoText(3, s); -#endif - - InitViewFromSelect(); - UpdateInfoText(); -} - -// Initializes the current triangles. - -void CModel::CurrentInit() -{ - m_triangleSel1 = 0; - m_triangleSel2 = SearchSamePlane(m_triangleSel1, +1); - - InitViewFromSelect(); - UpdateInfoText(); -} - -// Selects the current triangles. - -void CModel::CurrentSelect(bool bSelect) -{ - int i; - - for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ ) - { - m_triangleTable[i].bSelect = bSelect; - } -} - - -// Deselects all triangles. - -void CModel::DeselectAll() -{ - int used, i; - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; i= first && i < last ) - { - m_triangleTable[i].bSelect = true; - } - } - m_triangleSel1 = first; - m_triangleSel2 = last-1; -} - -// Selects all triangles. - -void CModel::SelectAll() -{ - int used, i; - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; i= m_triangleSel1 && i <= m_triangleSel2 ) - { - if ( !m_triangleTable[i].bSelect ) return; - } - else - { - if ( m_triangleTable[i].bSelect ) return; - } - } - - DeselectAll(); -} - -// Selects the triangles currents. - -void CModel::DefaultSelect() -{ - int used, i; - - used = m_modFile->RetTriangleUsed(); - for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ ) - { - m_triangleTable[i].bSelect = true; - } -} - - - -// Removes all selected triangles. - -void CModel::SelectDelete() -{ - int used ,i; - - DefaultSelect(); - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; iRetTriangleUsed(); - for ( i=0 ; iSetTriangleUsed(j); - CurrentInit(); -} - - -// Change the min / max of all selected triangles. - -void CModel::MinMaxChange() -{ - int used, i; - - DefaultSelect(); - - used = m_modFile->RetTriangleUsed(); - for ( i=0 ; i= Math::PI ) - { - m_viewAngleV -= Math::PI; - m_viewAngleH -= Math::PI; - } - m_viewAngleV *= 0.75f; - - char s[100]; - sprintf(s, "angle=%f %f -> %f %f\n", h,v, m_viewAngleH, m_viewAngleV); - OutputDebugString(s); -#endif -} - -// Updates the parameters for the point of view. - -void CModel::UpdateView() -{ - Math::Vector eye, lookat, vUpVec; - -//? lookat = RetSelectCDG(); - lookat = Math::Vector(0.0f, m_viewHeight, 0.0f); - eye = RotateView(lookat, m_viewAngleH, m_viewAngleV, m_viewDist); - - vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); - m_engine->SetViewParams(eye, lookat, vUpVec, 10.0f); - m_engine->SetRankView(0); -} - -// Moves the point of view. - -void CModel::ViewMove(const Event &event, float speed) -{ - if ( IsEditFocus() ) return; - - // Up/Down. - if ( event.axeY > 0.5f ) - { - if ( event.keyState & KS_CONTROL ) - { - m_viewHeight += event.rTime*10.0f*speed; - if ( m_viewHeight > 100.0f ) m_viewHeight = 100.0f; - } - else - { - m_viewAngleV -= event.rTime*1.0f*speed; - if ( m_viewAngleV < -Math::PI*0.49f ) m_viewAngleV = -Math::PI*0.49f; - } - } - if ( event.axeY < -0.5f ) - { - if ( event.keyState & KS_CONTROL ) - { - m_viewHeight -= event.rTime*10.0f*speed; - if ( m_viewHeight < -100.0f ) m_viewHeight = -100.0f; - } - else - { - m_viewAngleV += event.rTime*1.0f*speed; - if ( m_viewAngleV > Math::PI*0.49f ) m_viewAngleV = Math::PI*0.49f; - } - } - - // Left/Right. - if ( event.axeX < -0.5f ) - { - m_viewAngleH -= event.rTime*1.0f*speed; - } - if ( event.axeX > 0.5f ) - { - m_viewAngleH += event.rTime*1.0f*speed; - } - - // PageUp/PageDown. - if ( event.keyState & KS_PAGEUP ) - { - m_viewDist -= event.rTime*30.0f*speed; - if ( m_viewDist < 1.0f ) m_viewDist = 1.0f; - } - if ( event.keyState & KS_PAGEDOWN ) - { - m_viewDist += event.rTime*30.0f*speed; - if ( m_viewDist > 300.0f ) m_viewDist = 300.0f; - } -} - - - -// Updates the text information. - -void CModel::UpdateInfoText() -{ - char info[100]; - - if ( m_mode == 1 ) - { - sprintf(info, "[1] V:color=%d K:state=%d Sel=%d..%d (T=%d)", - m_color, m_state, - m_triangleSel1, m_triangleSel2, - m_triangleSel2-m_triangleSel1+1); - m_engine->SetInfoText(0, info); - - sprintf(info, "M:mode=%d Z:rot=%d XY:mir=%d;%d P:part=%d O:name=%s", - m_textureMode, m_textureRotate, - m_bTextureMirrorX, m_bTextureMirrorY, - m_texturePart, m_textureName); - m_engine->SetInfoText(1, info); - } - - if ( m_mode == 2 ) - { - sprintf(info, "[2] Sel=%d..%d (T=%d)", - m_triangleSel1, m_triangleSel2, - m_triangleSel2-m_triangleSel1+1); - m_engine->SetInfoText(0, info); - - sprintf(info, "O:dirty=%d UV:offset=%d;%d XY:mir=%d;%d S:subdiv=%d", - m_secondTexNum, - m_secondOffsetU, m_secondOffsetV, - m_bTextureMirrorX, m_bTextureMirrorY, - m_secondSubdiv); - m_engine->SetInfoText(1, info); - } - - if ( m_mode == 3 ) - { - sprintf(info, "[3] LOD Math::Min/max=%d..%d Sel=%d..%d (T=%d)", - (int)m_min, (int)m_max, - m_triangleSel1, m_triangleSel2, - m_triangleSel2-m_triangleSel1+1); - m_engine->SetInfoText(0, info); - - sprintf(info, "[Change]"); - m_engine->SetInfoText(1, info); - } -} - - - -static int tablePartT[] = // lemt.tga -{ - 192, 0, 256, 32, // track profile - 0, 64, 128, 128, // wheels for track - 0, 0, 128, 64, // profile - 90, 0, 128, 28, // pivot trainer - 128, 0, 192, 44, // chest front - 128, 44, 192, 58, // shell - 128, 58, 192, 87, // back chest - 128, 87, 192, 128, // back shell - 128, 128, 192, 144, // sub back shell - 0, 128, 32, 152, // rear fender - 0, 152, 32, 182, // fender middle - 0, 182, 32, 256, // front fender - 32, 128, 112, 176, // wing - 224, 48, 232, 64, // thrust tunnel - 192, 32, 224, 64, // fire under reactor - 224, 32, 256, 48, // foot - 192, 64, 256, 128, // sensor - 192, 128, 224, 176, // battery holder - 192, 216, 248, 248, // cannon board - 220, 216, 222, 245, // cannon board - 64, 176, 128, 224, // top cannon - 128, 152, 192, 160, // external cannon - 128, 144, 192, 152, // interior cannon - 192, 176, 224, 192, // small cannon - 128, 236, 192, 256, // cannon organic - 214, 192, 224, 216, // crosshair - 224, 128, 248, 152, // articulation - 128, 192, 192, 214, // piston board - 128, 214, 192, 236, // piston front - 192, 192, 214, 214, // piston edge - 128, 192, 161, 214, // small piston board - 32, 176, 64, 198, // radar piston - 128, 160, 160, 192, // wheel - 232, 48, 255, 56, // tire profile - 240, 152, 248, 216, // vertical hatching - 248, 192, 256, 256, // battery - 224, 152, 240, 168, // rock - 144, 80, 176, 112, // nuclear - 140, 76, 180, 116, // large nuclear - 144, 80, 152, 88, // yellow nuclear - 224, 168, 240, 192, // cap resolution C - 224, 192, 240, 210, // back resolution C - 32, 224, 96, 235, // arm resolution C - 32, 235, 96, 246, // arm resolution C - 161, 1, 164, 4, // blank - 168, 1, 171, 4, // medium gray - 154, 1, 157, 4, // dark gray uniform - 147, 1, 150, 4, // blue unifrom - 114, 130, 118, 134, // red unifrom - 121, 130, 125, 134, // green uniform - 114, 137, 118, 141, // yellow uniform - 121, 137, 125, 141, // violet uniform - -1 -}; - -static int tablePartR[] = // roller.tga -{ - 0, 0, 128, 52, // wheels for track - 48, 137, 128, 201, // catalytic radiator - 0, 52, 32, 84, // front radiator - 32, 52, 43, 84, // back radiator - 0, 84, 96, 137, // large catalytic - 128, 0, 192, 85, // front - 128, 173, 192, 256, // back - 192, 0, 256, 42, // over - 128, 85, 192, 109, // catalytic pillon - 128, 109, 192, 173, // top pillon - 192, 85, 240, 109, // catalytic gate pillon - 0, 137, 24, 256, // catalytic verrin - 24, 137, 48, 256, // catalytic verrin - 48, 201, 128, 233, // medium cannon - 192, 109, 256, 173, // bottom cannon - 192, 173, 240, 205, // cannon 1 - 192, 173, 240, 177, // cannon 2 - 43, 52, 75, 84, // front cannon - 48, 233, 128, 247, // piston - 96, 105, 128, 137, // front phazer - 96, 97, 128, 105, // phazer cannon - 75, 52, 107, 84, // exhaust pipe - 192, 205, 243, 256, // nuclear power plant instruction - 192, 42, 256, 85, // reflection glass - -1 -}; - -static int tablePartW[] = // subm.tga -{ - 0, 0, 128, 26, // chenilles - 0, 26, 22, 114, // portique 1 - 0, 114, 22, 202, // portique 2 - 22, 26, 82, 56, // c�t� hublot - 22, 56, 82, 86, // c�t� ligne rouge - 22, 86, 82, 116, // c�t� simple - 22, 116, 82, 146, // avant/arri�re - 22, 146, 82, 176, // avant/arri�re + phare - 132, 82, 196, 166, // capot trainer - 132, 166, 196, 177, // capot trainer - 132, 177, 196, 188, // capot trainer - 0, 224, 96, 256, // c�t� trainer - 30, 224, 48, 256, // arri�re trainer - 136, 240, 216, 256, // barri�re courte - 96, 240, 256, 256, // barri�re longue - 128, 0, 160, 32, // black-box 1 - 160, 0, 192, 32, // black-box 2 - 192, 0, 224, 32, // black-box 3 - 224, 105, 256, 137, // TNT 1 - 224, 137, 256, 169, // TNT 2 - 82, 32, 146, 82, // factory r�solution C - 146, 32, 210, 82, // factory r�solution C - 224, 0, 256, 105, // tower r�solution C - 82, 82, 132, 150, // research r�solution C - 199, 169, 256, 233, // sac r�solution C - 106, 150, 130, 214, // cl� A - 82, 150, 106, 214, // cl� B - 132, 188, 196, 212, // cl� C - 132, 212, 196, 236, // cl� D - 210, 32, 224, 46, // gris - 56, 176, 82, 224, // sol coffre-fort - -1 -}; - -static int tablePartDr[] = // drawer.tga -{ - 128, 0, 134, 6, // bleu - 128, 6, 134, 12, // gris fonc� - 128, 12, 134, 18, // gris clair - 0, 0, 128, 32, // roues chenille - 192, 0, 256, 32, // profil chenille - 140, 0, 160, 8, // profil phare - 160, 0, 192, 32, // face phare - 0, 32, 160, 48, // hachure - 160, 32, 192, 48, // c�t� - 0, 48, 96, 96, // tableau de bord - 96, 48, 192, 112, // radiateur - 192, 32, 256, 112, // grille lat�rale - 192, 112, 256, 128, // capot - 0, 96, 8, 160, // chassis - 8, 96, 96, 104, // axe chenilles - 8, 104, 16, 160, // axe carrousel - 16, 128, 24, 160, // flan support - 224, 128, 256, 160, // rotule - 24, 104, 32, 160, // bocal (18) - 32, 104, 40, 160, // bocal - 40, 104, 48, 160, // bocal - 24, 152, 48, 160, // bocal fond - 0, 240, 32, 256, // crayon 1: couleur (22) - 0, 160, 32, 192, // crayon 1: dessus - 0, 192, 32, 256, // crayon 1: pointe - 32, 240, 64, 256, // crayon 2: couleur - 32, 160, 64, 192, // crayon 2: dessus - 32, 192, 64, 256, // crayon 2: pointe - 64, 240, 96, 256, // crayon 3: couleur - 64, 160, 96, 192, // crayon 3: dessus - 64, 192, 96, 256, // crayon 3: pointe - 96, 240, 128, 256, // crayon 4: couleur - 96, 160, 128, 192, // crayon 4: dessus - 96, 192, 128, 256, // crayon 4: pointe - 128, 240, 160, 256, // crayon 5: couleur - 128, 160, 160, 192, // crayon 5: dessus - 128, 192, 160, 256, // crayon 5: pointe - 160, 240, 192, 256, // crayon 6: couleur - 160, 160, 192, 192, // crayon 6: dessus - 160, 192, 192, 256, // crayon 6: pointe - 192, 240, 224, 256, // crayon 7: couleur - 192, 160, 224, 192, // crayon 7: dessus - 192, 192, 224, 256, // crayon 7: pointe - 224, 240, 256, 256, // crayon 8: couleur - 224, 160, 256, 192, // crayon 8: dessus - 224, 192, 256, 256, // crayon 8: pointe - -1 -}; - -static int tablePartKi[] = // kid.tga -{ - 0, 0, 128, 53, // ciseaux - 128, 0, 256, 128, // CD - 0, 0, 8, 8, // livre 1: fond - 8, 0, 16, 8, // livre 2: fond - 16, 0, 24, 8, // livre: fond - 24, 0, 32, 8, // livre: fond - 32, 0, 40, 8, // livre: fond - 40, 0, 48, 8, // livre: fond - 0, 53, 22, 138, // livre 1: tranche - 22, 53, 86, 138, // livre 1: face - 0, 138, 22, 224, // livre 2: tranche - 22, 138, 86, 224, // livre 2: face - 86, 53, 94, 85, // livre: pages - 94, 53, 110, 139, // livre: tranche - 110, 53, 126, 139, // livre: tranche - 86, 139, 102, 225, // livre: tranche - 102, 139, 118, 225, // livre: tranche - 118, 139, 134, 225, // livre: tranche - 64, 0, 72, 8, // fauille: fond - 155, 155, 256, 256, // feuille: carreaux - 72, 0, 80, 8, // lampe - 80, 0, 88, 8, // lampe - 80, 8, 88, 16, // ampoule - 72, 8, 80, 16, // rayons (23) - 86, 85, 94, 139, // lampe - 0, 224, 32, 256, // lampe rotule - 64, 8, 72, 16, // arrosoir: fond - 134, 128, 142, 256, // arrosoir: corps - 142, 128, 150, 256, // arrosoir: tuyau - 128, 225, 134, 256, // arrosoir: int�rieur - 32, 224, 64, 256, // arrosoir: ponneau - 56, 8, 64, 16, // skate: roues (31) - 48, 8, 56, 16, // skate: axes - 40, 8, 48, 16, // skate: grip - 32, 8, 40, 16, // skate: tranche - 24, 8, 32, 16, // skate: dessous - 150, 128, 200, 256, // skate: motif 1 - 200, 128, 250, 256, // skate: motif 2 - 64, 224, 96, 256, // skate: roue (38) - 96, 225, 104, 256, // skate: amortisseur - -1 -}; - -static int tablePartKi2[] = // kid2.tga -{ - 2, 2, 62, 62, // coca: dessus - 0, 64, 8, 192, // coca: flan - 8, 64, 96, 192, // coca: logo - 128, 0, 256, 85, // carton - 128, 85, 256, 91, // carton tranche - 128, 128, 256, 256, // roue - 192, 96, 256, 128, // pneu - 184, 96, 192, 128, // jante - 128, 96, 160, 128, // int�rieur - 160, 96, 168, 104, // porte bois - 160, 104, 168, 112, // porte m�tal - 160, 112, 184, 128, // vitre - 96, 0, 128, 256, // bouteille: corps (12) - 64, 0, 96, 32, // bouteille: bouchon - 168, 96, 176, 104, // bouteille: vert - 0, 192, 96, 224, // bois clair - 0, 224, 96, 256, // bois fonc� - 64, 32, 96, 64, // bateau - 168, 104, 176, 112, // ballon (18) - 176, 104, 184, 112, // ballon - 176, 96, 184, 104, // int�rieur caisse - -1 -}; - -static int tablePartKi3[] = // kid3.tga -{ - 0, 0, 32, 28, // �crou: flan - 0, 28, 32, 44, // �crou: profil - 0, 44, 32, 60, // �crou: pas de vis - 0, 60, 32, 64, // tuyau - 0, 64, 32, 68, // tuyau - 0, 68, 8, 76, // tuyau - 0, 76, 32, 108, // plastic - 8, 68, 16, 76, // saut: gris clair (7) - 16, 68, 24, 76, // saut: gris fonc� - 24, 68, 32, 76, // saut: gris bois - 0, 108, 32, 140, // saut: rotule - 0, 140, 32, 144, // saut: axe - 128, 0, 256, 128, // saut: flan - 0, 144, 8, 152, // basket: gris fonc� (13) - 8, 144, 16, 152, // basket: gris clair - 16, 144, 24, 152, // basket: gris lacets - 24, 144, 32, 152, // basket: gris semelle - 0, 152, 8, 181, // basket: int�rieur - 0, 181, 192, 256, // basket: c�t� - 192, 181, 226, 256, // basket: arri�re - 32, 135, 96, 181, // basket: dessus (20) - 96, 168, 128, 181, // basket: avant - 8, 152, 16, 160, // chaise: plastique - 16, 152, 24, 160, // chaise: m�tal - 32, 0, 64, 32, // chaise: roue - 8, 177, 24, 181, // chaise: roue - 226, 181, 234, 256, // chaise: piston (26) - 64, 96, 128, 128, // chaise: relief - 96, 135, 128, 167, // chaise: dessous - 32, 128, 250, 135, // paille 1 - 38, 128, 256, 135, // paille 2 - 234, 181, 242, 256, // allumette - 8, 160, 16, 168, // allumette (dessus) - 128, 135, 224, 181, // panneau - 242, 135, 256, 256, // poteau (34) - 24, 152, 32, 160, // clou - 16, 160, 24, 168, // tuyau m�talique - 112, 181, 192, 185, // tuyau int�rieur - 32, 32, 48, 80, // pas de vis - 24, 160, 32, 168, // ventillateur: plastique (39) - 40, 80, 56, 96, // ventillateur: plastique d�grad� - 8, 168, 16, 176, // ventillateur: m�tal - 32, 80, 40, 112, // ventillateur: socle 1 - 64, 0, 96, 16, // ventillateur: socle 2 - 48, 32, 56, 80, // ventillateur: socle 3 - 64, 16, 96, 32, // ventillateur: moteur flan - 96, 0, 128, 32, // ventillateur: moteur face - 102, 6, 122, 26, // ventillateur: socle dessus - 16, 168, 24, 176, // pot: uni (48) - 56, 32, 64, 64, // pot: haut - 56, 64, 64, 96, // pot: bas - 64, 32, 128, 96, // pot: terre - -1 -}; - -static int tablePartF[] = // factory.tga -{ - 0, 0, 152, 152, // plancher octogonal fabrique - 50, 50, 102, 102, // dessus pile - 0, 152, 128, 252, // avant - 128, 152, 256, 252, // arri�re - 152, 28, 225, 128, // c�t� - 152, 28, 176, 128, // c�t� partiel - 152, 0, 216, 16, // hachures - 236, 0, 256, 40, // axe - 152, 128, 224, 152, // support cible - -1 -}; - -static int tablePartD[] = // derrick.tga -{ - 0, 0, 64, 32, // grand c�t� - 64, 0, 96, 24, // petit c�t� - 96, 0, 136, 24, // attention - 0, 32, 8, 160, // tube 1 - 8, 32, 16, 96, // tube 2 - 16, 32, 24, 160, // pilier - 24, 32, 32, 160, // tige foret - 32, 32, 40, 160, // tige destructeur - 8, 96, 16, 128, // foret - 136, 0, 256, 120, // plancher octogonal station de recharge - 40, 32, 64, 56, // cube m�tal - 64, 24, 128, 48, // c�t� tour haut - 64, 48, 128, 229, // c�t� tour bas - 136, 120, 256, 240, // int�rieur usine - 0, 160, 64, 224, // to�t usine - -1 -}; - -static int tablePartC[] = // convert.tga -{ - 0, 0, 120, 120, // plancher octogonal convertisseur - 0, 120, 128, 176, // grand c�t� - 128, 120, 192, 176, // petit c�t� - 192, 120, 256, 184, // couvercle convertisseur - 120, 0, 216, 64, // face trianble - 216, 0, 248, 64, // c�t� triangle - 120, 64, 160, 84, // axe - 0, 141, 128, 176, // recherche: base - 0, 176, 128, 214, // recherche: haut - 0, 214, 128, 252, // recherche: haut (!) - 174, 64, 190, 120, // recherche: montant - 190, 64, 206, 120, // recherche: montant - 206, 64, 254, 85, // radar - 192, 168, 256, 232, // hachures carr�es - 248, 0, 256, 64, // c�ne fabrique de piles - 128, 176, 192, 240, // dessus centrale nucl�aire - 120, 85, 174, 120, // technicien, visage - 206, 106, 256, 120, // technicien, casquette - 160, 64, 174, 78, // technicien, visi�re - -1 -}; - -static int tablePartS[] = // search.tga -{ - 0, 0, 128, 128, // usine 1 - 128, 0, 256, 128, // usine 2 - 0, 128, 128, 256, // pile - 128, 128, 228, 240, // support pile - 228, 128, 256, 184, // antenne - 128, 128, 192, 160, // contr�le 1 - 128, 160, 192, 192, // contr�le 2 - 128, 192, 192, 224, // contr�le 3 - 128, 224, 192, 256, // contr�le 4 - -1 -}; - -static int tablePartP[] = // plant.tga -{ - 0, 160, 48, 256, // feuille 1 - 0, 0, 94, 100, // feuille 2 - 48, 156, 108, 256, // feuille 3 - 94, 0, 104, 100, // tige 1 - 185, 0, 195, 100, // tige 2 - 108, 100, 182, 256, // foug�re - 104, 0, 144, 100, // courge - 203, 0, 256, 83, // armature derrick r�solution C - -1 -}; - -static int tablePartV[] = // vegetal.tga -{ - 0, 0, 94, 100, // racine - 186, 0, 256, 256, // tronc - 162, 0, 168, 128, // mat drapeau bleu - 168, 0, 174, 128, // mat drapeau rouge - 174, 0, 180, 128, // mat drapeau vert - 180, 0, 186, 128, // mat drapeau jaune - 180, 128, 186, 256, // mat drapeau violet - 94, 0, 107, 32, // drapeau bleu - 107, 0, 120, 32, // drapeau rouge - 120, 0, 133, 32, // drapeau vert - 133, 0, 146, 32, // drapeau jaune - 146, 0, 159, 32, // drapeau violet - 94, 64, 126, 96, // verre 1 - 126, 64, 158, 86, // verre 2 - 128, 128, 180, 144, // verre 3a - 128, 144, 180, 160, // verre 3b - 128, 94, 162, 128, // verre 4 - 0, 100, 32, 228, // champignon 1 - 32, 100, 48, 228, // champignon 1 - 48, 100, 112, 228, // champignon 2 - 112, 100, 128, 228, // champignon 2 - 128, 160, 180, 212, // tronc (21) - -1 -}; - -static int tablePartM[] = // mother.tga -{ - 0, 0, 128, 128, // corps arri�re - 128, 0, 192, 128, // corps avant - 0, 128, 64, 192, // t�te - 64, 128, 192, 160, // pince ext. - 64, 160, 192, 192, // pince int. - 0, 192, 64, 256, // mire - -1 -}; - -static int tablePartA[] = // ant.tga -{ - 0, 0, 64, 64, // queue - 0, 96, 128, 160, // queue abeille - 64, 0, 128, 64, // corps - 128, 0, 192, 64, // t�te - 0, 64, 64, 72, // patte - 0, 72, 64, 80, // antenne - 64, 64, 150, 96, // queue ver - 150, 64, 182, 96, // corps ver - 182, 64, 256, 96, // t�te ver - 224, 32, 256, 64, // articulation ver - 128, 96, 220, 160, // aile - 0, 80, 16, 96, // oeil - 200, 0, 208, 8, // vert clair - 200, 8, 208, 16, // vert fonc� - 0, 160, 64, 224, // corps araign�e - 64, 160, 128, 192, // t�te araign�e - 208, 0, 216, 64, // patte araign�e - 216, 0, 224, 32, // patte araign�e - 224, 0, 256, 8, // antenne araign�e - 192, 0, 200, 8, // brun clair - 192, 8, 200, 16, // brun fonc� - 128, 160, 256, 256, // SatCom - -1 -}; - -static int tablePartH[] = // human.tga -{ - 0, 0, 64, 64, // vissi�re - 64, 0, 96, 64, // cuisse - 96, 0, 128, 64, // jambe - 128, 0, 192, 32, // bras - 128, 32, 192, 64, // avant-bras - 0, 64, 128, 224, // ventre - 128, 64, 256, 224, // dos - 64, 224, 112, 256, // dessus pied - 144, 224, 168, 240, // dessous pied - 112, 224, 144, 240, // c�t� pied - 112, 224, 128, 240, // c�t� pied - 0, 224, 64, 256, // gant - 168, 224, 200, 256, // oreille - 112, 240, 144, 256, // ligne casque - 200, 224, 208, 256, // int�rieur coup - 240, 0, 244, 64, // bombone orange - 244, 0, 248, 64, // bombone orange (reflet) - 248, 0, 252, 64, // bombone bleu - 252, 0, 256, 64, // bombone bleu (reflet) - 144, 240, 156, 256, // gris habit - 156, 240, 168, 256, // gris articulation -//? 208, 224, 256, 256, // SatCom - 192, 0, 240, 64, // quartz - -1 -}; - -static int tablePartG[] = // apollo.tga -{ - 0, 0, 64, 64, // rev�tement LEM - 64, 0, 128, 64, // rev�tement LEM - 128, 8, 136, 128, // pied - 0, 64, 64, 128, // roue - 136, 24, 152, 44, // profil pneu - 136, 8, 160, 24, // garde boue - 64, 64, 128, 128, // si�ge - 64, 128, 128, 192, // si�ge - 64, 192, 128, 212, // si�ge - 128, 128, 240, 192, // moteur - 0, 192, 28, 256, // moteur - 32, 128, 60, 256, // moteur - 224, 0, 256, 128, // avant - 206, 0, 224, 128, // avant - 136, 44, 168, 62, // avant - 64, 212, 108, 256, // panneau de commande - 198, 0, 206, 128, // mat - 190, 64, 198, 128, // mat - 160, 8, 176, 24, // cam�ra - 176, 8, 192, 24, // moyeu - 136, 64, 168, 96, // module - 168, 64, 190, 96, // module - 136, 96, 168, 128, // module - 128, 192, 230, 252, // drapeau - 0, 128, 32, 192, // antenne - 128, 0, 136, 8, // jaune - 136, 0, 144, 8, // beige - 144, 0, 152, 8, // brun - 168, 0, 176, 8, // gris tr�s clair - 152, 0, 160, 8, // gris clair - 160, 0, 168, 8, // gris fonc� - -1 -}; - -static int tablePartB[] = // base1.tga -{ - 0, 0, 80, 256, // int�rieur porte - 80, 0, 88, 256, // tranche porte - 116, 0, 180, 64, // coiffe 1 - 116, 64, 180, 102, // coiffe 2 - 180, 0, 244, 37, // base - 180, 37, 196, 101, // support - 88, 0, 116, 256, // colonne - 212, 37, 256, 128, // suppl�ment - 128, 128, 256, 256, // 1/4 du sol - 196, 37, 212, 53, // gris fonc� - 196, 53, 212, 69, // gris clair - -1 -}; - -static int tablePartCe[] = // cellar01.tga -{ - 0, 128, 64, 192, // briques - 64, 128, 128, 192, // briques - 128, 128, 192, 192, // briques - 192, 128, 256, 192, // briques - -1 -}; - -static int tablePartFa[] = // face01.tga -{ - 0, 0, 256, 256, // visage - -1 -}; - -// Retourne le pointeur la table. - -int* CModel::RetTextureTable() -{ - if ( m_textureRank == 0 ) return tablePartT; - if ( m_textureRank == 1 ) return tablePartR; - if ( m_textureRank == 2 ) return tablePartW; - if ( m_textureRank == 3 ) return tablePartDr; - if ( m_textureRank == 4 ) return tablePartKi; - if ( m_textureRank == 5 ) return tablePartKi2; - if ( m_textureRank == 6 ) return tablePartKi3; - if ( m_textureRank == 7 ) return tablePartF; - if ( m_textureRank == 8 ) return tablePartD; - if ( m_textureRank == 9 ) return tablePartC; - if ( m_textureRank == 10 ) return tablePartS; - if ( m_textureRank == 11 ) return tablePartP; - if ( m_textureRank == 12 ) return tablePartV; - if ( m_textureRank == 13 ) return tablePartM; - if ( m_textureRank == 14 ) return tablePartA; - if ( m_textureRank == 15 ) return tablePartH; - if ( m_textureRank == 16 ) return tablePartG; - if ( m_textureRank == 17 ) return tablePartB; - if ( m_textureRank == 18 ) return tablePartCe; - if ( m_textureRank == 19 ) return tablePartFa; - if ( m_textureRank == 20 ) return tablePartFa; - if ( m_textureRank == 21 ) return tablePartFa; - if ( m_textureRank == 22 ) return tablePartFa; - return 0; -} - -// Updates the part of texture. - -void CModel::TexturePartUpdate() -{ - int *table; - - table = RetTextureTable(); - if ( table == 0 ) return; - - m_textureInf.x = (table[m_texturePart*4+0]+0.5f)/256.0f; - m_textureInf.y = (table[m_texturePart*4+1]+0.5f)/256.0f; - m_textureSup.x = (table[m_texturePart*4+2]-0.5f)/256.0f; - m_textureSup.y = (table[m_texturePart*4+3]-0.5f)/256.0f; - - PutTextureValues(); -} - -// Changes the texture. - -void CModel::TextureRankChange(int step) -{ - m_textureRank += step; - - if ( m_textureRank >= MAX_NAMES ) m_textureRank = 0; - if ( m_textureRank < 0 ) m_textureRank = MAX_NAMES-1; - - if ( m_textureRank == 0 ) strcpy(m_textureName, "lemt.tga"); - if ( m_textureRank == 1 ) strcpy(m_textureName, "roller.tga"); - if ( m_textureRank == 2 ) strcpy(m_textureName, "subm.tga"); - if ( m_textureRank == 3 ) strcpy(m_textureName, "drawer.tga"); - if ( m_textureRank == 4 ) strcpy(m_textureName, "kid.tga"); - if ( m_textureRank == 5 ) strcpy(m_textureName, "kid2.tga"); - if ( m_textureRank == 6 ) strcpy(m_textureName, "kid3.tga"); - if ( m_textureRank == 7 ) strcpy(m_textureName, "factory.tga"); - if ( m_textureRank == 8 ) strcpy(m_textureName, "derrick.tga"); - if ( m_textureRank == 9 ) strcpy(m_textureName, "convert.tga"); - if ( m_textureRank == 10 ) strcpy(m_textureName, "search.tga"); - if ( m_textureRank == 11 ) strcpy(m_textureName, "plant.tga"); - if ( m_textureRank == 12 ) strcpy(m_textureName, "vegetal.tga"); - if ( m_textureRank == 13 ) strcpy(m_textureName, "mother.tga"); - if ( m_textureRank == 14 ) strcpy(m_textureName, "ant.tga"); - if ( m_textureRank == 15 ) strcpy(m_textureName, "human.tga"); - if ( m_textureRank == 16 ) strcpy(m_textureName, "apollo.tga"); - if ( m_textureRank == 17 ) strcpy(m_textureName, "base1.tga"); - if ( m_textureRank == 18 ) strcpy(m_textureName, "cellar01.tga"); - if ( m_textureRank == 19 ) strcpy(m_textureName, "face01.tga"); - if ( m_textureRank == 20 ) strcpy(m_textureName, "face02.tga"); - if ( m_textureRank == 21 ) strcpy(m_textureName, "face03.tga"); - if ( m_textureRank == 22 ) strcpy(m_textureName, "face04.tga"); - - m_texturePart = 0; -} - -// Changes the part of texture. - -void CModel::TexturePartChange(int step) -{ - int *table; - - table = RetTextureTable(); - if ( table == 0 ) return; - - m_texturePart ++; - - if ( table[m_texturePart*4] == -1 ) - { - m_texturePart = 0; - } - - TexturePartUpdate(); -} - - +// * 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/. + +// model.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/water.h" +#include "object/robotmain.h" +#include "ui/interface.h" +#include "ui/edit.h" +#include "ui/button.h" +#include "script/cmdtoken.h" +#include "old/modfile.h" +#include "old/model.h" + + + +const int MAX_COLORS = 9; + +static float table_color[MAX_COLORS*3] = +{ + 1.0f, 1.0f, 1.0f, // white + 1.0f, 0.0f, 0.0f, // red + 0.0f, 1.0f, 0.0f, // green + 0.0f, 0.6f, 1.0f, // blue + 1.0f, 1.0f, 0.0f, // yellow + 0.0f, 1.0f, 1.0f, // cyan + 1.0f, 0.0f, 1.0f, // magenta + 0.3f, 0.3f, 0.3f, // grey + 0.0f, 0.0f, 0.0f, // black +}; + + +const int MAX_STATES = 10; + +static int table_state[MAX_STATES] = +{ + D3DSTATENORMAL, + D3DSTATEPART1, + D3DSTATEPART2, + D3DSTATEPART3, + D3DSTATEPART4, + D3DSTATE2FACE, // #5 + D3DSTATETTw, + D3DSTATETTb, + D3DSTATETTw|D3DSTATE2FACE, // #8 + D3DSTATETTb|D3DSTATE2FACE, // #9 +}; + + +const int MAX_NAMES = 23; + + + + +// Object's constructor. + +CModel::CModel(CInstanceManager* iMan) +{ + m_iMan = iMan; + + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE); + + m_modFile = new CModFile(m_iMan); + m_triangleTable = m_modFile->RetTriangleList(); + + m_textureRank = 0; + strcpy(m_textureName, "lemt.tga"); + m_color = 0; + m_state = 0; + m_textureMode = 0; + m_textureRotate = 0; + m_bTextureMirrorX = false; + m_bTextureMirrorY = false; + m_texturePart = 0; + TexturePartUpdate(); + + m_bDisplayTransparent = false; + m_bDisplayOnlySelection = false; + InitView(); + + m_triangleSel1 = 0; + m_triangleSel2 = 0; + + m_mode = 1; + m_oper = 'P'; + + m_secondTexNum = 0; + m_secondSubdiv = 1; + m_secondOffsetU = 0; + m_secondOffsetV = 0; + + m_min = 0.0f; + m_max = 1000000.0f; +} + +// Object's destructor. + +CModel::~CModel() +{ + delete m_modFile; +} + + +// You must call this procedure before changing the model interactively. + +void CModel::StartUserAction() +{ + Event event; + Math::Point pos, dim; + CButton* pb; + + dim.x = 105.0f/640.0f; + dim.y = 18.0f/480.0f; + pos.x = 10.0f/640.0f; + pos.y = 450.0f/480.0f; + m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT1); + + dim.x = 50.0f/640.0f; + pos.x = 125.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON1); + pb->SetState(STATE_SIMPLY); + pb->SetName("Load"); + pos.x = 185.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON2); + pb->SetState(STATE_SIMPLY); + pb->SetName("Script"); + pos.x = 245.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON3); + pb->SetState(STATE_SIMPLY); + pb->SetName("Read"); + pos.x = 305.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON4); + pb->SetState(STATE_SIMPLY); + pb->SetName("Add"); + pos.x = 365.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON5); + pb->SetState(STATE_SIMPLY); + pb->SetName("Write"); + + dim.x = 50.0f/640.0f; + dim.y = 18.0f/480.0f; + pos.x = 10.0f/640.0f; + pos.y = 425.0f/480.0f; + m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT2); + pos.x = 65.0f/640.0f; + pos.y = 425.0f/480.0f; + m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT3); + pos.x = 10.0f/640.0f; + pos.y = 400.0f/480.0f; + m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT4); + pos.x = 65.0f/640.0f; + pos.y = 400.0f/480.0f; + m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT5); + + dim.x = 20.0f/640.0f; + dim.y = 20.0f/480.0f; + pos.y = 370.0f/480.0f; + pos.x = 10.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON10); + pb->SetState(STATE_SIMPLY); + pb->SetName("P"); + pos.x = 30.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON11); + pb->SetState(STATE_SIMPLY); + pb->SetName("R"); + pos.x = 50.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON12); + pb->SetState(STATE_SIMPLY); + pb->SetName("Z"); + pos.y = 350.0f/480.0f; + pos.x = 10.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON13); + pb->SetState(STATE_SIMPLY); + pb->SetName("+X"); + pos.x = 30.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON14); + pb->SetState(STATE_SIMPLY); + pb->SetName("+Y"); + pos.x = 50.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON15); + pb->SetState(STATE_SIMPLY); + pb->SetName("+Z"); + pos.y = 330.0f/480.0f; + pos.x = 10.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON16); + pb->SetState(STATE_SIMPLY); + pb->SetName("-X"); + pos.x = 30.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON17); + pb->SetState(STATE_SIMPLY); + pb->SetName("-Y"); + pos.x = 50.0f/640.0f; + pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON18); + pb->SetState(STATE_SIMPLY); + pb->SetName("-Z"); + +//? m_modFile->ReadModel("objects\\io.mod"); + DeselectAll(); + CurrentInit(); + + ZeroMemory(&event, sizeof(Event)); + EventFrame(event); + + m_engine->LoadAllTexture(); + UpdateInfoText(); +} + +// You must call this procedure after modifing the model interactively. + +void CModel::StopUserAction() +{ + m_interface->DeleteControl(EVENT_EDIT1); + m_interface->DeleteControl(EVENT_EDIT2); + m_interface->DeleteControl(EVENT_EDIT3); + m_interface->DeleteControl(EVENT_EDIT4); + m_interface->DeleteControl(EVENT_EDIT5); + m_interface->DeleteControl(EVENT_BUTTON1); + m_interface->DeleteControl(EVENT_BUTTON2); + m_interface->DeleteControl(EVENT_BUTTON3); + m_interface->DeleteControl(EVENT_BUTTON4); + m_interface->DeleteControl(EVENT_BUTTON5); + m_interface->DeleteControl(EVENT_BUTTON10); + m_interface->DeleteControl(EVENT_BUTTON11); + m_interface->DeleteControl(EVENT_BUTTON12); + m_interface->DeleteControl(EVENT_BUTTON13); + m_interface->DeleteControl(EVENT_BUTTON14); + m_interface->DeleteControl(EVENT_BUTTON15); + m_interface->DeleteControl(EVENT_BUTTON16); + m_interface->DeleteControl(EVENT_BUTTON17); + m_interface->DeleteControl(EVENT_BUTTON18); + + m_engine->SetInfoText(0, ""); + m_engine->SetInfoText(1, ""); +} + + +// Updates the​editable values for mapping textures. + +void CModel::PutTextureValues() +{ + CEdit* pe; + char s[100]; + int value; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); + if ( pe != 0 ) + { + value = (int)(m_textureSup.x*256.0f+0.5f); + sprintf(s, "%d", value); + pe->SetText(s); + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); + if ( pe != 0 ) + { + value = (int)(m_textureSup.y*256.0f+0.5f); + sprintf(s, "%d", value); + pe->SetText(s); + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); + if ( pe != 0 ) + { + value = (int)(m_textureInf.x*256.0f-0.5f); + sprintf(s, "%d", value); + pe->SetText(s); + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); + if ( pe != 0 ) + { + value = (int)(m_textureInf.y*256.0f-0.5f); + sprintf(s, "%d", value); + pe->SetText(s); + } +} + +// Takes the editable values for mapping textures. + +void CModel::GetTextureValues() +{ + CEdit* pe; + char s[100]; + int value; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); + if ( pe != 0 ) + { + pe->GetText(s, 100); + sscanf(s, "%d", &value); + m_textureSup.x = ((float)value-0.5f)/256.0f; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); + if ( pe != 0 ) + { + pe->GetText(s, 100); + sscanf(s, "%d", &value); + m_textureSup.y = ((float)value-0.5f)/256.0f; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); + if ( pe != 0 ) + { + pe->GetText(s, 100); + sscanf(s, "%d", &value); + m_textureInf.x = ((float)value+0.5f)/256.0f; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); + if ( pe != 0 ) + { + pe->GetText(s, 100); + sscanf(s, "%d", &value); + m_textureInf.y = ((float)value+0.5f)/256.0f; + } +} + + +// Gives the model name. + +void CModel::GetModelName(char *buffer) +{ + CEdit* pe; + char s[100]; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); + if ( pe == 0 ) + { + strcpy(buffer, "objects\\io.mod"); + } + else + { + pe->GetText(s, 100); + sprintf(buffer, "objects\\%s.mod", s); + } +} + +// Gives the model name. + +void CModel::GetDXFName(char *buffer) +{ + CEdit* pe; + char s[100]; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); + if ( pe == 0 ) + { + strcpy(buffer, "models\\import.dxf"); + } + else + { + pe->GetText(s, 100); + sprintf(buffer, "models\\%s.dxf", s); + } +} + +// Gives the model name. + +void CModel::GetScriptName(char *buffer) +{ + CEdit* pe; + char s[100]; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); + if ( pe == 0 ) + { + strcpy(buffer, "objects\\script.txt"); + } + else + { + pe->GetText(s, 100); + sprintf(buffer, "objects\\%s.txt", s); + } +} + +// Indicates whether the edition name has focus. + +bool CModel::IsEditFocus() +{ + CEdit* pe; + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1); + if ( pe != 0 ) + { + if ( pe->RetFocus() ) return true; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2); + if ( pe != 0 ) + { + if ( pe->RetFocus() ) return true; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3); + if ( pe != 0 ) + { + if ( pe->RetFocus() ) return true; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4); + if ( pe != 0 ) + { + if ( pe->RetFocus() ) return true; + } + + pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5); + if ( pe != 0 ) + { + if ( pe->RetFocus() ) return true; + } + + return false; +} + + +// Management of an event. + +bool CModel::EventProcess(const Event &event) +{ + char s[100]; + int first, last; + + switch( event.event ) + { + case EVENT_FRAME: + EventFrame(event); + break; + + case EVENT_KEYDOWN: + if ( IsEditFocus() ) + break; + + if ( event.param == '1' ) + { + m_mode = 1; + UpdateInfoText(); + } + if ( event.param == '2' ) + { + m_mode = 2; + UpdateInfoText(); + } + if ( event.param == '3' ) + { + m_mode = 3; + UpdateInfoText(); + } + if ( event.param == VK_ADD ) // numpad? + { + if ( event.keyState & KS_SHIFT ) CurrentSelect(true); + CurrentSearchNext(+1, (event.keyState & KS_CONTROL)); + } + if ( event.param == VK_SUBTRACT ) // least numpad? + { + if ( event.keyState & KS_SHIFT ) CurrentSelect(true); + CurrentSearchNext(-1, (event.keyState & KS_CONTROL)); + } + if ( event.param == VK_NUMPAD0 ) + { + CurrentSelect(false); + } + if ( event.param == VK_DECIMAL ) + { + CurrentSelect(true); + } + if ( event.param == VK_END ) + { + DeselectAll(); + } + if ( event.param == VK_INSERT ) + { + SelectAll(); + } + if ( event.param == VK_BACK ) // Delete normal ? + { + SelectDelete(); + } + if ( event.param == VK_SPACE ) + { + m_bDisplayTransparent = !m_bDisplayTransparent; + m_bDisplayOnlySelection = false; + } + if ( event.param == 'H' ) + { + m_bDisplayOnlySelection = !m_bDisplayOnlySelection; + m_bDisplayTransparent = false; + } + if ( m_mode == 1 ) + { + if ( event.param == 'S' ) + { + SmoothSelect(); + } + if ( event.param == 'N' ) + { + PlaneSelect(); + } + if ( event.param == 'C' ) + { + ColorSelect(); + } + if ( event.param == 'V' ) + { + m_color ++; + if ( m_color >= MAX_COLORS ) m_color = 0; + UpdateInfoText(); + ColorSelect(); + } + if ( event.param == 'J' ) + { + StateSelect(); + } + if ( event.param == 'K' ) + { + m_state ++; + if ( m_state >= MAX_STATES ) m_state = 0; + UpdateInfoText(); + StateSelect(); + } + if ( event.param == 'M' ) + { + m_textureMode ++; + if ( m_textureMode > 3 ) m_textureMode = 0; + UpdateInfoText(); + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'Z' ) + { + m_textureRotate ++; + if ( m_textureRotate > 2 ) m_textureRotate = 0; + UpdateInfoText(); + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'X' ) + { + m_bTextureMirrorX = !m_bTextureMirrorX; + UpdateInfoText(); + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'Y' ) + { + m_bTextureMirrorY = !m_bTextureMirrorY; + UpdateInfoText(); + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'O' ) + { + TextureRankChange(+1); + UpdateInfoText(); + } + if ( event.param == 'P' ) + { + TexturePartChange(+1); + UpdateInfoText(); + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'T' ) + { + GetTextureValues(); + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_textureInf, m_textureSup, m_textureName); + } + if ( event.param == 'E' ) + { + Math::Point ti, ts; + ti.x = 0.00f; + ti.y = 0.00f; + ts.x = 0.00f; + ts.y = 0.00f; + MappingSelect(m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + ti, ts, ""); + } + } + if ( m_mode == 2 ) + { + if ( event.param == 'E' ) + { + m_secondTexNum = 0; + UpdateInfoText(); + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + } + if ( event.param == 'O' ) + { + m_secondTexNum ++; + if ( m_secondTexNum > 10 ) m_secondTexNum = 1; + UpdateInfoText(); + } + if ( event.param == 'T' ) + { + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + m_engine->LoadAllTexture(); + } + if ( event.param == 'U' ) + { + m_secondOffsetU += 45; + if ( m_secondOffsetU >= 360 ) m_secondOffsetU = 0; + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + UpdateInfoText(); + } + if ( event.param == 'V' ) + { + m_secondOffsetV += 45; + if ( m_secondOffsetV >= 360 ) m_secondOffsetV = 0; + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + UpdateInfoText(); + } + if ( event.param == 'X' ) + { + m_bTextureMirrorX = !m_bTextureMirrorX; + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + UpdateInfoText(); + } + if ( event.param == 'Y' ) + { + m_bTextureMirrorY = !m_bTextureMirrorY; + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + UpdateInfoText(); + } + if ( event.param == 'S' ) + { + m_secondSubdiv ++; + if ( m_secondSubdiv > 7 ) m_secondSubdiv = 1; + MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY); + UpdateInfoText(); + } + } + if ( m_mode == 3 ) + { + if ( event.param == 'M' ) + { + if ( m_min == 0.0f && m_max == 1000000.0f ) + { + m_min = 0.0f; m_max = 100.0f; + } + else if ( m_min == 0.0f && m_max == 100.0f ) + { + m_min = 100.0f; m_max = 200.0f; + } + else if ( m_min == 100.0f && m_max == 200.0f ) + { + m_min = 200.0f; m_max = 1000000.0f; + } + else if ( m_min == 200.0f && m_max == 1000000.0f ) + { + m_min = 0.0f; m_max = 1000000.0f; + } + UpdateInfoText(); + } + if ( event.param == 'C' ) + { + MinMaxChange(); + } + } + break; + + case EVENT_BUTTON1: // import ? + GetDXFName(s); + m_modFile->ReadDXF(s, m_min, m_max); + DeselectAll(); + CurrentInit(); + EventFrame(event); + m_engine->LoadAllTexture(); + break; + + case EVENT_BUTTON2: // script ? + GetScriptName(s); + ReadScript(s); + DeselectAll(); + CurrentInit(); + EventFrame(event); + m_engine->LoadAllTexture(); + break; + + case EVENT_BUTTON3: // read ? + GetModelName(s); + m_modFile->ReadModel(s, true, false); // standard read with borders + DeselectAll(); + CurrentInit(); + EventFrame(event); + m_engine->LoadAllTexture(); + break; + + case EVENT_BUTTON4: // add ? + GetModelName(s); + first = m_modFile->RetTriangleUsed(); + m_modFile->AddModel(s, first, true, false); // standard read with borders + last = m_modFile->RetTriangleUsed(); + SelectZone(first, last); + EventFrame(event); + break; + + case EVENT_BUTTON5: // write ? + GetModelName(s); + DeselectAll(); + m_modFile->WriteModel(s); + break; + + case EVENT_BUTTON10: // pos ? + m_oper = 'P'; + break; + case EVENT_BUTTON11: // rotate ? + m_oper = 'R'; + break; + case EVENT_BUTTON12: // zoom ? + m_oper = 'Z'; + break; + + case EVENT_BUTTON13: // +X ? + MoveSelect(Math::Vector(1.0f, 0.0f, 0.0f)); + break; + case EVENT_BUTTON16: // -X ? + MoveSelect(Math::Vector(-1.0f, 0.0f, 0.0f)); + break; + case EVENT_BUTTON14: // +Y ? + MoveSelect(Math::Vector(0.0f, 1.0f, 0.0f)); + break; + case EVENT_BUTTON17: // -Y ? + MoveSelect(Math::Vector(0.0f, -1.0f, 0.0f)); + break; + case EVENT_BUTTON15: // +Z ? + MoveSelect(Math::Vector(0.0f, 0.0f, 1.0f)); + break; + case EVENT_BUTTON18: // -Z ? + MoveSelect(Math::Vector(0.0f, 0.0f, -1.0f)); + break; + } + + return 0; +} + + +// Drives the model. + +bool CModel::EventFrame(const Event &event) +{ + D3DMATERIAL7 matCurrent, matCurrenti, matCurrents, matTrans; + D3DMATERIAL7* pMat; + D3DVERTEX2 vertex[3]; + char texName2[20]; + int i, used, objRank, state; + + m_time += event.rTime; + + m_engine->FlushObject(); + objRank = m_engine->CreateObject(); + + ZeroMemory(&matCurrent, sizeof(D3DMATERIAL7)); + matCurrent.diffuse.r = 1.0f; + matCurrent.diffuse.g = 0.0f; + matCurrent.diffuse.b = 0.0f; // red + matCurrent.ambient.r = 0.5f; + matCurrent.ambient.g = 0.5f; + matCurrent.ambient.b = 0.5f; + + ZeroMemory(&matCurrents, sizeof(D3DMATERIAL7)); + matCurrents.diffuse.r = 1.0f; + matCurrents.diffuse.g = 1.0f; + matCurrents.diffuse.b = 0.0f; // yellow + matCurrents.ambient.r = 0.5f; + matCurrents.ambient.g = 0.5f; + matCurrents.ambient.b = 0.5f; + + ZeroMemory(&matCurrenti, sizeof(D3DMATERIAL7)); + matCurrenti.diffuse.r = 0.0f; + matCurrenti.diffuse.g = 0.0f; + matCurrenti.diffuse.b = 1.0f; // blue + matCurrenti.ambient.r = 0.5f; + matCurrenti.ambient.g = 0.5f; + matCurrenti.ambient.b = 0.5f; + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; i= m_triangleSel1 && + i <= m_triangleSel2 && + (int)(m_time*10.0f)%2 == 0 ) + { + pMat = &matCurrent; + } + else if ( m_triangleTable[i].bSelect && + (int)(m_time*10.0f)%2 == 0 ) + { + pMat = &matCurrents; + } + else + { + if ( m_bDisplayOnlySelection ) continue; + if ( m_bDisplayTransparent ) + { + matTrans = m_triangleTable[i].material; + matTrans.diffuse.a = 0.1f; // very transparent + pMat = &matTrans; + state = D3DSTATETD; + } + } + + if ( m_triangleTable[i].texNum2 == 0 ) + { + m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, + *pMat, state, + m_triangleTable[i].texName, "", + 0.0f, 1000000.0f, false); + } + else + { + sprintf(texName2, "dirty%.2d.tga", m_triangleTable[i].texNum2); + m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, + *pMat, state|D3DSTATEDUALb, + m_triangleTable[i].texName, texName2, + 0.0f, 1000000.0f, false); + } + + if ( m_bDisplayTransparent && // draws inside? + i >= m_triangleSel1 && + i <= m_triangleSel2 ) + { + vertex[0] = m_triangleTable[i].p3; + vertex[1] = m_triangleTable[i].p2; + vertex[2] = m_triangleTable[i].p1; + + m_engine->AddTriangle(objRank, vertex, 3, + matCurrenti, D3DSTATENORMAL, + m_triangleTable[i].texName, "", + 0.0f, 1000000.0f, false); + } + } + + return true; +} + + +// Gives a vertex. + +bool CModel::GetVertex(int rank, D3DVERTEX2 &vertex) +{ + if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return false; + if ( !m_triangleTable[rank/3].bUsed ) return false; + + if ( !m_triangleTable[rank/3].bSelect ) return false; + + if ( rank%3 == 0 ) + { + vertex = m_triangleTable[rank/3].p1; + return true; + } + if ( rank%3 == 1 ) + { + vertex = m_triangleTable[rank/3].p2; + return true; + } + if ( rank%3 == 2 ) + { + vertex = m_triangleTable[rank/3].p3; + return true; + } + return false; +} + +// Modifies a vertex. + +bool CModel::SetVertex(int rank, D3DVERTEX2 &vertex) +{ + if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return false; + if ( !m_triangleTable[rank/3].bUsed ) return false; + + if ( !m_triangleTable[rank/3].bSelect ) return false; + + if ( rank%3 == 0 ) + { + m_triangleTable[rank/3].p1 = vertex; + return true; + } + if ( rank%3 == 1 ) + { + m_triangleTable[rank/3].p2 = vertex; + return true; + } + if ( rank%3 == 2 ) + { + m_triangleTable[rank/3].p3 = vertex; + return true; + } + return false; +} + +// Smoothed normals selected triangles. + +void CModel::SmoothSelect() +{ + char* bDone; + int index[100]; + int used, i, j, rank; + D3DVERTEX2 vi, vj; + Math::Vector sum; + + used = m_modFile->RetTriangleUsed(); + + bDone = (char*)malloc(used*3*sizeof(char)); + for ( i=0 ; i= 100 ) break; + } + } + + sum.x = 0; + sum.y = 0; + sum.z = 0; + for ( j=0 ; jRetTriangleUsed(); + + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iReadModel(buffer, true, true); + last = m_modFile->RetTriangleUsed(); + SelectZone(0, last); + } + else + { + first = m_modFile->RetTriangleUsed(); + m_modFile->AddModel(buffer, first, true, false); + last = m_modFile->RetTriangleUsed(); + SelectZone(first, last); + } + bFirst = false; + + move = OpDir(line, "zoom"); + OperSelect(move, 'Z'); + + move = OpDir(line, "rot"); + move *= Math::PI/180.0f; // degrees -> radians + OperSelect(move, 'R'); + + move = OpDir(line, "pos"); + OperSelect(move, 'P'); + } + } + + fclose(file); +} + + + +// Computes the bbox of selected triangles. + +void CModel::BBoxCompute(Math::Vector &min, Math::Vector &max) +{ + D3DVERTEX2 vertex; + int used, i; + + min.x = 1000000.0f; + min.y = 1000000.0f; + min.z = 1000000.0f; + max.x = -1000000.0f; + max.y = -1000000.0f; + max.z = -1000000.0f; + + used = m_modFile->RetTriangleUsed(); + + for ( i=0 ; i max.x ) max.x = vertex.x; + if ( vertex.y > max.y ) max.y = vertex.y; + if ( vertex.z > max.z ) max.z = vertex.z; + } +} + +// Returns the gravity center of the selection. + +Math::Vector CModel::RetSelectCDG() +{ + Math::Vector min, max, cdg; + + BBoxCompute(min, max); + + cdg.x = (min.x+max.x)/2.0f; + cdg.y = (min.y+max.y)/2.0f; + cdg.z = (min.z+max.z)/2.0f; + + return cdg; +} + +// Returns the normal vector of the selection. + +Math::Vector CModel::RetSelectNormal() +{ + Math::Vector p1, p2, p3, n; + + p1.x = m_triangleTable[m_triangleSel1].p1.nx; + p1.y = m_triangleTable[m_triangleSel1].p1.ny; + p1.z = m_triangleTable[m_triangleSel1].p1.nz; + + p2.x = m_triangleTable[m_triangleSel1].p2.nx; + p2.y = m_triangleTable[m_triangleSel1].p2.ny; + p2.z = m_triangleTable[m_triangleSel1].p2.nz; + + p3.x = m_triangleTable[m_triangleSel1].p3.nx; + p3.y = m_triangleTable[m_triangleSel1].p3.ny; + p3.z = m_triangleTable[m_triangleSel1].p3.nz; + + n = Normalize(p1+p2+p3); + + return n; +} + +// Maps a texture onto the selected triangles. + +bool CModel::IsMappingSelectPlausible(D3DMaping D3Dmode) +{ + D3DVERTEX2 vertex[3]; + Math::Vector min, max; + Math::Point a, b, ti, ts; + float au, bu, av, bv; + int used, i, j; + + ti.x = 0.0f; + ti.y = 0.0f; + ts.x = 1.0f; + ts.y = 1.0f; + + BBoxCompute(min, max); + + if ( D3Dmode == D3DMAPPINGX ) + { + a.x = min.z; + a.y = min.y; + b.x = max.z; + b.y = max.y; + } + if ( D3Dmode == D3DMAPPINGY ) + { + a.x = min.x; + a.y = min.z; + b.x = max.x; + b.y = max.z; + } + if ( D3Dmode == D3DMAPPINGZ ) + { + a.x = min.x; + a.y = min.y; + b.x = max.x; + b.y = max.y; + } + + au = (ts.x-ti.x)/(b.x-a.x); + bu = ts.x-b.x*(ts.x-ti.x)/(b.x-a.x); + + av = (ts.y-ti.y)/(b.y-a.y); + bv = ts.y-b.y*(ts.y-ti.y)/(b.y-a.y); + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; i 1.0f ) u[j] -= 1.0f; +#else + u[j] = Math::RotateAngle(p.x, p.z)/Math::PI; +//? if ( u[j] > 1.0f ) u[j] = 2.0f-u[j]; + if ( u[j] > 1.0f ) u[j] -= 1.0f; +#endif + + v[j] = p.y/dim.y/2.0f + 0.5f; + + if ( u[j] < 0.5f ) m[j] = u[j]; + else m[j] = u[j]-1.0f; + } + + avg = (m[0]+m[1]+m[2])/3.0f; + + for ( j=0 ; j<3 ; j++ ) + { + if ( u[j] < 0.05f || u[j] > 0.95f ) + { + if ( avg > 0.0f ) u[j] = 0.0f; + else u[j] = 1.0f; + } + + vertex[j].tu = ti.x+(ts.x-ti.x)*u[j]; + vertex[j].tv = ti.y+(ts.y-ti.y)*v[j]; + + SetVertex(i*3+j, vertex[j]); + } + } + + SelectTerm(); +} + + +// Maps a secondary texture on selected triangles. + +void CModel::MappingSelect2(int texNum2, int subdiv, + int offsetU, int offsetV, + bool bMirrorX, bool bMirrorY) +{ + D3DVERTEX2 vertex; + Math::Vector min, max, center, p; + float u ,v; + int used, i; + + DefaultSelect(); + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; i 2 ) + { + MappingSelectPlane2(subdiv-3, bMirrorX, bMirrorY); + return; + } + + BBoxCompute(min, max); + center = (min+max)/2.0f; + + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; i= Math::Max(n.y, n.z) ) mode = 0; + if ( n.y >= Math::Max(n.x, n.z) ) mode = 1; + if ( n.z >= Math::Max(n.x, n.y) ) mode = 2; + } + + if ( !GetVertex(i, vertex) ) continue; + + if ( mode == 0 ) + { + vertex.tu2 = vertex.z*au.z+bu.z; + vertex.tv2 = vertex.y*av.y+bv.y; + } + if ( mode == 1 ) + { + vertex.tu2 = vertex.x*au.x+bu.x; + vertex.tv2 = vertex.z*av.z+bv.z; + } + if ( mode == 2 ) + { + vertex.tu2 = vertex.x*au.x+bu.x; + vertex.tv2 = vertex.y*av.y+bv.y; + } + + SetVertex(i, vertex); + } + + SelectTerm(); +} + + +// Seeks the next triangle. + +int CModel::SearchNext(int rank, int step) +{ + int max, i; + + max = m_modFile->RetTriangleUsed(); + + for ( i=0 ; i= max ) rank = 0; + + if ( m_triangleTable[rank].min != m_min || + m_triangleTable[rank].max != m_max ) continue; + + if ( m_triangleTable[rank].bUsed ) break; + } + return rank; +} + +// Seeks all the triangles belonging to the same plane. + +int CModel::SearchSamePlane(int first, int step) +{ + Math::Vector vFirst[3], vNext[3]; + int last, i; + + vFirst[0].x = m_triangleTable[first].p1.x; + vFirst[0].y = m_triangleTable[first].p1.y; + vFirst[0].z = m_triangleTable[first].p1.z; + vFirst[1].x = m_triangleTable[first].p2.x; + vFirst[1].y = m_triangleTable[first].p2.y; + vFirst[1].z = m_triangleTable[first].p2.z; + vFirst[2].x = m_triangleTable[first].p3.x; + vFirst[2].y = m_triangleTable[first].p3.y; + vFirst[2].z = m_triangleTable[first].p3.z; + + for ( i=0 ; i<1000 ; i++ ) + { + last = first; + first = SearchNext(first, step); + + vNext[0].x = m_triangleTable[first].p1.x; + vNext[0].y = m_triangleTable[first].p1.y; + vNext[0].z = m_triangleTable[first].p1.z; + vNext[1].x = m_triangleTable[first].p2.x; + vNext[1].y = m_triangleTable[first].p2.y; + vNext[1].z = m_triangleTable[first].p2.z; + vNext[2].x = m_triangleTable[first].p3.x; + vNext[2].y = m_triangleTable[first].p3.y; + vNext[2].z = m_triangleTable[first].p3.z; + + if ( !IsSamePlane(vFirst, vNext) ) // other plan? + { + return last; + } + } + return first; +} + +// Seeks the next triangle. + +void CModel::CurrentSearchNext(int step, bool bControl) +{ + if ( step > 0 ) // forward? + { + m_triangleSel1 = SearchNext(m_triangleSel2, step); + if ( bControl ) + { + m_triangleSel2 = m_triangleSel1; + } + else + { + m_triangleSel2 = SearchSamePlane(m_triangleSel1, step); + } + } + if ( step < 0 ) // back? + { + m_triangleSel2 = SearchNext(m_triangleSel1, step); + if ( bControl ) + { + m_triangleSel1 = m_triangleSel2; + } + else + { + m_triangleSel1 = SearchSamePlane(m_triangleSel2, step); + } + } + +#if 0 + char s[100]; + sprintf(s, "(%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f)", + m_triangleTable[m_triangleSel1].p1.x, + m_triangleTable[m_triangleSel1].p1.y, + m_triangleTable[m_triangleSel1].p1.z, + m_triangleTable[m_triangleSel1].p2.x, + m_triangleTable[m_triangleSel1].p2.y, + m_triangleTable[m_triangleSel1].p2.z, + m_triangleTable[m_triangleSel1].p3.x, + m_triangleTable[m_triangleSel1].p3.y, + m_triangleTable[m_triangleSel1].p3.z); + m_engine->SetInfoText(2, s); + sprintf(s, "(%.2f;%.2f) (%.2f;%.2f) (%.2f;%.2f)", + m_triangleTable[m_triangleSel1].p1.tu2, + m_triangleTable[m_triangleSel1].p1.tv2, + m_triangleTable[m_triangleSel1].p2.tu2, + m_triangleTable[m_triangleSel1].p2.tv2, + m_triangleTable[m_triangleSel1].p3.tu2, + m_triangleTable[m_triangleSel1].p3.tv2); + m_engine->SetInfoText(3, s); +#endif + + InitViewFromSelect(); + UpdateInfoText(); +} + +// Initializes the current triangles. + +void CModel::CurrentInit() +{ + m_triangleSel1 = 0; + m_triangleSel2 = SearchSamePlane(m_triangleSel1, +1); + + InitViewFromSelect(); + UpdateInfoText(); +} + +// Selects the current triangles. + +void CModel::CurrentSelect(bool bSelect) +{ + int i; + + for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ ) + { + m_triangleTable[i].bSelect = bSelect; + } +} + + +// Deselects all triangles. + +void CModel::DeselectAll() +{ + int used, i; + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; i= first && i < last ) + { + m_triangleTable[i].bSelect = true; + } + } + m_triangleSel1 = first; + m_triangleSel2 = last-1; +} + +// Selects all triangles. + +void CModel::SelectAll() +{ + int used, i; + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; i= m_triangleSel1 && i <= m_triangleSel2 ) + { + if ( !m_triangleTable[i].bSelect ) return; + } + else + { + if ( m_triangleTable[i].bSelect ) return; + } + } + + DeselectAll(); +} + +// Selects the triangles currents. + +void CModel::DefaultSelect() +{ + int used, i; + + used = m_modFile->RetTriangleUsed(); + for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ ) + { + m_triangleTable[i].bSelect = true; + } +} + + + +// Removes all selected triangles. + +void CModel::SelectDelete() +{ + int used ,i; + + DefaultSelect(); + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; iRetTriangleUsed(); + for ( i=0 ; iSetTriangleUsed(j); + CurrentInit(); +} + + +// Change the min / max of all selected triangles. + +void CModel::MinMaxChange() +{ + int used, i; + + DefaultSelect(); + + used = m_modFile->RetTriangleUsed(); + for ( i=0 ; i= Math::PI ) + { + m_viewAngleV -= Math::PI; + m_viewAngleH -= Math::PI; + } + m_viewAngleV *= 0.75f; + + char s[100]; + sprintf(s, "angle=%f %f -> %f %f\n", h,v, m_viewAngleH, m_viewAngleV); + OutputDebugString(s); +#endif +} + +// Updates the parameters for the point of view. + +void CModel::UpdateView() +{ + Math::Vector eye, lookat, vUpVec; + +//? lookat = RetSelectCDG(); + lookat = Math::Vector(0.0f, m_viewHeight, 0.0f); + eye = RotateView(lookat, m_viewAngleH, m_viewAngleV, m_viewDist); + + vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); + m_engine->SetViewParams(eye, lookat, vUpVec, 10.0f); + m_engine->SetRankView(0); +} + +// Moves the point of view. + +void CModel::ViewMove(const Event &event, float speed) +{ + if ( IsEditFocus() ) return; + + // Up/Down. + if ( event.axeY > 0.5f ) + { + if ( event.keyState & KS_CONTROL ) + { + m_viewHeight += event.rTime*10.0f*speed; + if ( m_viewHeight > 100.0f ) m_viewHeight = 100.0f; + } + else + { + m_viewAngleV -= event.rTime*1.0f*speed; + if ( m_viewAngleV < -Math::PI*0.49f ) m_viewAngleV = -Math::PI*0.49f; + } + } + if ( event.axeY < -0.5f ) + { + if ( event.keyState & KS_CONTROL ) + { + m_viewHeight -= event.rTime*10.0f*speed; + if ( m_viewHeight < -100.0f ) m_viewHeight = -100.0f; + } + else + { + m_viewAngleV += event.rTime*1.0f*speed; + if ( m_viewAngleV > Math::PI*0.49f ) m_viewAngleV = Math::PI*0.49f; + } + } + + // Left/Right. + if ( event.axeX < -0.5f ) + { + m_viewAngleH -= event.rTime*1.0f*speed; + } + if ( event.axeX > 0.5f ) + { + m_viewAngleH += event.rTime*1.0f*speed; + } + + // PageUp/PageDown. + if ( event.keyState & KS_PAGEUP ) + { + m_viewDist -= event.rTime*30.0f*speed; + if ( m_viewDist < 1.0f ) m_viewDist = 1.0f; + } + if ( event.keyState & KS_PAGEDOWN ) + { + m_viewDist += event.rTime*30.0f*speed; + if ( m_viewDist > 300.0f ) m_viewDist = 300.0f; + } +} + + + +// Updates the text information. + +void CModel::UpdateInfoText() +{ + char info[100]; + + if ( m_mode == 1 ) + { + sprintf(info, "[1] V:color=%d K:state=%d Sel=%d..%d (T=%d)", + m_color, m_state, + m_triangleSel1, m_triangleSel2, + m_triangleSel2-m_triangleSel1+1); + m_engine->SetInfoText(0, info); + + sprintf(info, "M:mode=%d Z:rot=%d XY:mir=%d;%d P:part=%d O:name=%s", + m_textureMode, m_textureRotate, + m_bTextureMirrorX, m_bTextureMirrorY, + m_texturePart, m_textureName); + m_engine->SetInfoText(1, info); + } + + if ( m_mode == 2 ) + { + sprintf(info, "[2] Sel=%d..%d (T=%d)", + m_triangleSel1, m_triangleSel2, + m_triangleSel2-m_triangleSel1+1); + m_engine->SetInfoText(0, info); + + sprintf(info, "O:dirty=%d UV:offset=%d;%d XY:mir=%d;%d S:subdiv=%d", + m_secondTexNum, + m_secondOffsetU, m_secondOffsetV, + m_bTextureMirrorX, m_bTextureMirrorY, + m_secondSubdiv); + m_engine->SetInfoText(1, info); + } + + if ( m_mode == 3 ) + { + sprintf(info, "[3] LOD Math::Min/max=%d..%d Sel=%d..%d (T=%d)", + (int)m_min, (int)m_max, + m_triangleSel1, m_triangleSel2, + m_triangleSel2-m_triangleSel1+1); + m_engine->SetInfoText(0, info); + + sprintf(info, "[Change]"); + m_engine->SetInfoText(1, info); + } +} + + + +static int tablePartT[] = // lemt.tga +{ + 192, 0, 256, 32, // track profile + 0, 64, 128, 128, // wheels for track + 0, 0, 128, 64, // profile + 90, 0, 128, 28, // pivot trainer + 128, 0, 192, 44, // chest front + 128, 44, 192, 58, // shell + 128, 58, 192, 87, // back chest + 128, 87, 192, 128, // back shell + 128, 128, 192, 144, // sub back shell + 0, 128, 32, 152, // rear fender + 0, 152, 32, 182, // fender middle + 0, 182, 32, 256, // front fender + 32, 128, 112, 176, // wing + 224, 48, 232, 64, // thrust tunnel + 192, 32, 224, 64, // fire under reactor + 224, 32, 256, 48, // foot + 192, 64, 256, 128, // sensor + 192, 128, 224, 176, // battery holder + 192, 216, 248, 248, // cannon board + 220, 216, 222, 245, // cannon board + 64, 176, 128, 224, // top cannon + 128, 152, 192, 160, // external cannon + 128, 144, 192, 152, // interior cannon + 192, 176, 224, 192, // small cannon + 128, 236, 192, 256, // cannon organic + 214, 192, 224, 216, // crosshair + 224, 128, 248, 152, // articulation + 128, 192, 192, 214, // piston board + 128, 214, 192, 236, // piston front + 192, 192, 214, 214, // piston edge + 128, 192, 161, 214, // small piston board + 32, 176, 64, 198, // radar piston + 128, 160, 160, 192, // wheel + 232, 48, 255, 56, // tire profile + 240, 152, 248, 216, // vertical hatching + 248, 192, 256, 256, // battery + 224, 152, 240, 168, // rock + 144, 80, 176, 112, // nuclear + 140, 76, 180, 116, // large nuclear + 144, 80, 152, 88, // yellow nuclear + 224, 168, 240, 192, // cap resolution C + 224, 192, 240, 210, // back resolution C + 32, 224, 96, 235, // arm resolution C + 32, 235, 96, 246, // arm resolution C + 161, 1, 164, 4, // blank + 168, 1, 171, 4, // medium gray + 154, 1, 157, 4, // dark gray uniform + 147, 1, 150, 4, // blue unifrom + 114, 130, 118, 134, // red unifrom + 121, 130, 125, 134, // green uniform + 114, 137, 118, 141, // yellow uniform + 121, 137, 125, 141, // violet uniform + -1 +}; + +static int tablePartR[] = // roller.tga +{ + 0, 0, 128, 52, // wheels for track + 48, 137, 128, 201, // catalytic radiator + 0, 52, 32, 84, // front radiator + 32, 52, 43, 84, // back radiator + 0, 84, 96, 137, // large catalytic + 128, 0, 192, 85, // front + 128, 173, 192, 256, // back + 192, 0, 256, 42, // over + 128, 85, 192, 109, // catalytic pillon + 128, 109, 192, 173, // top pillon + 192, 85, 240, 109, // catalytic gate pillon + 0, 137, 24, 256, // catalytic verrin + 24, 137, 48, 256, // catalytic verrin + 48, 201, 128, 233, // medium cannon + 192, 109, 256, 173, // bottom cannon + 192, 173, 240, 205, // cannon 1 + 192, 173, 240, 177, // cannon 2 + 43, 52, 75, 84, // front cannon + 48, 233, 128, 247, // piston + 96, 105, 128, 137, // front phazer + 96, 97, 128, 105, // phazer cannon + 75, 52, 107, 84, // exhaust pipe + 192, 205, 243, 256, // nuclear power plant instruction + 192, 42, 256, 85, // reflection glass + -1 +}; + +static int tablePartW[] = // subm.tga +{ + 0, 0, 128, 26, // chenilles + 0, 26, 22, 114, // portique 1 + 0, 114, 22, 202, // portique 2 + 22, 26, 82, 56, // c�t� hublot + 22, 56, 82, 86, // c�t� ligne rouge + 22, 86, 82, 116, // c�t� simple + 22, 116, 82, 146, // avant/arri�re + 22, 146, 82, 176, // avant/arri�re + phare + 132, 82, 196, 166, // capot trainer + 132, 166, 196, 177, // capot trainer + 132, 177, 196, 188, // capot trainer + 0, 224, 96, 256, // c�t� trainer + 30, 224, 48, 256, // arri�re trainer + 136, 240, 216, 256, // barri�re courte + 96, 240, 256, 256, // barri�re longue + 128, 0, 160, 32, // black-box 1 + 160, 0, 192, 32, // black-box 2 + 192, 0, 224, 32, // black-box 3 + 224, 105, 256, 137, // TNT 1 + 224, 137, 256, 169, // TNT 2 + 82, 32, 146, 82, // factory r�solution C + 146, 32, 210, 82, // factory r�solution C + 224, 0, 256, 105, // tower r�solution C + 82, 82, 132, 150, // research r�solution C + 199, 169, 256, 233, // sac r�solution C + 106, 150, 130, 214, // cl� A + 82, 150, 106, 214, // cl� B + 132, 188, 196, 212, // cl� C + 132, 212, 196, 236, // cl� D + 210, 32, 224, 46, // gris + 56, 176, 82, 224, // sol coffre-fort + -1 +}; + +static int tablePartDr[] = // drawer.tga +{ + 128, 0, 134, 6, // bleu + 128, 6, 134, 12, // gris fonc� + 128, 12, 134, 18, // gris clair + 0, 0, 128, 32, // roues chenille + 192, 0, 256, 32, // profil chenille + 140, 0, 160, 8, // profil phare + 160, 0, 192, 32, // face phare + 0, 32, 160, 48, // hachure + 160, 32, 192, 48, // c�t� + 0, 48, 96, 96, // tableau de bord + 96, 48, 192, 112, // radiateur + 192, 32, 256, 112, // grille lat�rale + 192, 112, 256, 128, // capot + 0, 96, 8, 160, // chassis + 8, 96, 96, 104, // axe chenilles + 8, 104, 16, 160, // axe carrousel + 16, 128, 24, 160, // flan support + 224, 128, 256, 160, // rotule + 24, 104, 32, 160, // bocal (18) + 32, 104, 40, 160, // bocal + 40, 104, 48, 160, // bocal + 24, 152, 48, 160, // bocal fond + 0, 240, 32, 256, // crayon 1: couleur (22) + 0, 160, 32, 192, // crayon 1: dessus + 0, 192, 32, 256, // crayon 1: pointe + 32, 240, 64, 256, // crayon 2: couleur + 32, 160, 64, 192, // crayon 2: dessus + 32, 192, 64, 256, // crayon 2: pointe + 64, 240, 96, 256, // crayon 3: couleur + 64, 160, 96, 192, // crayon 3: dessus + 64, 192, 96, 256, // crayon 3: pointe + 96, 240, 128, 256, // crayon 4: couleur + 96, 160, 128, 192, // crayon 4: dessus + 96, 192, 128, 256, // crayon 4: pointe + 128, 240, 160, 256, // crayon 5: couleur + 128, 160, 160, 192, // crayon 5: dessus + 128, 192, 160, 256, // crayon 5: pointe + 160, 240, 192, 256, // crayon 6: couleur + 160, 160, 192, 192, // crayon 6: dessus + 160, 192, 192, 256, // crayon 6: pointe + 192, 240, 224, 256, // crayon 7: couleur + 192, 160, 224, 192, // crayon 7: dessus + 192, 192, 224, 256, // crayon 7: pointe + 224, 240, 256, 256, // crayon 8: couleur + 224, 160, 256, 192, // crayon 8: dessus + 224, 192, 256, 256, // crayon 8: pointe + -1 +}; + +static int tablePartKi[] = // kid.tga +{ + 0, 0, 128, 53, // ciseaux + 128, 0, 256, 128, // CD + 0, 0, 8, 8, // livre 1: fond + 8, 0, 16, 8, // livre 2: fond + 16, 0, 24, 8, // livre: fond + 24, 0, 32, 8, // livre: fond + 32, 0, 40, 8, // livre: fond + 40, 0, 48, 8, // livre: fond + 0, 53, 22, 138, // livre 1: tranche + 22, 53, 86, 138, // livre 1: face + 0, 138, 22, 224, // livre 2: tranche + 22, 138, 86, 224, // livre 2: face + 86, 53, 94, 85, // livre: pages + 94, 53, 110, 139, // livre: tranche + 110, 53, 126, 139, // livre: tranche + 86, 139, 102, 225, // livre: tranche + 102, 139, 118, 225, // livre: tranche + 118, 139, 134, 225, // livre: tranche + 64, 0, 72, 8, // fauille: fond + 155, 155, 256, 256, // feuille: carreaux + 72, 0, 80, 8, // lampe + 80, 0, 88, 8, // lampe + 80, 8, 88, 16, // ampoule + 72, 8, 80, 16, // rayons (23) + 86, 85, 94, 139, // lampe + 0, 224, 32, 256, // lampe rotule + 64, 8, 72, 16, // arrosoir: fond + 134, 128, 142, 256, // arrosoir: corps + 142, 128, 150, 256, // arrosoir: tuyau + 128, 225, 134, 256, // arrosoir: int�rieur + 32, 224, 64, 256, // arrosoir: ponneau + 56, 8, 64, 16, // skate: roues (31) + 48, 8, 56, 16, // skate: axes + 40, 8, 48, 16, // skate: grip + 32, 8, 40, 16, // skate: tranche + 24, 8, 32, 16, // skate: dessous + 150, 128, 200, 256, // skate: motif 1 + 200, 128, 250, 256, // skate: motif 2 + 64, 224, 96, 256, // skate: roue (38) + 96, 225, 104, 256, // skate: amortisseur + -1 +}; + +static int tablePartKi2[] = // kid2.tga +{ + 2, 2, 62, 62, // coca: dessus + 0, 64, 8, 192, // coca: flan + 8, 64, 96, 192, // coca: logo + 128, 0, 256, 85, // carton + 128, 85, 256, 91, // carton tranche + 128, 128, 256, 256, // roue + 192, 96, 256, 128, // pneu + 184, 96, 192, 128, // jante + 128, 96, 160, 128, // int�rieur + 160, 96, 168, 104, // porte bois + 160, 104, 168, 112, // porte m�tal + 160, 112, 184, 128, // vitre + 96, 0, 128, 256, // bouteille: corps (12) + 64, 0, 96, 32, // bouteille: bouchon + 168, 96, 176, 104, // bouteille: vert + 0, 192, 96, 224, // bois clair + 0, 224, 96, 256, // bois fonc� + 64, 32, 96, 64, // bateau + 168, 104, 176, 112, // ballon (18) + 176, 104, 184, 112, // ballon + 176, 96, 184, 104, // int�rieur caisse + -1 +}; + +static int tablePartKi3[] = // kid3.tga +{ + 0, 0, 32, 28, // �crou: flan + 0, 28, 32, 44, // �crou: profil + 0, 44, 32, 60, // �crou: pas de vis + 0, 60, 32, 64, // tuyau + 0, 64, 32, 68, // tuyau + 0, 68, 8, 76, // tuyau + 0, 76, 32, 108, // plastic + 8, 68, 16, 76, // saut: gris clair (7) + 16, 68, 24, 76, // saut: gris fonc� + 24, 68, 32, 76, // saut: gris bois + 0, 108, 32, 140, // saut: rotule + 0, 140, 32, 144, // saut: axe + 128, 0, 256, 128, // saut: flan + 0, 144, 8, 152, // basket: gris fonc� (13) + 8, 144, 16, 152, // basket: gris clair + 16, 144, 24, 152, // basket: gris lacets + 24, 144, 32, 152, // basket: gris semelle + 0, 152, 8, 181, // basket: int�rieur + 0, 181, 192, 256, // basket: c�t� + 192, 181, 226, 256, // basket: arri�re + 32, 135, 96, 181, // basket: dessus (20) + 96, 168, 128, 181, // basket: avant + 8, 152, 16, 160, // chaise: plastique + 16, 152, 24, 160, // chaise: m�tal + 32, 0, 64, 32, // chaise: roue + 8, 177, 24, 181, // chaise: roue + 226, 181, 234, 256, // chaise: piston (26) + 64, 96, 128, 128, // chaise: relief + 96, 135, 128, 167, // chaise: dessous + 32, 128, 250, 135, // paille 1 + 38, 128, 256, 135, // paille 2 + 234, 181, 242, 256, // allumette + 8, 160, 16, 168, // allumette (dessus) + 128, 135, 224, 181, // panneau + 242, 135, 256, 256, // poteau (34) + 24, 152, 32, 160, // clou + 16, 160, 24, 168, // tuyau m�talique + 112, 181, 192, 185, // tuyau int�rieur + 32, 32, 48, 80, // pas de vis + 24, 160, 32, 168, // ventillateur: plastique (39) + 40, 80, 56, 96, // ventillateur: plastique d�grad� + 8, 168, 16, 176, // ventillateur: m�tal + 32, 80, 40, 112, // ventillateur: socle 1 + 64, 0, 96, 16, // ventillateur: socle 2 + 48, 32, 56, 80, // ventillateur: socle 3 + 64, 16, 96, 32, // ventillateur: moteur flan + 96, 0, 128, 32, // ventillateur: moteur face + 102, 6, 122, 26, // ventillateur: socle dessus + 16, 168, 24, 176, // pot: uni (48) + 56, 32, 64, 64, // pot: haut + 56, 64, 64, 96, // pot: bas + 64, 32, 128, 96, // pot: terre + -1 +}; + +static int tablePartF[] = // factory.tga +{ + 0, 0, 152, 152, // plancher octogonal fabrique + 50, 50, 102, 102, // dessus pile + 0, 152, 128, 252, // avant + 128, 152, 256, 252, // arri�re + 152, 28, 225, 128, // c�t� + 152, 28, 176, 128, // c�t� partiel + 152, 0, 216, 16, // hachures + 236, 0, 256, 40, // axe + 152, 128, 224, 152, // support cible + -1 +}; + +static int tablePartD[] = // derrick.tga +{ + 0, 0, 64, 32, // grand c�t� + 64, 0, 96, 24, // petit c�t� + 96, 0, 136, 24, // attention + 0, 32, 8, 160, // tube 1 + 8, 32, 16, 96, // tube 2 + 16, 32, 24, 160, // pilier + 24, 32, 32, 160, // tige foret + 32, 32, 40, 160, // tige destructeur + 8, 96, 16, 128, // foret + 136, 0, 256, 120, // plancher octogonal station de recharge + 40, 32, 64, 56, // cube m�tal + 64, 24, 128, 48, // c�t� tour haut + 64, 48, 128, 229, // c�t� tour bas + 136, 120, 256, 240, // int�rieur usine + 0, 160, 64, 224, // to�t usine + -1 +}; + +static int tablePartC[] = // convert.tga +{ + 0, 0, 120, 120, // plancher octogonal convertisseur + 0, 120, 128, 176, // grand c�t� + 128, 120, 192, 176, // petit c�t� + 192, 120, 256, 184, // couvercle convertisseur + 120, 0, 216, 64, // face trianble + 216, 0, 248, 64, // c�t� triangle + 120, 64, 160, 84, // axe + 0, 141, 128, 176, // recherche: base + 0, 176, 128, 214, // recherche: haut + 0, 214, 128, 252, // recherche: haut (!) + 174, 64, 190, 120, // recherche: montant + 190, 64, 206, 120, // recherche: montant + 206, 64, 254, 85, // radar + 192, 168, 256, 232, // hachures carr�es + 248, 0, 256, 64, // c�ne fabrique de piles + 128, 176, 192, 240, // dessus centrale nucl�aire + 120, 85, 174, 120, // technicien, visage + 206, 106, 256, 120, // technicien, casquette + 160, 64, 174, 78, // technicien, visi�re + -1 +}; + +static int tablePartS[] = // search.tga +{ + 0, 0, 128, 128, // usine 1 + 128, 0, 256, 128, // usine 2 + 0, 128, 128, 256, // pile + 128, 128, 228, 240, // support pile + 228, 128, 256, 184, // antenne + 128, 128, 192, 160, // contr�le 1 + 128, 160, 192, 192, // contr�le 2 + 128, 192, 192, 224, // contr�le 3 + 128, 224, 192, 256, // contr�le 4 + -1 +}; + +static int tablePartP[] = // plant.tga +{ + 0, 160, 48, 256, // feuille 1 + 0, 0, 94, 100, // feuille 2 + 48, 156, 108, 256, // feuille 3 + 94, 0, 104, 100, // tige 1 + 185, 0, 195, 100, // tige 2 + 108, 100, 182, 256, // foug�re + 104, 0, 144, 100, // courge + 203, 0, 256, 83, // armature derrick r�solution C + -1 +}; + +static int tablePartV[] = // vegetal.tga +{ + 0, 0, 94, 100, // racine + 186, 0, 256, 256, // tronc + 162, 0, 168, 128, // mat drapeau bleu + 168, 0, 174, 128, // mat drapeau rouge + 174, 0, 180, 128, // mat drapeau vert + 180, 0, 186, 128, // mat drapeau jaune + 180, 128, 186, 256, // mat drapeau violet + 94, 0, 107, 32, // drapeau bleu + 107, 0, 120, 32, // drapeau rouge + 120, 0, 133, 32, // drapeau vert + 133, 0, 146, 32, // drapeau jaune + 146, 0, 159, 32, // drapeau violet + 94, 64, 126, 96, // verre 1 + 126, 64, 158, 86, // verre 2 + 128, 128, 180, 144, // verre 3a + 128, 144, 180, 160, // verre 3b + 128, 94, 162, 128, // verre 4 + 0, 100, 32, 228, // champignon 1 + 32, 100, 48, 228, // champignon 1 + 48, 100, 112, 228, // champignon 2 + 112, 100, 128, 228, // champignon 2 + 128, 160, 180, 212, // tronc (21) + -1 +}; + +static int tablePartM[] = // mother.tga +{ + 0, 0, 128, 128, // corps arri�re + 128, 0, 192, 128, // corps avant + 0, 128, 64, 192, // t�te + 64, 128, 192, 160, // pince ext. + 64, 160, 192, 192, // pince int. + 0, 192, 64, 256, // mire + -1 +}; + +static int tablePartA[] = // ant.tga +{ + 0, 0, 64, 64, // queue + 0, 96, 128, 160, // queue abeille + 64, 0, 128, 64, // corps + 128, 0, 192, 64, // t�te + 0, 64, 64, 72, // patte + 0, 72, 64, 80, // antenne + 64, 64, 150, 96, // queue ver + 150, 64, 182, 96, // corps ver + 182, 64, 256, 96, // t�te ver + 224, 32, 256, 64, // articulation ver + 128, 96, 220, 160, // aile + 0, 80, 16, 96, // oeil + 200, 0, 208, 8, // vert clair + 200, 8, 208, 16, // vert fonc� + 0, 160, 64, 224, // corps araign�e + 64, 160, 128, 192, // t�te araign�e + 208, 0, 216, 64, // patte araign�e + 216, 0, 224, 32, // patte araign�e + 224, 0, 256, 8, // antenne araign�e + 192, 0, 200, 8, // brun clair + 192, 8, 200, 16, // brun fonc� + 128, 160, 256, 256, // SatCom + -1 +}; + +static int tablePartH[] = // human.tga +{ + 0, 0, 64, 64, // vissi�re + 64, 0, 96, 64, // cuisse + 96, 0, 128, 64, // jambe + 128, 0, 192, 32, // bras + 128, 32, 192, 64, // avant-bras + 0, 64, 128, 224, // ventre + 128, 64, 256, 224, // dos + 64, 224, 112, 256, // dessus pied + 144, 224, 168, 240, // dessous pied + 112, 224, 144, 240, // c�t� pied + 112, 224, 128, 240, // c�t� pied + 0, 224, 64, 256, // gant + 168, 224, 200, 256, // oreille + 112, 240, 144, 256, // ligne casque + 200, 224, 208, 256, // int�rieur coup + 240, 0, 244, 64, // bombone orange + 244, 0, 248, 64, // bombone orange (reflet) + 248, 0, 252, 64, // bombone bleu + 252, 0, 256, 64, // bombone bleu (reflet) + 144, 240, 156, 256, // gris habit + 156, 240, 168, 256, // gris articulation +//? 208, 224, 256, 256, // SatCom + 192, 0, 240, 64, // quartz + -1 +}; + +static int tablePartG[] = // apollo.tga +{ + 0, 0, 64, 64, // rev�tement LEM + 64, 0, 128, 64, // rev�tement LEM + 128, 8, 136, 128, // pied + 0, 64, 64, 128, // roue + 136, 24, 152, 44, // profil pneu + 136, 8, 160, 24, // garde boue + 64, 64, 128, 128, // si�ge + 64, 128, 128, 192, // si�ge + 64, 192, 128, 212, // si�ge + 128, 128, 240, 192, // moteur + 0, 192, 28, 256, // moteur + 32, 128, 60, 256, // moteur + 224, 0, 256, 128, // avant + 206, 0, 224, 128, // avant + 136, 44, 168, 62, // avant + 64, 212, 108, 256, // panneau de commande + 198, 0, 206, 128, // mat + 190, 64, 198, 128, // mat + 160, 8, 176, 24, // cam�ra + 176, 8, 192, 24, // moyeu + 136, 64, 168, 96, // module + 168, 64, 190, 96, // module + 136, 96, 168, 128, // module + 128, 192, 230, 252, // drapeau + 0, 128, 32, 192, // antenne + 128, 0, 136, 8, // jaune + 136, 0, 144, 8, // beige + 144, 0, 152, 8, // brun + 168, 0, 176, 8, // gris tr�s clair + 152, 0, 160, 8, // gris clair + 160, 0, 168, 8, // gris fonc� + -1 +}; + +static int tablePartB[] = // base1.tga +{ + 0, 0, 80, 256, // int�rieur porte + 80, 0, 88, 256, // tranche porte + 116, 0, 180, 64, // coiffe 1 + 116, 64, 180, 102, // coiffe 2 + 180, 0, 244, 37, // base + 180, 37, 196, 101, // support + 88, 0, 116, 256, // colonne + 212, 37, 256, 128, // suppl�ment + 128, 128, 256, 256, // 1/4 du sol + 196, 37, 212, 53, // gris fonc� + 196, 53, 212, 69, // gris clair + -1 +}; + +static int tablePartCe[] = // cellar01.tga +{ + 0, 128, 64, 192, // briques + 64, 128, 128, 192, // briques + 128, 128, 192, 192, // briques + 192, 128, 256, 192, // briques + -1 +}; + +static int tablePartFa[] = // face01.tga +{ + 0, 0, 256, 256, // visage + -1 +}; + +// Retourne le pointeur la table. + +int* CModel::RetTextureTable() +{ + if ( m_textureRank == 0 ) return tablePartT; + if ( m_textureRank == 1 ) return tablePartR; + if ( m_textureRank == 2 ) return tablePartW; + if ( m_textureRank == 3 ) return tablePartDr; + if ( m_textureRank == 4 ) return tablePartKi; + if ( m_textureRank == 5 ) return tablePartKi2; + if ( m_textureRank == 6 ) return tablePartKi3; + if ( m_textureRank == 7 ) return tablePartF; + if ( m_textureRank == 8 ) return tablePartD; + if ( m_textureRank == 9 ) return tablePartC; + if ( m_textureRank == 10 ) return tablePartS; + if ( m_textureRank == 11 ) return tablePartP; + if ( m_textureRank == 12 ) return tablePartV; + if ( m_textureRank == 13 ) return tablePartM; + if ( m_textureRank == 14 ) return tablePartA; + if ( m_textureRank == 15 ) return tablePartH; + if ( m_textureRank == 16 ) return tablePartG; + if ( m_textureRank == 17 ) return tablePartB; + if ( m_textureRank == 18 ) return tablePartCe; + if ( m_textureRank == 19 ) return tablePartFa; + if ( m_textureRank == 20 ) return tablePartFa; + if ( m_textureRank == 21 ) return tablePartFa; + if ( m_textureRank == 22 ) return tablePartFa; + return 0; +} + +// Updates the part of texture. + +void CModel::TexturePartUpdate() +{ + int *table; + + table = RetTextureTable(); + if ( table == 0 ) return; + + m_textureInf.x = (table[m_texturePart*4+0]+0.5f)/256.0f; + m_textureInf.y = (table[m_texturePart*4+1]+0.5f)/256.0f; + m_textureSup.x = (table[m_texturePart*4+2]-0.5f)/256.0f; + m_textureSup.y = (table[m_texturePart*4+3]-0.5f)/256.0f; + + PutTextureValues(); +} + +// Changes the texture. + +void CModel::TextureRankChange(int step) +{ + m_textureRank += step; + + if ( m_textureRank >= MAX_NAMES ) m_textureRank = 0; + if ( m_textureRank < 0 ) m_textureRank = MAX_NAMES-1; + + if ( m_textureRank == 0 ) strcpy(m_textureName, "lemt.tga"); + if ( m_textureRank == 1 ) strcpy(m_textureName, "roller.tga"); + if ( m_textureRank == 2 ) strcpy(m_textureName, "subm.tga"); + if ( m_textureRank == 3 ) strcpy(m_textureName, "drawer.tga"); + if ( m_textureRank == 4 ) strcpy(m_textureName, "kid.tga"); + if ( m_textureRank == 5 ) strcpy(m_textureName, "kid2.tga"); + if ( m_textureRank == 6 ) strcpy(m_textureName, "kid3.tga"); + if ( m_textureRank == 7 ) strcpy(m_textureName, "factory.tga"); + if ( m_textureRank == 8 ) strcpy(m_textureName, "derrick.tga"); + if ( m_textureRank == 9 ) strcpy(m_textureName, "convert.tga"); + if ( m_textureRank == 10 ) strcpy(m_textureName, "search.tga"); + if ( m_textureRank == 11 ) strcpy(m_textureName, "plant.tga"); + if ( m_textureRank == 12 ) strcpy(m_textureName, "vegetal.tga"); + if ( m_textureRank == 13 ) strcpy(m_textureName, "mother.tga"); + if ( m_textureRank == 14 ) strcpy(m_textureName, "ant.tga"); + if ( m_textureRank == 15 ) strcpy(m_textureName, "human.tga"); + if ( m_textureRank == 16 ) strcpy(m_textureName, "apollo.tga"); + if ( m_textureRank == 17 ) strcpy(m_textureName, "base1.tga"); + if ( m_textureRank == 18 ) strcpy(m_textureName, "cellar01.tga"); + if ( m_textureRank == 19 ) strcpy(m_textureName, "face01.tga"); + if ( m_textureRank == 20 ) strcpy(m_textureName, "face02.tga"); + if ( m_textureRank == 21 ) strcpy(m_textureName, "face03.tga"); + if ( m_textureRank == 22 ) strcpy(m_textureName, "face04.tga"); + + m_texturePart = 0; +} + +// Changes the part of texture. + +void CModel::TexturePartChange(int step) +{ + int *table; + + table = RetTextureTable(); + if ( table == 0 ) return; + + m_texturePart ++; + + if ( table[m_texturePart*4] == -1 ) + { + m_texturePart = 0; + } + + TexturePartUpdate(); +} + + diff --git a/src/old/model.h b/src/old/model.h index 9acfbbc..275807b 100644 --- a/src/old/model.h +++ b/src/old/model.h @@ -1,136 +1,136 @@ -// * This file is part of the COLOBOT source code -// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU General Public License for more details. -// * -// * You should have received a copy of the GNU General Public License -// * along with this program. If not, see http://www.gnu.org/licenses/. - -// model.h - -#pragma once - - -#include "common/event.h" -#include "old/modfile.h" -#include "math/point.h" - - -class CInstanceManager; -class CD3DEngine; -class CModFile; -class CInterface; - - - -class CModel -{ -public: - CModel(CInstanceManager* iMan); - ~CModel(); - - void StartUserAction(); - void StopUserAction(); - - bool EventProcess(const Event &event); - - void InitView(); - void InitViewFromSelect(); - void UpdateView(); - void ViewMove(const Event &event, float speed); - -protected: - bool EventFrame(const Event &event); - bool GetVertex(int rank, D3DVERTEX2 &vertex); - bool SetVertex(int rank, D3DVERTEX2 &vertex); - Math::Vector RetSelectCDG(); - Math::Vector RetSelectNormal(); - void SmoothSelect(); - void PlaneSelect(); - void ColorSelect(); - void StateSelect(); - void MoveSelect(Math::Vector move); - void OperSelect(Math::Vector move, char oper); - void ReadScript(char *filename); - void BBoxCompute(Math::Vector &min, Math::Vector &max); - bool IsMappingSelectPlausible(D3DMaping D3Dmode); - void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min); - void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); - void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY); - void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY); - void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY); - void MappingSelectMagic2(bool bMirrorX, bool bMirrorY); - int SearchNext(int rank, int step); - int SearchSamePlane(int first, int step); - void CurrentSearchNext(int step, bool bControl); - void CurrentInit(); - void CurrentSelect(bool bSelect); - void DeselectAll(); - void SelectAll(); - void SelectZone(int first, int last); - void SelectTerm(); - void DefaultSelect(); - void SelectDelete(); - void Compress(); - void MinMaxSelect(); - void MinMaxChange(); - void UpdateInfoText(); - int* RetTextureTable(); - void TexturePartUpdate(); - void TextureRankChange(int step); - void TexturePartChange(int step); - void PutTextureValues(); - void GetTextureValues(); - void GetModelName(char *buffer); - void GetDXFName(char *buffer); - void GetScriptName(char *buffer); - bool IsEditFocus(); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - CModFile* m_modFile; - CInterface* m_interface; - - float m_time; - ModelTriangle* m_triangleTable; - int m_triangleSel1; - int m_triangleSel2; - int m_mode; - int m_textureMode; - int m_textureRotate; - bool m_bTextureMirrorX; - bool m_bTextureMirrorY; - Math::Point m_textureInf; - Math::Point m_textureSup; - int m_texturePart; - int m_textureRank; - char m_textureName[20]; - bool m_bDisplayTransparent; - bool m_bDisplayOnlySelection; - float m_viewHeight; - float m_viewDist; - float m_viewAngleH; - float m_viewAngleV; - int m_color; - int m_state; - int m_secondTexNum; - int m_secondSubdiv; - int m_secondOffsetU; - int m_secondOffsetV; - char m_oper; - float m_min; - float m_max; -}; - +// * 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/. + +// model.h + +#pragma once + + +#include "common/event.h" +#include "old/modfile.h" +#include "math/point.h" + + +class CInstanceManager; +class CD3DEngine; +class CModFile; +class CInterface; + + + +class CModel +{ +public: + CModel(CInstanceManager* iMan); + ~CModel(); + + void StartUserAction(); + void StopUserAction(); + + bool EventProcess(const Event &event); + + void InitView(); + void InitViewFromSelect(); + void UpdateView(); + void ViewMove(const Event &event, float speed); + +protected: + bool EventFrame(const Event &event); + bool GetVertex(int rank, D3DVERTEX2 &vertex); + bool SetVertex(int rank, D3DVERTEX2 &vertex); + Math::Vector RetSelectCDG(); + Math::Vector RetSelectNormal(); + void SmoothSelect(); + void PlaneSelect(); + void ColorSelect(); + void StateSelect(); + void MoveSelect(Math::Vector move); + void OperSelect(Math::Vector move, char oper); + void ReadScript(char *filename); + void BBoxCompute(Math::Vector &min, Math::Vector &max); + bool IsMappingSelectPlausible(D3DMaping D3Dmode); + void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); + void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); + Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min); + void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); + void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName); + void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY); + void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY); + void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY); + void MappingSelectMagic2(bool bMirrorX, bool bMirrorY); + int SearchNext(int rank, int step); + int SearchSamePlane(int first, int step); + void CurrentSearchNext(int step, bool bControl); + void CurrentInit(); + void CurrentSelect(bool bSelect); + void DeselectAll(); + void SelectAll(); + void SelectZone(int first, int last); + void SelectTerm(); + void DefaultSelect(); + void SelectDelete(); + void Compress(); + void MinMaxSelect(); + void MinMaxChange(); + void UpdateInfoText(); + int* RetTextureTable(); + void TexturePartUpdate(); + void TextureRankChange(int step); + void TexturePartChange(int step); + void PutTextureValues(); + void GetTextureValues(); + void GetModelName(char *buffer); + void GetDXFName(char *buffer); + void GetScriptName(char *buffer); + bool IsEditFocus(); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + CModFile* m_modFile; + CInterface* m_interface; + + float m_time; + ModelTriangle* m_triangleTable; + int m_triangleSel1; + int m_triangleSel2; + int m_mode; + int m_textureMode; + int m_textureRotate; + bool m_bTextureMirrorX; + bool m_bTextureMirrorY; + Math::Point m_textureInf; + Math::Point m_textureSup; + int m_texturePart; + int m_textureRank; + char m_textureName[20]; + bool m_bDisplayTransparent; + bool m_bDisplayOnlySelection; + float m_viewHeight; + float m_viewDist; + float m_viewAngleH; + float m_viewAngleV; + int m_color; + int m_state; + int m_secondTexNum; + int m_secondSubdiv; + int m_secondOffsetU; + int m_secondOffsetV; + char m_oper; + float m_min; + float m_max; +}; + diff --git a/src/old/modfile.cpp b/src/old/modfile.cpp index fa0b0be..705885a 100644 --- a/src/old/modfile.cpp +++ b/src/old/modfile.cpp @@ -42,20 +42,20 @@ const int MAX_VERTICES = 2000; CModFile::CModFile(CInstanceManager* iMan) { - m_iMan = iMan; + m_iMan = iMan; - m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); - m_triangleUsed = 0; - m_triangleTable = (ModelTriangle*)malloc(sizeof(ModelTriangle)*MAX_VERTICES); - ZeroMemory(m_triangleTable, sizeof(ModelTriangle)*MAX_VERTICES); + m_triangleUsed = 0; + m_triangleTable = (ModelTriangle*)malloc(sizeof(ModelTriangle)*MAX_VERTICES); + ZeroMemory(m_triangleTable, sizeof(ModelTriangle)*MAX_VERTICES); } // Object's destructor. CModFile::~CModFile() { - free(m_triangleTable); + free(m_triangleTable); } @@ -64,190 +64,190 @@ CModFile::~CModFile() // Creates a triangle in the internal structure. bool CModFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, - float min, float max) + float min, float max) { - Math::Vector n; - int i; + Math::Vector n; + int i; - if ( m_triangleUsed >= MAX_VERTICES ) - { - OutputDebugString("ERROR: CreateTriangle::Too many triangles\n"); - return false; - } + if ( m_triangleUsed >= MAX_VERTICES ) + { + OutputDebugString("ERROR: CreateTriangle::Too many triangles\n"); + return false; + } - i = m_triangleUsed++; + i = m_triangleUsed++; - ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle)); + ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle)); - m_triangleTable[i].bUsed = true; - m_triangleTable[i].bSelect = false; + m_triangleTable[i].bUsed = true; + m_triangleTable[i].bSelect = false; - n = Math::NormalToPlane(p3, p2, p1); - m_triangleTable[i].p1 = D3DVERTEX2( p1, n); - m_triangleTable[i].p2 = D3DVERTEX2( p2, n); - m_triangleTable[i].p3 = D3DVERTEX2( p3, n); + n = Math::NormalToPlane(p3, p2, p1); + m_triangleTable[i].p1 = D3DVERTEX2( p1, n); + m_triangleTable[i].p2 = D3DVERTEX2( p2, n); + m_triangleTable[i].p3 = D3DVERTEX2( p3, n); - m_triangleTable[i].material.diffuse.r = 1.0f; - m_triangleTable[i].material.diffuse.g = 1.0f; - m_triangleTable[i].material.diffuse.b = 1.0f; // white - m_triangleTable[i].material.ambient.r = 0.5f; - m_triangleTable[i].material.ambient.g = 0.5f; - m_triangleTable[i].material.ambient.b = 0.5f; + m_triangleTable[i].material.diffuse.r = 1.0f; + m_triangleTable[i].material.diffuse.g = 1.0f; + m_triangleTable[i].material.diffuse.b = 1.0f; // white + m_triangleTable[i].material.ambient.r = 0.5f; + m_triangleTable[i].material.ambient.g = 0.5f; + m_triangleTable[i].material.ambient.b = 0.5f; - m_triangleTable[i].min = min; - m_triangleTable[i].max = max; + m_triangleTable[i].min = min; + m_triangleTable[i].max = max; - return true; + return true; } // Reads a DXF file. bool CModFile::ReadDXF(char *filename, float min, float max) { - FILE* file = NULL; - char line[100]; - int command, rankSommet, nbSommet, nbFace; - Math::Vector table[MAX_VERTICES]; - bool bWaitNbSommet; - bool bWaitNbFace; - bool bWaitSommetX; - bool bWaitSommetY; - bool bWaitSommetZ; - bool bWaitFaceX; - bool bWaitFaceY; - bool bWaitFaceZ; - float x,y,z; - int p1,p2,p3; - - file = fopen(filename, "r"); - if ( file == NULL ) return false; - - m_triangleUsed = 0; - - rankSommet = 0; - bWaitNbSommet = false; - bWaitNbFace = false; - bWaitSommetX = false; - bWaitSommetY = false; - bWaitSommetZ = false; - bWaitFaceX = false; - bWaitFaceY = false; - bWaitFaceZ = false; - - while ( fgets(line, 100, file) != NULL ) - { - sscanf(line, "%d", &command); - if ( fgets(line, 100, file) == NULL ) break; - - if ( command == 66 ) - { - bWaitNbSommet = true; - } - - if ( command == 71 && bWaitNbSommet ) - { - bWaitNbSommet = false; - sscanf(line, "%d", &nbSommet); - if ( nbSommet > MAX_VERTICES ) nbSommet = MAX_VERTICES; - rankSommet = 0; - bWaitNbFace = true; - -//? sprintf(s, "Waiting for %d sommets\n", nbSommet); -//? OutputDebugString(s); - } - - if ( command == 72 && bWaitNbFace ) - { - bWaitNbFace = false; - sscanf(line, "%d", &nbFace); - bWaitSommetX = true; - -//? sprintf(s, "Waiting for %d faces\n", nbFace); -//? OutputDebugString(s); - } - - if ( command == 10 && bWaitSommetX ) - { - bWaitSommetX = false; - sscanf(line, "%f", &x); - bWaitSommetY = true; - } - - if ( command == 20 && bWaitSommetY ) - { - bWaitSommetY = false; - sscanf(line, "%f", &y); - bWaitSommetZ = true; - } - - if ( command == 30 && bWaitSommetZ ) - { - bWaitSommetZ = false; - sscanf(line, "%f", &z); - - nbSommet --; - if ( nbSommet >= 0 ) - { - Math::Vector p(x,z,y); // permutation of Y and Z! - table[rankSommet++] = p; - bWaitSommetX = true; - -//? sprintf(s, "Sommet[%d]=%f;%f;%f\n", rankSommet, p.x,p.y,p.z); -//? OutputDebugString(s); - } - else - { - bWaitFaceX = true; - } - } - - if ( command == 71 && bWaitFaceX ) - { - bWaitFaceX = false; - sscanf(line, "%d", &p1); - if ( p1 < 0 ) p1 = -p1; - bWaitFaceY = true; - } - - if ( command == 72 && bWaitFaceY ) - { - bWaitFaceY = false; - sscanf(line, "%d", &p2); - if ( p2 < 0 ) p2 = -p2; - bWaitFaceZ = true; - } - - if ( command == 73 && bWaitFaceZ ) - { - bWaitFaceZ = false; - sscanf(line, "%d", &p3); - if ( p3 < 0 ) p3 = -p3; - - nbFace --; - if ( nbFace >= 0 ) - { - CreateTriangle( table[p3-1], table[p2-1], table[p1-1], min,max ); - bWaitFaceX = true; - -//? sprintf(s, "Face=%d;%d;%d\n", p1,p2,p3); -//? OutputDebugString(s); - } - } - - } - - fclose(file); - return true; + FILE* file = NULL; + char line[100]; + int command, rankSommet, nbSommet, nbFace; + Math::Vector table[MAX_VERTICES]; + bool bWaitNbSommet; + bool bWaitNbFace; + bool bWaitSommetX; + bool bWaitSommetY; + bool bWaitSommetZ; + bool bWaitFaceX; + bool bWaitFaceY; + bool bWaitFaceZ; + float x,y,z; + int p1,p2,p3; + + file = fopen(filename, "r"); + if ( file == NULL ) return false; + + m_triangleUsed = 0; + + rankSommet = 0; + bWaitNbSommet = false; + bWaitNbFace = false; + bWaitSommetX = false; + bWaitSommetY = false; + bWaitSommetZ = false; + bWaitFaceX = false; + bWaitFaceY = false; + bWaitFaceZ = false; + + while ( fgets(line, 100, file) != NULL ) + { + sscanf(line, "%d", &command); + if ( fgets(line, 100, file) == NULL ) break; + + if ( command == 66 ) + { + bWaitNbSommet = true; + } + + if ( command == 71 && bWaitNbSommet ) + { + bWaitNbSommet = false; + sscanf(line, "%d", &nbSommet); + if ( nbSommet > MAX_VERTICES ) nbSommet = MAX_VERTICES; + rankSommet = 0; + bWaitNbFace = true; + +//? sprintf(s, "Waiting for %d sommets\n", nbSommet); +//? OutputDebugString(s); + } + + if ( command == 72 && bWaitNbFace ) + { + bWaitNbFace = false; + sscanf(line, "%d", &nbFace); + bWaitSommetX = true; + +//? sprintf(s, "Waiting for %d faces\n", nbFace); +//? OutputDebugString(s); + } + + if ( command == 10 && bWaitSommetX ) + { + bWaitSommetX = false; + sscanf(line, "%f", &x); + bWaitSommetY = true; + } + + if ( command == 20 && bWaitSommetY ) + { + bWaitSommetY = false; + sscanf(line, "%f", &y); + bWaitSommetZ = true; + } + + if ( command == 30 && bWaitSommetZ ) + { + bWaitSommetZ = false; + sscanf(line, "%f", &z); + + nbSommet --; + if ( nbSommet >= 0 ) + { + Math::Vector p(x,z,y); // permutation of Y and Z! + table[rankSommet++] = p; + bWaitSommetX = true; + +//? sprintf(s, "Sommet[%d]=%f;%f;%f\n", rankSommet, p.x,p.y,p.z); +//? OutputDebugString(s); + } + else + { + bWaitFaceX = true; + } + } + + if ( command == 71 && bWaitFaceX ) + { + bWaitFaceX = false; + sscanf(line, "%d", &p1); + if ( p1 < 0 ) p1 = -p1; + bWaitFaceY = true; + } + + if ( command == 72 && bWaitFaceY ) + { + bWaitFaceY = false; + sscanf(line, "%d", &p2); + if ( p2 < 0 ) p2 = -p2; + bWaitFaceZ = true; + } + + if ( command == 73 && bWaitFaceZ ) + { + bWaitFaceZ = false; + sscanf(line, "%d", &p3); + if ( p3 < 0 ) p3 = -p3; + + nbFace --; + if ( nbFace >= 0 ) + { + CreateTriangle( table[p3-1], table[p2-1], table[p1-1], min,max ); + bWaitFaceX = true; + +//? sprintf(s, "Face=%d;%d;%d\n", p1,p2,p3); +//? OutputDebugString(s); + } + } + + } + + fclose(file); + return true; } struct InfoMOD { - int rev; - int vers; - int total; - int reserve[10]; + int rev; + int vers; + int total; + int reserve[10]; }; @@ -255,10 +255,10 @@ struct InfoMOD void ChangeBMPtoTGA(char *filename) { - char* p; + char* p; - p = strstr(filename, ".bmp"); - if ( p != 0 ) strcpy(p, ".tga"); + p = strstr(filename, ".bmp"); + if ( p != 0 ) strcpy(p, ".tga"); } @@ -266,224 +266,224 @@ void ChangeBMPtoTGA(char *filename) bool CModFile::AddModel(char *filename, int first, bool bEdit, bool bMeta) { - FILE* file; - InfoMOD info; - float limit[2]; - int i, nb, err; - char* p; - - if ( m_engine->RetDebugMode() ) - { - bMeta = false; - } - - if ( bMeta ) - { - p = strchr(filename, '\\'); - if ( p == 0 ) - { + FILE* file; + InfoMOD info; + float limit[2]; + int i, nb, err; + char* p; + + if ( m_engine->RetDebugMode() ) + { + bMeta = false; + } + + if ( bMeta ) + { + p = strchr(filename, '\\'); + if ( p == 0 ) + { #if _SCHOOL - err = g_metafile.Open("ceebot2.dat", filename); + err = g_metafile.Open("ceebot2.dat", filename); #else - err = g_metafile.Open("colobot2.dat", filename); + err = g_metafile.Open("colobot2.dat", filename); #endif - } - else - { + } + else + { #if _SCHOOL - err = g_metafile.Open("ceebot2.dat", p+1); + err = g_metafile.Open("ceebot2.dat", p+1); #else - err = g_metafile.Open("colobot2.dat", p+1); + err = g_metafile.Open("colobot2.dat", p+1); #endif - } - if ( err != 0 ) bMeta = false; - } - if ( !bMeta ) - { - file = fopen(filename, "rb"); - if ( file == NULL ) return false; - } - - if ( bMeta ) - { - g_metafile.Read(&info, sizeof(InfoMOD)); - } - else - { - fread(&info, sizeof(InfoMOD), 1, file); - } - nb = info.total; - m_triangleUsed += nb; - - if ( info.rev == 1 && info.vers == 0 ) - { - OldModelTriangle1 old; - - for ( i=first ; iRetLimitLOD(0); // frontier AB as config - limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config - - // Standard frontiers -> config. - for ( i=first ; iRetLimitLOD(0); // frontier AB as config + limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config + + // Standard frontiers -> config. + for ( i=first ; iRetSecondTexture(); - } - else - { - texNum = m_triangleTable[i].texNum2; - } - - if ( texNum >= 1 && texNum <= 10 ) - { - state = m_triangleTable[i].state|D3DSTATEDUALb; - } - if ( texNum >= 11 && texNum <= 20 ) - { - state = m_triangleTable[i].state|D3DSTATEDUALw; - } - sprintf(texName2, "dirty%.2d.bmp", texNum); - } - - m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, - m_triangleTable[i].material, - state+addState, - m_triangleTable[i].texName, texName2, - m_triangleTable[i].min, - m_triangleTable[i].max, false); - } - return true; + char texName2[20]; + int texNum, i, state; + + for ( i=0 ; iRetSecondTexture(); + } + else + { + texNum = m_triangleTable[i].texNum2; + } + + if ( texNum >= 1 && texNum <= 10 ) + { + state = m_triangleTable[i].state|D3DSTATEDUALb; + } + if ( texNum >= 11 && texNum <= 20 ) + { + state = m_triangleTable[i].state|D3DSTATEDUALw; + } + sprintf(texName2, "dirty%.2d.bmp", texNum); + } + + m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, + m_triangleTable[i].material, + state+addState, + m_triangleTable[i].texName, texName2, + m_triangleTable[i].min, + m_triangleTable[i].max, false); + } + return true; #else - char texName1[20]; - char texName2[20]; - int texNum, i, state; - - for ( i=0 ; iRetSecondTexture(); - } - else - { - texNum = m_triangleTable[i].texNum2; - } - - if ( texNum >= 1 && texNum <= 10 ) - { - state |= D3DSTATEDUALb; - } - if ( texNum >= 11 && texNum <= 20 ) - { - state |= D3DSTATEDUALw; - } - sprintf(texName2, "dirty%.2d.tga", texNum); - } - - m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, - m_triangleTable[i].material, - state+addState, - texName1, texName2, - m_triangleTable[i].min, - m_triangleTable[i].max, false); - } - return true; + char texName1[20]; + char texName2[20]; + int texNum, i, state; + + for ( i=0 ; iRetSecondTexture(); + } + else + { + texNum = m_triangleTable[i].texNum2; + } + + if ( texNum >= 1 && texNum <= 10 ) + { + state |= D3DSTATEDUALb; + } + if ( texNum >= 11 && texNum <= 20 ) + { + state |= D3DSTATEDUALw; + } + sprintf(texName2, "dirty%.2d.tga", texNum); + } + + m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3, + m_triangleTable[i].material, + state+addState, + texName1, texName2, + m_triangleTable[i].min, + m_triangleTable[i].max, false); + } + return true; #endif } @@ -613,23 +613,23 @@ bool CModFile::CreateEngineObject(int objRank, int addState) void CModFile::Mirror() { - D3DVERTEX2 t; - int i; - - for ( i=0 ; i using - char bSelect; // true -> selected - D3DVERTEX p1; - D3DVERTEX p2; - D3DVERTEX p3; - D3DMATERIAL7 material; - char texName[20]; - float min; - float max; -}; // length = 196 bytes + char bUsed; // true -> using + char bSelect; // true -> selected + D3DVERTEX p1; + D3DVERTEX p2; + D3DVERTEX p3; + D3DMATERIAL7 material; + char texName[20]; + float min; + float max; +}; // length = 196 bytes struct OldModelTriangle2 { - char bUsed; // true -> used - char bSelect; // true -> selected - D3DVERTEX p1; - D3DVERTEX p2; - D3DVERTEX p3; - D3DMATERIAL7 material; - char texName[20]; - float min; - float max; - long state; - short reserve1; - short reserve2; - short reserve3; - short reserve4; + char bUsed; // true -> used + char bSelect; // true -> selected + D3DVERTEX p1; + D3DVERTEX p2; + D3DVERTEX p3; + D3DMATERIAL7 material; + char texName[20]; + float min; + float max; + long state; + short reserve1; + short reserve2; + short reserve3; + short reserve4; }; struct ModelTriangle { - char bUsed; // true -> used - char bSelect; // true -> selected - D3DVERTEX2 p1; - D3DVERTEX2 p2; - D3DVERTEX2 p3; - D3DMATERIAL7 material; - char texName[20]; - float min; - float max; - long state; - short texNum2; - short reserve2; - short reserve3; - short reserve4; -}; // length = 208 bytes + char bUsed; // true -> used + char bSelect; // true -> selected + D3DVERTEX2 p1; + D3DVERTEX2 p2; + D3DVERTEX2 p3; + D3DMATERIAL7 material; + char texName[20]; + float min; + float max; + long state; + short texNum2; + short reserve2; + short reserve3; + short reserve4; +}; // length = 208 bytes @@ -83,33 +83,33 @@ struct ModelTriangle class CModFile { public: - CModFile(CInstanceManager* iMan); - ~CModFile(); + CModFile(CInstanceManager* iMan); + ~CModFile(); - bool ReadDXF(char *filename, float min, float max); - bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true); - bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true); - bool WriteModel(char *filename); + bool ReadDXF(char *filename, float min, float max); + bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true); + bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true); + bool WriteModel(char *filename); - bool CreateEngineObject(int objRank, int addState=0); - void Mirror(); + bool CreateEngineObject(int objRank, int addState=0); + void Mirror(); - void SetTriangleUsed(int total); - int RetTriangleUsed(); - int RetTriangleMax(); - ModelTriangle* RetTriangleList(); + void SetTriangleUsed(int total); + int RetTriangleUsed(); + int RetTriangleMax(); + ModelTriangle* RetTriangleList(); - float RetHeight(Math::Vector pos); + float RetHeight(Math::Vector pos); protected: - bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max); + bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max); protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; + CInstanceManager* m_iMan; + CD3DEngine* m_engine; - ModelTriangle* m_triangleTable; - int m_triangleUsed; + ModelTriangle* m_triangleTable; + int m_triangleUsed; }; diff --git a/src/old/particule.cpp b/src/old/particule.cpp index 8c8a162..b807e3d 100644 --- a/src/old/particule.cpp +++ b/src/old/particule.cpp @@ -1,4401 +1,4401 @@ -// * 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/. - -// particule.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dmath.h" -#include "old/d3dtextr.h" -#include "old/d3dengine.h" -#include "old/d3dutil.h" -#include "common/language.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "common/event.h" -#include "object/object.h" -#include "physics/physics.h" -#include "object/auto/auto.h" -#include "object/robotmain.h" -#include "old/terrain.h" -#include "old/sound.h" -#include "old/water.h" -#include "old/particule.h" - - - -const float FOG_HSUP = 10.0f; -const float FOG_HINF = 100.0f; - - - - -// Check if an object can be destroyed, but is not an enemy. - -bool IsSoft(ObjectType type) -{ - return ( type == OBJECT_HUMAN || - type == OBJECT_MOBILEfa || - type == OBJECT_MOBILEta || - type == OBJECT_MOBILEwa || - type == OBJECT_MOBILEia || - type == OBJECT_MOBILEfc || - type == OBJECT_MOBILEtc || - type == OBJECT_MOBILEwc || - type == OBJECT_MOBILEic || - type == OBJECT_MOBILEfi || - type == OBJECT_MOBILEti || - type == OBJECT_MOBILEwi || - type == OBJECT_MOBILEii || - type == OBJECT_MOBILEfs || - type == OBJECT_MOBILEts || - type == OBJECT_MOBILEws || - type == OBJECT_MOBILEis || - type == OBJECT_MOBILErt || - type == OBJECT_MOBILErc || - type == OBJECT_MOBILErr || - type == OBJECT_MOBILErs || - type == OBJECT_MOBILEsa || - type == OBJECT_MOBILEft || - type == OBJECT_MOBILEtt || - type == OBJECT_MOBILEwt || - type == OBJECT_MOBILEit || - type == OBJECT_MOBILEdr || // robot? - type == OBJECT_METAL || - type == OBJECT_POWER || - type == OBJECT_ATOMIC || // cargo? - type == OBJECT_DERRICK || - type == OBJECT_STATION || - type == OBJECT_FACTORY || - type == OBJECT_REPAIR || - type == OBJECT_DESTROYER|| - type == OBJECT_CONVERT || - type == OBJECT_TOWER || - type == OBJECT_RESEARCH || - type == OBJECT_RADAR || - type == OBJECT_INFO || - type == OBJECT_ENERGY || - type == OBJECT_LABO || - type == OBJECT_NUCLEAR || - type == OBJECT_PARA ); // building? -} - -// Check if an object is a destroyable enemy. - -bool IsAlien(ObjectType type) -{ - return ( type == OBJECT_ANT || - type == OBJECT_SPIDER || - type == OBJECT_BEE || - type == OBJECT_WORM || - type == OBJECT_MOTHER || - type == OBJECT_NEST || - type == OBJECT_BULLET || - type == OBJECT_EGG || - type == OBJECT_MOBILEtg || - type == OBJECT_TEEN28 || - type == OBJECT_TEEN31 ); -} - -// Returns the damping factor for friendly fire. - -float RetDecay(ObjectType type) -{ - if ( IsSoft(type) ) return 0.2f; - return 1.0f; -} - - - -// Application constructor. - -CParticule::CParticule(CInstanceManager *iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_PARTICULE, this); - - m_pD3DDevice = 0; - m_engine = engine; - m_main = 0; - m_terrain = 0; - m_water = 0; - m_sound = 0; - m_uniqueStamp = 0; - m_exploGunCounter = 0; - m_lastTimeGunDel = 0.0f; - m_absTime = 0.0f; - - FlushParticule(); -} - -// Application destructor. Free memory. - -CParticule::~CParticule() -{ - m_iMan->DeleteInstance(CLASS_PARTICULE, this); -} - - -void CParticule::SetD3DDevice(LPDIRECT3DDEVICE7 device) -{ - m_pD3DDevice = device; -} - - -// Removes all particles. - -void CParticule::FlushParticule() -{ - int i, j; - - for ( i=0 ; iSearchInstance(CLASS_MAIN); - } - -#if 0 - if ( sheet == SH_WORLD && - type != PARTISELY && - type != PARTISELR && - type != PARTIGUN1 && - type != PARTIGUN2 && - type != PARTIGUN3 && - type != PARTIGUN4 && - type != PARTIQUARTZ && - !m_main->RetMovieLock() ) - { - dist = Math::Distance(pos, m_engine->RetEyePt()); - if ( dist > 300.0f ) return -1; - } -#endif - - t = -1; - if ( type == PARTIEXPLOT || - type == PARTIEXPLOO || - type == PARTIMOTOR || - type == PARTIBLITZ || - type == PARTICRASH || - type == PARTIVAPOR || - type == PARTIGAS || - type == PARTIBASE || - type == PARTIFIRE || - type == PARTIFIREZ || - type == PARTIBLUE || - type == PARTIROOT || - type == PARTIRECOVER || - type == PARTIEJECT || - type == PARTISCRAPS || - type == PARTIGUN2 || - type == PARTIGUN3 || - type == PARTIGUN4 || - type == PARTIQUEUE || - type == PARTIORGANIC1 || - type == PARTIORGANIC2 || - type == PARTIFLAME || - type == PARTIBUBBLE || - type == PARTIERROR || - type == PARTIWARNING || - type == PARTIINFO || - type == PARTISPHERE1 || - type == PARTISPHERE2 || - type == PARTISPHERE4 || - type == PARTISPHERE5 || - type == PARTISPHERE6 || - type == PARTIPLOUF0 || - type == PARTITRACK1 || - type == PARTITRACK2 || - type == PARTITRACK3 || - type == PARTITRACK4 || - type == PARTITRACK5 || - type == PARTITRACK6 || - type == PARTITRACK7 || - type == PARTITRACK8 || - type == PARTITRACK9 || - type == PARTITRACK10 || - type == PARTITRACK11 || - type == PARTITRACK12 || - type == PARTILENS1 || - type == PARTILENS2 || - type == PARTILENS3 || - type == PARTILENS4 || - type == PARTIGFLAT || - type == PARTIDROP || - type == PARTIWATER || - type == PARTILIMIT1 || - type == PARTILIMIT2 || - type == PARTILIMIT3 || - type == PARTILIMIT4 || - type == PARTIEXPLOG1 || - type == PARTIEXPLOG2 ) - { - t = 1; // effect00 - } - if ( type == PARTIGLINT || - type == PARTIGLINTb || - type == PARTIGLINTr || - type == PARTITOTO || - type == PARTISELY || - type == PARTISELR || - type == PARTIQUARTZ || - type == PARTIGUNDEL || - type == PARTICONTROL || - type == PARTISHOW || - type == PARTICHOC || - type == PARTIFOG4 || - type == PARTIFOG5 || - type == PARTIFOG6 || - type == PARTIFOG7 ) - { - t = 2; // effect01 - } - if ( type == PARTIGUN1 || - type == PARTIFLIC || - type == PARTISPHERE0 || - type == PARTISPHERE3 || - type == PARTIFOG0 || - type == PARTIFOG1 || - type == PARTIFOG2 || - type == PARTIFOG3 ) - { - t = 3; // effect02 - } - if ( type == PARTISMOKE1 || - type == PARTISMOKE2 || - type == PARTISMOKE3 || - type == PARTIBLOOD || - type == PARTIBLOODM || - type == PARTIVIRUS1 || - type == PARTIVIRUS2 || - type == PARTIVIRUS3 || - type == PARTIVIRUS4 || - type == PARTIVIRUS5 || - type == PARTIVIRUS6 || - type == PARTIVIRUS7 || - type == PARTIVIRUS8 || - type == PARTIVIRUS9 || - type == PARTIVIRUS10 ) - { - t = 4; // text (D3DSTATETTw) - } - if ( t >= MAXPARTITYPE ) return -1; - if ( t == -1 ) return -1; - - for ( j=0 ; j= PARTIFOG0 && - type <= PARTIFOG9 ) - { - if ( m_fogTotal < MAXPARTIFOG ) - m_fog[m_fogTotal++] = i; - } - - return i | ((m_particule[i].uniqueStamp&0xffff)<<16); - } - } - - return -1; -} - -// Creates a new triangular particle (debris). -// Returns the channel of the particle created or -1 on error. - -int CParticule::CreateFrag(Math::Vector pos, Math::Vector speed, - D3DTriangle *triangle, - ParticuleType type, - float duration, float mass, - float windSensitivity, int sheet) -{ - Math::Vector p1, p2, p3, n; - float l1, l2, l3, dx, dy; - int i, j, t; - - t = 0; - for ( j=0 ; j= MAXPARTITYPE ) return -1; - if ( t == -1 ) return -1; - - for ( j=0 ; jRetWheelTraceQuantity()*MAXWHEELTRACE); - max = MAXWHEELTRACE; - i = m_wheelTraceIndex++; - if ( m_wheelTraceIndex > max ) m_wheelTraceIndex = 0; - - m_wheelTrace[i].type = type; - m_wheelTrace[i].pos[0] = p1; // ul - m_wheelTrace[i].pos[1] = p2; // dl - m_wheelTrace[i].pos[2] = p3; // ur - m_wheelTrace[i].pos[3] = p4; // dr - m_wheelTrace[i].startTime = m_absTime; - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - - m_terrain->MoveOnFloor(m_wheelTrace[i].pos[0]); - m_wheelTrace[i].pos[0].y += 0.2f; // just above the ground - - m_terrain->MoveOnFloor(m_wheelTrace[i].pos[1]); - m_wheelTrace[i].pos[1].y += 0.2f; // just above the ground - - m_terrain->MoveOnFloor(m_wheelTrace[i].pos[2]); - m_wheelTrace[i].pos[2].y += 0.2f; // just above the ground - - m_terrain->MoveOnFloor(m_wheelTrace[i].pos[3]); - m_wheelTrace[i].pos[3].y += 0.2f; // just above the ground - - if ( m_wheelTraceTotal < max ) - { - m_wheelTraceTotal ++; - } - else - { - m_wheelTraceTotal = max; - } -} - - -// Check a channel number. -// Adapts the channel so it can be used as an offset in m_particule. - -bool CParticule::CheckChannel(int &channel) -{ - int uniqueStamp; - - uniqueStamp = (channel>>16)&0xffff; - channel &= 0xffff; - - if ( channel < 0 ) return false; - if ( channel >= MAXPARTICULE*MAXPARTITYPE ) return false; -#if 0 - if ( !m_particule[channel].bUsed ) return false; - - if ( m_particule[channel].uniqueStamp != uniqueStamp ) return false; -#else - if ( !m_particule[channel].bUsed ) - { - OutputDebugString("CheckChannel bUsed=false !\n"); - return false; - } - - if ( m_particule[channel].uniqueStamp != uniqueStamp ) - { - OutputDebugString("CheckChannel uniqueStamp !\n"); - return false; - } -#endif - - return true; -} - -// Removes a particle after his rank. - -void CParticule::DeleteRank(int rank) -{ - int i; - - if ( m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] > 0 ) - { - m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] --; - } - - i = m_particule[rank].trackRank; - if ( i != -1 ) // drag associated? - { - m_track[i].bUsed = false; // frees the drag - } - - m_particule[rank].bUsed = false; -} - -// Removes all particles of a given type. - -void CParticule::DeleteParticule(ParticuleType type) -{ - int i; - - for ( i=0 ; i 0 ) - { - m_totalInterface[channel/MAXPARTICULE][m_particule[channel].sheet] --; - } - - i = m_particule[channel].trackRank; - if ( i != -1 ) // drag associated? - { - m_track[i].bUsed = false; // frees the drag - } - - m_particule[channel].bUsed = false; -} - - -// Specifies the object to which the particle is bound. - -void CParticule::SetObjectLink(int channel, CObject *object) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].objLink = object; -} - -// Specifies the parent object that created the particle. - -void CParticule::SetObjectFather(int channel, CObject *object) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].objFather = object; -} - -void CParticule::SetPosition(int channel, Math::Vector pos) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].pos = pos; -} - -void CParticule::SetDimension(int channel, Math::Point dim) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].dim = dim; -} - -void CParticule::SetZoom(int channel, float zoom) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].zoom = zoom; -} - -void CParticule::SetAngle(int channel, float angle) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].angle = angle; -} - -void CParticule::SetIntensity(int channel, float intensity) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].intensity = intensity; -} - -void CParticule::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, - float angle, float intensity) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].pos = pos; - m_particule[channel].dim = dim; - m_particule[channel].zoom = zoom; - m_particule[channel].angle = angle; - m_particule[channel].intensity = intensity; -} - -void CParticule::SetPhase(int channel, ParticulePhase phase, float duration) -{ - if ( !CheckChannel(channel) ) return; - m_particule[channel].phase = phase; - m_particule[channel].duration = duration; - m_particule[channel].phaseTime = m_particule[channel].time; -} - -// Returns the position of the particle. - -bool CParticule::GetPosition(int channel, Math::Vector &pos) -{ - if ( !CheckChannel(channel) ) return false; - pos = m_particule[channel].pos; - return true; -} - - -// Indicates whether a sheet evolves or not. - -void CParticule::SetFrameUpdate(int sheet, bool bUpdate) -{ - m_bFrameUpdate[sheet] = bUpdate; -} - -// Makes evolve all the particles. - -void CParticule::FrameParticule(float rTime) -{ - CObject* object; - Math::Vector eye, pos, speed, wind; - Math::Point ts, ti, dim; - bool bPause; - float progress, dp, h, duration, mass, amplitude; - int i, j, r, total; - - if ( m_main == 0 ) - { - m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN); - } - - bPause = ( m_engine->RetPause() && !m_main->RetInfoLock() ); - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - if ( m_water == 0 ) - { - m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); - } - - if ( !bPause ) - { - m_lastTimeGunDel += rTime; - m_absTime += rTime; - } - - wind = m_terrain->RetWind(); - eye = m_engine->RetEyePt(); - - for ( i=0 ; iRetFloorLevel(m_particule[i].pos, true); - } - h += m_particule[i].dim.y*0.75f; - if ( m_particule[i].pos.y < h ) // impact with the ground? - { - if ( m_particule[i].type == PARTIPART && - m_particule[i].weight > 3.0f && // heavy enough? - m_particule[i].bounce < 3 ) - { - amplitude = m_particule[i].weight*0.1f; - amplitude *= 1.0f-0.3f*m_particule[i].bounce; - if ( amplitude > 1.0f ) amplitude = 1.0f; - if ( amplitude > 0.0f ) - { - Play(SOUND_BOUM, m_particule[i].pos, amplitude); - } - } - - if ( m_particule[i].bounce < 3 ) - { - m_particule[i].pos.y = h; - m_particule[i].speed.y *= -0.4f; - m_particule[i].speed.x *= 0.4f; - m_particule[i].speed.z *= 0.4f; - m_particule[i].bounce ++; // more impact - } - else // disappears after 3 bounces? - { - if ( m_particule[i].pos.y < h-10.0f || - m_particule[i].time >= 20.0f ) - { - DeleteRank(i); - continue; - } - } - } - } - - // Manages drag associated. - r = m_particule[i].trackRank; - if ( r != -1 ) // drag exists? - { - if ( TrackMove(r, m_particule[i].pos, progress) ) - { - DeleteRank(i); - continue; - } - - m_track[r].bDrawParticule = (progress < 1.0f); - } - - if ( m_particule[i].type == PARTITRACK1 ) // explosion technique? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.375f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK2 ) // spray blue? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.500f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK3 ) // spider? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.500f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK4 ) // insect explosion? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.625f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK5 ) // derrick? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.750f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK6 ) // reset in/out? - { - ts.x = 0.0f; - ts.y = 0.0f; - ti.x = 0.0f; - ti.y = 0.0f; - } - - if ( m_particule[i].type == PARTITRACK7 || // win-1 ? - m_particule[i].type == PARTITRACK8 || // win-2 ? - m_particule[i].type == PARTITRACK9 || // win-3 ? - m_particule[i].type == PARTITRACK10 ) // win-4 ? - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.25f*(m_particule[i].type-PARTITRACK7); - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTITRACK11 ) // phazer shot? - { - object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); - m_particule[i].goal = m_particule[i].pos; - if ( object != 0 ) - { - if ( object->RetType() == OBJECT_MOTHER ) - { - object->ExploObject(EXPLO_BOUM, 0.1f); - } - else - { - object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType())); - } - } - - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.375f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTITRACK12 ) // drag reactor? - { - m_particule[i].zoom = 1.0f; - - ts.x = 0.375f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIMOTOR ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.000f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIBLITZ ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - m_particule[i].angle = Math::Rand()*Math::PI*2.0f; - - ts.x = 0.125f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTICRASH ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - -//? m_particule[i].intensity = 1.0f-progress; - if ( progress < 0.25f ) - { - m_particule[i].zoom = progress/0.25f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; - } - -//? ts.x = 0.250f; - ts.x = 0.000f; -//? ts.x = 0.375f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIVAPOR ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - m_particule[i].zoom = 1.0f+progress*3.0f; - - ts.x = 0.000f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIGAS ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - - ts.x = 0.375f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIBASE ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f+progress*7.0f; - m_particule[i].intensity = powf(1.0f-progress, 3.0f); - - ts.x = 0.375f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIFIRE || - m_particule[i].type == PARTIFIREZ ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].type == PARTIFIRE ) - { - m_particule[i].zoom = 1.0f-progress; - } - else - { - m_particule[i].zoom = progress; - } - - ts.x = 0.500f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIGUN1 ) // fireball shot? - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].testTime >= 0.1f ) - { - m_particule[i].testTime = 0.0f; - - if ( m_terrain->RetFloorHeight(m_particule[i].pos, true) < -2.0f ) - { - m_exploGunCounter ++; - - if ( m_exploGunCounter%2 == 0 ) - { - pos = m_particule[i].goal; - m_terrain->MoveOnFloor(pos, true); - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 0.0f; - dim.x = Math::Rand()*6.0f+6.0f; - dim.y = dim.x; - duration = Math::Rand()*1.0f+1.0f; - mass = 0.0f; - CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); - - pos.y += 1.0f; - total = (int)(2.0f*m_engine->RetParticuleDensity()); - for ( j=0 ; jExploObject(EXPLO_BURN, 0.0f, RetDecay(object->RetType())); - - m_exploGunCounter ++; - - if ( m_exploGunCounter%2 == 0 ) - { - pos = m_particule[i].pos; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 0.0f; - dim.x = Math::Rand()*6.0f+6.0f; - dim.y = dim.x; - duration = Math::Rand()*1.0f+1.0f; - mass = 0.0f; - CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); - - pos.y += 1.0f; - total = (int)(2.0f*m_engine->RetParticuleDensity()); - for ( j=0 ; j= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].testTime >= 0.2f ) - { - m_particule[i].testTime = 0.0f; - object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); - m_particule[i].goal = m_particule[i].pos; - if ( object != 0 ) - { - if ( object->RetShieldRadius() > 0.0f ) // protected by shield? - { - CreateParticule(m_particule[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); - if ( m_lastTimeGunDel > 0.2f ) - { - m_lastTimeGunDel = 0.0f; - Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f); - } - DeleteRank(i); - continue; - } - else - { - if ( object->RetType() != OBJECT_HUMAN ) - { - Play(SOUND_TOUCH, m_particule[i].pos, 1.0f); - } - object->ExploObject(EXPLO_BOUM, 0.0f); // starts explosion - } - } - } - - m_particule[i].angle = Math::Rand()*Math::PI*2.0f; - m_particule[i].zoom = 1.0f-progress; - - ts.x = 0.125f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIGUN3 ) // spider suicides? - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].testTime >= 0.2f ) - { - m_particule[i].testTime = 0.0f; - object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); - m_particule[i].goal = m_particule[i].pos; - if ( object != 0 ) - { - if ( object->RetShieldRadius() > 0.0f ) - { - CreateParticule(m_particule[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); - if ( m_lastTimeGunDel > 0.2f ) - { - m_lastTimeGunDel = 0.0f; - Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f); - } - DeleteRank(i); - continue; - } - else - { - object->ExploObject(EXPLO_BURN, 1.0f); // starts explosion - } - } - } - -//? ts.x = 0.875f; -//? ts.y = 0.750f; - ts.x = 0.500f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIGUN4 ) // orgaball shot? - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].testTime >= 0.1f ) - { - m_particule[i].testTime = 0.0f; - - if ( m_terrain->RetFloorHeight(m_particule[i].pos, true) < -2.0f ) - { - m_exploGunCounter ++; - - if ( m_exploGunCounter%2 == 0 ) - { - pos = m_particule[i].goal; - m_terrain->MoveOnFloor(pos, true); - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 0.0f; - dim.x = Math::Rand()*4.0f+2.0f; - dim.y = dim.x; - duration = Math::Rand()*0.7f+0.7f; - mass = 0.0f; - CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); - } - - if ( m_exploGunCounter%4 == 0 ) - { - Play(SOUND_EXPLOg2, pos, 0.5f); - } - - DeleteRank(i); - continue; - } - - object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); - m_particule[i].goal = m_particule[i].pos; - if ( object != 0 ) - { - object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType())); - - m_exploGunCounter ++; - - if ( m_exploGunCounter%2 == 0 ) - { - pos = m_particule[i].pos; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 0.0f; - dim.x = Math::Rand()*4.0f+2.0f; - dim.y = dim.x; - duration = Math::Rand()*0.7f+0.7f; - mass = 0.0f; - CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); - } - - if ( m_exploGunCounter%4 == 0 ) - { - Play(SOUND_EXPLOg2, pos, 0.5f); - } - - DeleteRank(i); - continue; - } - } - - m_particule[i].angle = Math::Rand()*Math::PI*2.0f; - m_particule[i].zoom = 1.0f-progress; - - ts.x = 0.125f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIFLIC ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 0.1f+progress; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.00f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTISHOW ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.5f ) m_particule[i].intensity = progress/0.5f; - else m_particule[i].intensity = 2.0f-progress/0.5f; - m_particule[i].zoom = 1.0f-progress*0.8f; - m_particule[i].angle -= rTime*Math::PI*0.5f; - - ts.x = 0.50f; - ts.y = 0.00f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTICHOC ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 0.1f+progress; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.50f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIGFLAT ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 0.1f+progress; - m_particule[i].intensity = 1.0f-progress; - m_particule[i].angle -= rTime*Math::PI*2.0f; - - ts.x = 0.00f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTILIMIT1 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f; - m_particule[i].intensity = 1.0f; - - ts.x = 0.000f; - ts.y = 0.125f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - if ( m_particule[i].type == PARTILIMIT2 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f; - m_particule[i].intensity = 1.0f; - - ts.x = 0.375f; - ts.y = 0.125f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - if ( m_particule[i].type == PARTILIMIT3 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f; - m_particule[i].intensity = 1.0f; - - ts.x = 0.500f; - ts.y = 0.125f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIFOG0 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.3f+sinf(progress)*0.15f; - m_particule[i].angle += rTime*0.05f; - - ts.x = 0.25f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - if ( m_particule[i].type == PARTIFOG1 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.3f+sinf(progress)*0.15f; - m_particule[i].angle -= rTime*0.07f; - - ts.x = 0.25f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIFOG2 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.6f+sinf(progress)*0.15f; - m_particule[i].angle += rTime*0.05f; - - ts.x = 0.75f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - if ( m_particule[i].type == PARTIFOG3 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.6f+sinf(progress)*0.15f; - m_particule[i].angle -= rTime*0.07f; - - ts.x = 0.75f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIFOG4 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; - m_particule[i].angle += rTime*0.05f; - - ts.x = 0.00f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - if ( m_particule[i].type == PARTIFOG5 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; - m_particule[i].angle -= rTime*0.07f; - - ts.x = 0.00f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIFOG6 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; - m_particule[i].angle += rTime*0.05f; - - ts.x = 0.50f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - if ( m_particule[i].type == PARTIFOG7 ) - { - m_particule[i].zoom = progress; - m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; - m_particule[i].angle -= rTime*0.07f; - - ts.x = 0.50f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - // Decreases the intensity if the camera - // is almost at the same height (fog was eye level). - if ( m_particule[i].type >= PARTIFOG0 && - m_particule[i].type <= PARTIFOG9 ) - { - h = 10.0f; - - if ( m_particule[i].pos.y >= eye.y && - m_particule[i].pos.y < eye.y+h ) - { - m_particule[i].intensity *= (m_particule[i].pos.y-eye.y)/h; - } - if ( m_particule[i].pos.y > eye.y-h && - m_particule[i].pos.y < eye.y ) - { - m_particule[i].intensity *= (eye.y-m_particule[i].pos.y)/h; - } - } - - if ( m_particule[i].type == PARTIEXPLOT || - m_particule[i].type == PARTIEXPLOO ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress/2.0f; - m_particule[i].intensity = 1.0f-progress; - - if ( m_particule[i].type == PARTIEXPLOT ) ts.x = 0.750f; - else ts.x = 0.875f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIEXPLOG1 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.375f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - if ( m_particule[i].type == PARTIEXPLOG2 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.625f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIFLAME ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress/2.0f; - if ( progress < 0.5f ) - { - m_particule[i].intensity = progress/0.5f; - } - else - { - m_particule[i].intensity = 2.0f-progress/0.5f; - } - - ts.x = 0.750f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIBUBBLE ) - { - if ( progress >= 1.0f || - m_particule[i].pos.y >= m_water->RetLevel() ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress/2.0f; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.250f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISMOKE1 || - m_particule[i].type == PARTISMOKE2 || - m_particule[i].type == PARTISMOKE3 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.25f ) - { - m_particule[i].zoom = progress/0.25f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; - } - - ts.x = 0.500f+0.125f*(m_particule[i].type-PARTISMOKE1); - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIBLOOD ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.750f+(rand()%2)*0.125f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIBLOODM ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.875f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIVIRUS1 || - m_particule[i].type == PARTIVIRUS2 || - m_particule[i].type == PARTIVIRUS3 || - m_particule[i].type == PARTIVIRUS4 || - m_particule[i].type == PARTIVIRUS5 || - m_particule[i].type == PARTIVIRUS6 || - m_particule[i].type == PARTIVIRUS7 || - m_particule[i].type == PARTIVIRUS8 || - m_particule[i].type == PARTIVIRUS9 || - m_particule[i].type == PARTIVIRUS10 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.25f ) - { - m_particule[i].zoom = progress/0.25f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; - } - m_particule[i].angle += rTime*Math::PI*1.0f; - - if ( m_particule[i].type == PARTIVIRUS1 ) // A ? - { - ts.x = 0.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 10.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS2 ) // C ? - { - ts.x = 19.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 28.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS3 ) // E ? - { - ts.x = 36.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 45.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS4 ) // N ? - { - ts.x = 110.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 120.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS5 ) // R ? - { - ts.x = 148.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 158.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS6 ) // T ? - { - ts.x = 166.0f/256.0f; ts.y = 19.0f/256.0f; - ti.x = 175.0f/256.0f; ti.y = 30.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS7 ) // 0 ? - { - ts.x = 90.0f/256.0f; ts.y = 2.0f/256.0f; - ti.x = 98.0f/256.0f; ti.y = 13.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS8 ) // 2 ? - { - ts.x = 103.0f/256.0f; ts.y = 2.0f/256.0f; - ti.x = 111.0f/256.0f; ti.y = 13.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS9 ) // 5 ? - { - ts.x = 125.0f/256.0f; ts.y = 2.0f/256.0f; - ti.x = 132.0f/256.0f; ti.y = 13.0f/256.0f; - } - if ( m_particule[i].type == PARTIVIRUS10 ) // 9 ? - { - ts.x = 153.0f/256.0f; ts.y = 2.0f/256.0f; - ti.x = 161.0f/256.0f; ti.y = 13.0f/256.0f; - } - } - - if ( m_particule[i].type == PARTIBLUE ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - - ts.x = 0.625f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIROOT ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.25f ) - { - m_particule[i].zoom = progress/0.25f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; - } - - ts.x = 0.000f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIRECOVER ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.25f ) - { - m_particule[i].zoom = progress/0.25f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; - } - - ts.x = 0.875f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIEJECT ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f+powf(progress, 2.0f)*5.0f; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.625f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISCRAPS ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - - ts.x = 0.625f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIFRAG ) - { - m_particule[i].angle += rTime*Math::PI*0.5f; - - ts.x = 0.0f; - ts.y = 0.0f; - ti.x = 0.0f; - ti.y = 0.0f; - } - - if ( m_particule[i].type == PARTIPART ) - { - ts.x = 0.0f; - ts.y = 0.0f; - ti.x = 0.0f; - ti.y = 0.0f; - } - - if ( m_particule[i].type == PARTIQUEUE ) - { - if ( m_particule[i].testTime >= 0.05f ) - { - m_particule[i].testTime = 0.0f; - - Math::Vector pos, speed; - Math::Point dim; - - pos = m_particule[i].pos; -//? speed = -m_particule[i].speed*0.5f; - speed = Math::Vector(0.0f, 0.0f, 0.0f); - dim.x = 1.0f*(Math::Rand()*0.8f+0.6f); - dim.y = dim.x; - CreateParticule(pos, speed, dim, PARTIGAS, 0.5f); - } - - ts.x = 0.375f; - ts.y = 0.750f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIORGANIC1 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - - pos = m_particule[i].pos; - dim.x = m_particule[i].dim.x/4.0f; - dim.y = dim.x; - duration = m_particule[i].duration; - mass = m_particule[i].mass; - total = (int)(10.0f*m_engine->RetParticuleDensity()); - for ( i=0 ; iRetParticuleDensity()); - for ( i=0 ; i= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); - - ts.x = 0.125f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIGLINT ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress > 0.5f ) - { -//? m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f); - m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; - } - m_particule[i].angle = m_particule[i].time*Math::PI; - - ts.x = 0.75f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIGLINTb ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress > 0.5f ) - { - m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; - } - m_particule[i].angle = m_particule[i].time*Math::PI; - - ts.x = 0.75f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIGLINTr ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress > 0.5f ) - { - m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; - } - m_particule[i].angle = m_particule[i].time*Math::PI; - - ts.x = 0.75f; - ts.y = 0.00f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type >= PARTILENS1 && - m_particule[i].type <= PARTILENS4 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.5f ) - { - m_particule[i].zoom = progress*2.0f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.5f)*2.0f; - } -//? m_particule[i].angle = m_particule[i].time*Math::PI; - - ts.x = 0.25f*(m_particule[i].type-PARTILENS1); - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTICONTROL ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.3f ) - { - m_particule[i].zoom = progress/0.3f; - } - else - { - m_particule[i].zoom = 1.0f; - m_particule[i].intensity = 1.0f-(progress-0.3f)/0.7f; - } - - ts.x = 0.00f; - ts.y = 0.00f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIGUNDEL ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress > 0.5f ) - { - m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f); - } - m_particule[i].angle = m_particule[i].time*Math::PI; - - ts.x = 0.75f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIQUARTZ ) - { - if ( progress >= 1.0f ) - { - m_particule[i].time = 0.0f; - m_particule[i].duration = 0.5f+Math::Rand()*2.0f; - m_particule[i].pos.x = m_particule[i].speed.x + (Math::Rand()-0.5f)*m_particule[i].mass; - m_particule[i].pos.y = m_particule[i].speed.y + (Math::Rand()-0.5f)*m_particule[i].mass; - m_particule[i].pos.z = m_particule[i].speed.z + (Math::Rand()-0.5f)*m_particule[i].mass; - m_particule[i].dim.x = 0.5f+Math::Rand()*1.5f; - m_particule[i].dim.y = m_particule[i].dim.x; - progress = 0.0f; - } - - if ( progress < 0.2f ) - { - m_particule[i].zoom = progress/0.2f; - m_particule[i].intensity = 1.0f; - } - else - { - m_particule[i].zoom = 1.0f; - m_particule[i].intensity = 1.0f-(progress-0.2f)/0.8f; - } - - ts.x = 0.25f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTITOTO ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - if ( progress < 0.15f ) - { - m_particule[i].intensity = progress/0.15f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.15f)/0.85f; - } - m_particule[i].intensity *= 0.5f; - - ts.x = 0.25f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIERROR ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress*1.0f; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.500f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIWARNING ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress*1.0f; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.875f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIINFO ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress*1.0f; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.750f; - ts.y = 0.875f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISELY ) - { - ts.x = 0.75f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - if ( m_particule[i].type == PARTISELR ) - { - ts.x = 0.75f; - ts.y = 0.00f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTISPHERE0 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress*m_particule[i].dim.x; -//? m_particule[i].intensity = 1.0f-progress; - if ( progress < 0.65f ) - { - m_particule[i].intensity = progress/0.65f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f; - } - m_particule[i].intensity *= 0.5f; - - ts.x = 0.50f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTISPHERE1 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.30f ) - { - m_particule[i].intensity = progress/0.30f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.30f)/0.70f; - } - m_particule[i].zoom = progress*m_particule[i].dim.x; - m_particule[i].angle = m_particule[i].time*Math::PI*2.0f; - - ts.x = 0.000f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISPHERE2 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( progress < 0.20f ) - { - m_particule[i].intensity = 1.0f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.20f)/0.80f; - } - m_particule[i].zoom = progress*m_particule[i].dim.x; - m_particule[i].angle = m_particule[i].time*Math::PI*2.0f; - - ts.x = 0.125f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISPHERE3 ) - { - if ( m_particule[i].phase == PARPHEND && - progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].phase == PARPHSTART ) - { - m_particule[i].intensity = progress; - if ( m_particule[i].intensity > 1.0f ) - { - m_particule[i].intensity = 1.0f; - } - } - - if ( m_particule[i].phase == PARPHEND ) - { - m_particule[i].intensity = 1.0f-progress; - } - - m_particule[i].zoom = m_particule[i].dim.x; - m_particule[i].angle = m_particule[i].time*Math::PI*0.2f; - - ts.x = 0.25f; - ts.y = 0.75f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTISPHERE4 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress*m_particule[i].dim.x; - if ( progress < 0.65f ) - { - m_particule[i].intensity = progress/0.65f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f; - } - m_particule[i].intensity *= 0.5f; - - ts.x = 0.125f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTISPHERE5 ) - { - m_particule[i].intensity = 0.7f+sinf(progress)*0.3f; - m_particule[i].zoom = m_particule[i].dim.x*(1.0f+sinf(progress*0.7f)*0.01f); - m_particule[i].angle = m_particule[i].time*Math::PI*0.2f; - - ts.x = 0.25f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTISPHERE6 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = (1.0f-progress)*m_particule[i].dim.x; - m_particule[i].intensity = progress*0.5f; - - ts.x = 0.125f; - ts.y = 0.000f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIPLOUF0 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = progress; -#if 0 - if ( progress <= 0.5f ) - { - m_particule[i].intensity = 1.0f; - } - else - { - m_particule[i].intensity = 1.0f-(progress-0.5f)/0.5f; - } -#else -//? m_particule[i].intensity = 1.0f; - m_particule[i].intensity = 1.0f-progress; -#endif - - ts.x = 0.50f; - ts.y = 0.50f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIDROP ) - { - if ( progress >= 1.0f || - m_particule[i].pos.y < m_water->RetLevel() ) - { - DeleteRank(i); - continue; - } - - m_particule[i].zoom = 1.0f-progress; - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.750f; - ts.y = 0.500f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIWATER ) - { - if ( progress >= 1.0f || - m_particule[i].pos.y < m_water->RetLevel() ) - { - DeleteRank(i); - continue; - } - - m_particule[i].intensity = 1.0f-progress; - - ts.x = 0.125f; - ts.y = 0.125f; - ti.x = ts.x+0.125f; - ti.y = ts.y+0.125f; - } - - if ( m_particule[i].type == PARTIRAY1 ) // rayon tour ? - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - if ( m_particule[i].testTime >= 0.2f ) - { - m_particule[i].testTime = 0.0f; - object = SearchObjectRay(m_particule[i].pos, m_particule[i].goal, - m_particule[i].type, m_particule[i].objFather); - if ( object != 0 ) - { - object->ExploObject(EXPLO_BOUM, 0.0f); - } - } - - ts.x = 0.00f; - ts.y = 0.00f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - if ( m_particule[i].type == PARTIRAY2 || - m_particule[i].type == PARTIRAY3 ) - { - if ( progress >= 1.0f ) - { - DeleteRank(i); - continue; - } - - ts.x = 0.00f; - ts.y = 0.25f; - ti.x = ts.x+0.25f; - ti.y = ts.y+0.25f; - } - - dp = (1.0f/256.0f)/2.0f; - m_particule[i].texSup.x = ts.x+dp; - m_particule[i].texSup.y = ts.y+dp; - m_particule[i].texInf.x = ti.x-dp; - m_particule[i].texInf.y = ti.y-dp; - m_particule[i].time += rTime; - m_particule[i].testTime += rTime; - } -} - - -// Moves a drag. -// Returns true if the drag is finished. - -bool CParticule::TrackMove(int i, Math::Vector pos, float progress) -{ - Math::Vector last; - int h, hh; - - if ( i < 0 || i >= MAXTRACK ) return true; - if ( m_track[i].bUsed == false ) return true; - - if ( progress < 1.0f ) // particle exists? - { - h = m_track[i].head; - - if ( m_track[i].used == 1 || - m_track[i].last+m_track[i].step <= progress ) - { - m_track[i].last = progress; - last = m_track[i].pos[h]; - h ++; - if ( h == MAXTRACKLEN ) h = 0; - if ( m_track[i].used < MAXTRACKLEN ) m_track[i].used ++; - } - else - { - hh = h-1; - if ( hh < 0 ) hh = MAXTRACKLEN-1; - last = m_track[i].pos[hh]; - } - m_track[i].pos[h] = pos; - m_track[i].len[h] = Math::Distance(pos, last); - - m_track[i].head = h; - -//? m_track[i].intensity = 1.0f; - m_track[i].intensity = 1.0f-progress; - } - else // mort lente de la tra�n�e ? - { -//? m_track[i].intensity = 1.0f-(progress-1.0f)/(m_track[i].step*MAXTRACKLEN); - m_track[i].intensity = 0.0f; - } - - return (m_track[i].intensity <= 0.0f); -} - -// Draws a drag. - -void CParticule::TrackDraw(int i, ParticuleType type) -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector corner[4], p1, p2, p, n, eye; - Math::Matrix matrix; - Math::Point texInf, texSup, rot; - float lTotal, f1, f2, a; - int counter, h; - - // Calculates the total length memorized. - lTotal = 0.0f; - h = m_track[i].head; - for ( counter=0 ; counterSetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - if ( type == PARTITRACK1 ) // explosion technique? - { - texInf.x = 64.5f/256.0f; - texInf.y = 21.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 22.0f/256.0f; // orange - } - if ( type == PARTITRACK2 ) // blue spray? - { - texInf.x = 64.5f/256.0f; - texInf.y = 13.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 14.0f/256.0f; // blue - } - if ( type == PARTITRACK3 ) // spider? - { - texInf.x = 64.5f/256.0f; - texInf.y = 5.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 6.0f/256.0f; // brown - } - if ( type == PARTITRACK4 ) // insect explosion? - { - texInf.x = 64.5f/256.0f; - texInf.y = 9.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 10.0f/256.0f; // dark green - } - if ( type == PARTITRACK5 ) // derrick? - { - texInf.x = 64.5f/256.0f; - texInf.y = 29.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 30.0f/256.0f; // dark brown - } - if ( type == PARTITRACK6 ) // reset in/out? - { - texInf.x = 64.5f/256.0f; - texInf.y = 17.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 18.0f/256.0f; // cyan - } - if ( type == PARTITRACK7 ) // win-1? - { - texInf.x = 64.5f/256.0f; - texInf.y = 41.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 42.0f/256.0f; // orange - } - if ( type == PARTITRACK8 ) // win-2? - { - texInf.x = 64.5f/256.0f; - texInf.y = 45.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 46.0f/256.0f; // yellow - } - if ( type == PARTITRACK9 ) // win-3? - { - texInf.x = 64.5f/256.0f; - texInf.y = 49.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 50.0f/256.0f; // red - } - if ( type == PARTITRACK10 ) // win-4? - { - texInf.x = 64.5f/256.0f; - texInf.y = 53.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 54.0f/256.0f; // violet - } - if ( type == PARTITRACK11 ) // phazer shot? - { - texInf.x = 64.5f/256.0f; - texInf.y = 21.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 22.0f/256.0f; // orange - } - if ( type == PARTITRACK12 ) // drag reactor? - { - texInf.x = 64.5f/256.0f; - texInf.y = 21.0f/256.0f; - texSup.x = 95.5f/256.0f; - texSup.y = 22.0f/256.0f; // orange - } - - h = m_track[i].head; - p1 = m_track[i].pos[h]; - f1 = m_track[i].intensity; - - eye = m_engine->RetEyePt(); - a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); - - for ( counter=0 ; counterDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - - if ( f2 < 0.0f ) break; - f1 = f2; - p1 = p2; - } -} - -// Draws a triangular particle. - -void CParticule::DrawParticuleTriangle(int i) -{ - CObject* object; - Math::Matrix matrix; - Math::Vector eye, pos, angle; - - if ( m_particule[i].zoom == 0.0f ) return; - - eye = m_engine->RetEyePt(); - pos = m_particule[i].pos; - - object = m_particule[i].objLink; - if ( object != 0 ) - { - pos += object->RetPosition(0); - } - - angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); - angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); - angle.z = m_particule[i].angle; - - Math::LoadRotationXZYMatrix(matrix, angle); - matrix.Set(1, 4, pos.x); - matrix.Set(2, 4, pos.y); - matrix.Set(3, 4, pos.z); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2, - m_triangle[i].triangle, 3, NULL); - m_engine->AddStatisticTriangle(1); -} - -// Draw a normal particle. - -void CParticule::DrawParticuleNorm(int i) -{ - CObject* object; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Matrix matrix; - Math::Vector corner[4], eye, pos, n, angle; - Math::Point dim; - float zoom; - - zoom = m_particule[i].zoom; - if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f ) - { - zoom *= m_particule[i].intensity/0.5f; - } - - if ( zoom == 0.0f ) return; - if ( m_particule[i].intensity == 0.0f ) return; - - if ( m_particule[i].sheet == SH_INTERFACE ) - { - pos = m_particule[i].pos; - - n = Math::Vector(0.0f, 0.0f, -1.0f); - - dim.x = m_particule[i].dim.x * zoom; - dim.y = m_particule[i].dim.y * zoom; - - corner[0].x = pos.x+dim.x; - corner[0].y = pos.y+dim.y; - corner[0].z = 0.0f; - - corner[1].x = pos.x-dim.x; - corner[1].y = pos.y+dim.y; - corner[1].z = 0.0f; - - corner[2].x = pos.x+dim.x; - corner[2].y = pos.y-dim.y; - corner[2].z = 0.0f; - - corner[3].x = pos.x-dim.x; - corner[3].y = pos.y-dim.y; - corner[3].z = 0.0f; - - vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); - vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); - vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); - vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - } - else - { - eye = m_engine->RetEyePt(); - pos = m_particule[i].pos; - - object = m_particule[i].objLink; - if ( object != 0 ) - { - pos += object->RetPosition(0); - } - - angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); - angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); - angle.z = m_particule[i].angle; - - Math::LoadRotationXZYMatrix(matrix, angle); - matrix.Set(1, 4, pos.x); - matrix.Set(2, 4, pos.y); - matrix.Set(3, 4, pos.z); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - n = Math::Vector(0.0f, 0.0f, -1.0f); - - dim.x = m_particule[i].dim.x * zoom; - dim.y = m_particule[i].dim.y * zoom; - - corner[0].x = dim.x; - corner[0].y = dim.y; - corner[0].z = 0.0f; - - corner[1].x = -dim.x; - corner[1].y = dim.y; - corner[1].z = 0.0f; - - corner[2].x = dim.x; - corner[2].y = -dim.y; - corner[2].z = 0.0f; - - corner[3].x = -dim.x; - corner[3].y = -dim.y; - corner[3].z = 0.0f; - - vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); - vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); - vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); - vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - } -} - -// Draw a particle flat (horizontal). - -void CParticule::DrawParticuleFlat(int i) -{ - CObject* object; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Matrix matrix; - Math::Vector corner[4], pos, n, angle, eye; - Math::Point dim; - - if ( m_particule[i].zoom == 0.0f ) return; - if ( m_particule[i].intensity == 0.0f ) return; - - pos = m_particule[i].pos; - - object = m_particule[i].objLink; - if ( object != 0 ) - { - pos += object->RetPosition(0); - } - - angle.x = Math::PI/2.0f; - angle.y = 0.0f; - angle.z = m_particule[i].angle; - -#if 0 - if ( m_engine->RetRankView() == 1 ) // underwater? - { - angle.x = -Math::PI/2.0f; - pos.y -= 1.0f; - } -#else - if ( m_engine->RetRankView() == 1 ) // underwater? - { - pos.y -= 1.0f; - } - - eye = m_engine->RetEyePt(); - if ( pos.y > eye.y ) // seen from below? - { - angle.x = -Math::PI/2.0f; - } -#endif - - Math::LoadRotationXZYMatrix(matrix, angle); - matrix.Set(1, 4, pos.x); - matrix.Set(2, 4, pos.y); - matrix.Set(3, 4, pos.z); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - n = Math::Vector(0.0f, 0.0f, -1.0f); - - dim.x = m_particule[i].dim.x * m_particule[i].zoom; - dim.y = m_particule[i].dim.y * m_particule[i].zoom; - - corner[0].x = dim.x; - corner[0].y = dim.y; - corner[0].z = 0.0f; - - corner[1].x = -dim.x; - corner[1].y = dim.y; - corner[1].z = 0.0f; - - corner[2].x = dim.x; - corner[2].y = -dim.y; - corner[2].z = 0.0f; - - corner[3].x = -dim.x; - corner[3].y = -dim.y; - corner[3].z = 0.0f; - - vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); - vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); - vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); - vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); -} - -// Draw a particle to a flat sheet of fog. - -void CParticule::DrawParticuleFog(int i) -{ - CObject* object; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Matrix matrix; - Math::Vector corner[4], pos, n, angle, eye; - Math::Point dim, zoom; - - if ( !m_engine->RetFog() ) return; - if ( m_particule[i].intensity == 0.0f ) return; - - pos = m_particule[i].pos; - - dim.x = m_particule[i].dim.x; - dim.y = m_particule[i].dim.y; - - if ( m_particule[i].type == PARTIFOG0 || - m_particule[i].type == PARTIFOG2 || - m_particule[i].type == PARTIFOG4 || - m_particule[i].type == PARTIFOG6 ) - { -//? pos.x += sinf(m_particule[i].zoom*1.2f)*dim.x*0.1f; -//? pos.y += cosf(m_particule[i].zoom*1.5f)*dim.y*0.1f; - zoom.x = 1.0f+sinf(m_particule[i].zoom*2.0f)/6.0f; - zoom.y = 1.0f+cosf(m_particule[i].zoom*2.7f)/6.0f; - } - if ( m_particule[i].type == PARTIFOG1 || - m_particule[i].type == PARTIFOG3 || - m_particule[i].type == PARTIFOG5 || - m_particule[i].type == PARTIFOG7 ) - { -//? pos.x += sinf(m_particule[i].zoom*1.0f)*dim.x*0.1f; -//? pos.y += cosf(m_particule[i].zoom*1.3f)*dim.y*0.1f; - zoom.x = 1.0f+sinf(m_particule[i].zoom*3.0f)/6.0f; - zoom.y = 1.0f+cosf(m_particule[i].zoom*3.7f)/6.0f; - } - - dim.x *= zoom.x; - dim.y *= zoom.y; - - object = m_particule[i].objLink; - if ( object != 0 ) - { - pos += object->RetPosition(0); - } - - angle.x = Math::PI/2.0f; - angle.y = 0.0f; - angle.z = m_particule[i].angle; - - if ( m_engine->RetRankView() == 1 ) // underwater? - { - pos.y -= 1.0f; - } - - eye = m_engine->RetEyePt(); - if ( pos.y > eye.y ) // seen from below? - { - angle.x = -Math::PI/2.0f; - } - - Math::LoadRotationXZYMatrix(matrix, angle); - matrix.Set(1, 4, pos.x); - matrix.Set(2, 4, pos.y); - matrix.Set(3, 4, pos.z); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - n = Math::Vector(0.0f, 0.0f, -1.0f); - - corner[0].x = dim.x; - corner[0].y = dim.y; - corner[0].z = 0.0f; - - corner[1].x = -dim.x; - corner[1].y = dim.y; - corner[1].z = 0.0f; - - corner[2].x = dim.x; - corner[2].y = -dim.y; - corner[2].z = 0.0f; - - corner[3].x = -dim.x; - corner[3].y = -dim.y; - corner[3].z = 0.0f; - - vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); - vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); - vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); - vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); -} - -// Draw a particle in the form of radius. - -void CParticule::DrawParticuleRay(int i) -{ - CObject* object; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Matrix matrix; - Math::Vector corner[4], eye, pos, goal, n, angle, proj; - Math::Point dim, texInf, texSup; - bool bLeft; - float a, len, adv, prop, vario1, vario2; - int r, rank, step, first, last; - - if ( m_particule[i].zoom == 0.0f ) return; - if ( m_particule[i].intensity == 0.0f ) return; - - eye = m_engine->RetEyePt(); - pos = m_particule[i].pos; - goal = m_particule[i].goal; - - object = m_particule[i].objLink; - if ( object != 0 ) - { - pos += object->RetPosition(0); - } - - a = Math::RotateAngle(Math::Point(pos.x,pos.z), Math::Point(goal.x,goal.z), Math::Point(eye.x,eye.z)); - bLeft = (a < Math::PI); - - proj = Math::Projection(pos, goal, eye); - angle.x = -Math::RotateAngle(Math::DistanceProjected(proj, eye), proj.y-eye.y); - angle.y = Math::RotateAngle(pos.z-goal.z, pos.x-goal.x)+Math::PI/2.0f; - angle.z = -Math::RotateAngle(Math::DistanceProjected(pos, goal), pos.y-goal.y); - if ( bLeft ) angle.x = -angle.x; - - Math::LoadRotationZXYMatrix(matrix, angle); - matrix.Set(1, 4, pos.x); - matrix.Set(2, 4, pos.y); - matrix.Set(3, 4, pos.z); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - n = Math::Vector(0.0f, 0.0f, bLeft?1.0f:-1.0f); - - dim.x = m_particule[i].dim.x * m_particule[i].zoom; - dim.y = m_particule[i].dim.y * m_particule[i].zoom; - - if ( bLeft ) dim.y = -dim.y; - - len = Math::Distance(pos, goal); - adv = 0.0f; - - step = (int)(len/(dim.x*2.0f))+1; - - if ( step == 1 ) - { - vario1 = 1.0f; - vario2 = 1.0f; - } - else - { - vario1 = 0.0f; - vario2 = 2.0f; - } - - if ( m_particule[i].type == PARTIRAY2 ) - { - first = 0; - last = step; - vario1 = 0.0f; - vario2 = 0.0f; - } - else if ( m_particule[i].type == PARTIRAY3 ) - { - if ( m_particule[i].time < m_particule[i].duration*0.40f ) - { - prop = m_particule[i].time / (m_particule[i].duration*0.40f); - first = 0; - last = (int)(prop*step); - } - else if ( m_particule[i].time < m_particule[i].duration*0.60f ) - { - first = 0; - last = step; - } - else - { - prop = (m_particule[i].time-m_particule[i].duration*0.60f) / (m_particule[i].duration*0.40f); - first = (int)(prop*step); - last = step; - } - } - else - { - if ( m_particule[i].time < m_particule[i].duration*0.50f ) - { - prop = m_particule[i].time / (m_particule[i].duration*0.50f); - first = 0; - last = (int)(prop*step); - } - else if ( m_particule[i].time < m_particule[i].duration*0.75f ) - { - first = 0; - last = step; - } - else - { - prop = (m_particule[i].time-m_particule[i].duration*0.75f) / (m_particule[i].duration*0.25f); - first = (int)(prop*step); - last = step; - } - } - - corner[0].x = adv; - corner[2].x = adv; - corner[0].y = dim.y; - corner[2].y = -dim.y; - corner[0].z = (Math::Rand()-0.5f)*vario1; - corner[1].z = (Math::Rand()-0.5f)*vario1; - corner[2].z = (Math::Rand()-0.5f)*vario1; - corner[3].z = (Math::Rand()-0.5f)*vario1; - - for ( rank=0 ; rank= first && rank <= last ) - { -#if 1 - texInf = m_particule[i].texInf; - texSup = m_particule[i].texSup; - - r = rand()%16; - texInf.x += 0.25f*(r/4); - texSup.x += 0.25f*(r/4); - if ( r%2 < 1 && adv > 0.0f && m_particule[i].type != PARTIRAY1 ) - { - Math::Swap(texInf.x, texSup.x); - } - if ( r%4 < 2 ) - { - Math::Swap(texInf.y, texSup.y); - } -#else - texInf.x = Math::Mod(texInf.x+0.25f, 1.0f); - texSup.x = Math::Mod(texSup.x+0.25f, 1.0f); -#endif - - vertex[0] = D3DVERTEX2(corner[1], n, texSup.x, texSup.y); - vertex[1] = D3DVERTEX2(corner[0], n, texInf.x, texSup.y); - vertex[2] = D3DVERTEX2(corner[3], n, texSup.x, texInf.y); - vertex[3] = D3DVERTEX2(corner[2], n, texInf.x, texInf.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - } - adv += dim.x*2.0f; - } -} - -// Draws a spherical particle. - -void CParticule::DrawParticuleSphere(int i) -{ - D3DVERTEX2 vertex[2*16*(16+1)]; // triangles - Math::Matrix matrix, rot; - Math::Vector angle, v0, v1; - Math::Point ts, ti; - float zoom, deltaRingAngle, deltaSegAngle; - float r0,r1, tu0,tv0, tu1,tv1; - int j, ring, seg, numRings, numSegments; - - zoom = m_particule[i].zoom; -#if 0 - if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f ) - { - zoom *= m_particule[i].intensity/0.5f; - } -#endif - - if ( zoom == 0.0f ) return; - - m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity)); - - matrix.LoadIdentity(); - matrix.Set(1, 1, zoom); - matrix.Set(2, 2, zoom); - matrix.Set(3, 3, zoom); - matrix.Set(1, 4, m_particule[i].pos.x); - matrix.Set(2, 4, m_particule[i].pos.y); - matrix.Set(3, 4, m_particule[i].pos.z); - - if ( m_particule[i].angle != 0.0f ) - { - angle.x = m_particule[i].angle*0.4f; - angle.y = m_particule[i].angle*1.0f; - angle.z = m_particule[i].angle*0.7f; - Math::LoadRotationZXYMatrix(rot, angle); - matrix = Math::MultiplyMatrices(rot, matrix); - } - - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - ts.x = m_particule[i].texSup.x; - ts.y = m_particule[i].texSup.y; - ti.x = m_particule[i].texInf.x; - ti.y = m_particule[i].texInf.y; - - // Choose a tesselation level. - if ( m_particule[i].type == PARTISPHERE3 || - m_particule[i].type == PARTISPHERE5 ) - { - numRings = 16; - numSegments = 16; - } - else - { - numRings = 8; - numSegments = 10; - } - - // Establish constants used in sphere generation. - deltaRingAngle = Math::PI/numRings; - deltaSegAngle = 2.0f*Math::PI/numSegments; - - // Generate the group of rings for the sphere. - j = 0; - for ( ring=0 ; ringDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL); - m_engine->AddStatisticTriangle(j); - - m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity)); -} - -// Returns the height depending on the progress. - -float ProgressCylinder(float progress) -{ - if ( progress < 0.5f ) - { - return 1.0f - (powf(1.0f-progress*2.0f, 2.0f)); - } - else - { - return 1.0f - (powf(progress*2.0f-1.0f, 2.0f)); - } -} - -// Draws a cylindrical particle. - -void CParticule::DrawParticuleCylinder(int i) -{ - D3DVERTEX2 vertex[2*5*(10+1)]; // triangles - Math::Matrix matrix, rot; - Math::Vector angle, v0, v1; - Math::Point ts, ti; - float progress, zoom, diam, deltaSegAngle, h[6], d[6]; - float r0,r1, tu0,tv0, tu1,tv1, p1, p2, pp; - int j, ring, seg, numRings, numSegments; - - progress = m_particule[i].zoom; - zoom = m_particule[i].dim.x; - diam = m_particule[i].dim.y; - if ( progress >= 1.0f || zoom == 0.0f ) return; - - m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity)); - - matrix.LoadIdentity(); - matrix.Set(1, 1, zoom); - matrix.Set(2, 2, zoom); - matrix.Set(3, 3, zoom); - matrix.Set(1, 4, m_particule[i].pos.x); - matrix.Set(2, 4, m_particule[i].pos.y); - matrix.Set(3, 4, m_particule[i].pos.z); - - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - ts.x = m_particule[i].texSup.x; - ts.y = m_particule[i].texSup.y; - ti.x = m_particule[i].texInf.x; - ti.y = m_particule[i].texInf.y; - - numRings = 5; - numSegments = 10; - deltaSegAngle = 2.0f*Math::PI/numSegments; - - if ( m_particule[i].type == PARTIPLOUF0 ) - { -#if 0 - if ( progress <= 0.5f ) - { - p1 = progress/0.5f; // front - p2 = 0.0f; // back - } - else - { - p1 = 1.0f; // front - p2 = (progress-0.5f)/0.5f; // back - ts.y += (ti.y-ts.y)*p2; - } -#else - p1 = progress; // front - p2 = powf(progress, 5.0f); // back -#endif - - for ( ring=0 ; ring<=numRings ; ring++ ) - { - pp = p2+(p1-p2)*((float)ring/numRings); - d[ring] = diam/zoom+pp*2.0f; - h[ring] = ProgressCylinder(pp); - } - } - - j = 0; - for ( ring=0 ; ringDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL); - m_engine->AddStatisticTriangle(j); - - m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity)); -} - -// Draws a tire mark. - -void CParticule::DrawParticuleWheel(int i) -{ - Math::Vector pos[4], center; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector n; - Math::Point ts, ti; - float dist, dp; - - dist = Math::DistanceProjected(m_engine->RetEyePt(), m_wheelTrace[i].pos[0]); - if ( dist > 300.0f ) return; - - pos[0] = m_wheelTrace[i].pos[0]; - pos[1] = m_wheelTrace[i].pos[1]; - pos[2] = m_wheelTrace[i].pos[2]; - pos[3] = m_wheelTrace[i].pos[3]; - - if ( m_wheelTrace[i].type == PARTITRACE0 ) // white ground track? - { - ts.x = 8.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE1 ) // black ground track? - { - ts.x = 0.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE2 ) // gray ground track? - { - ts.x = 0.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE3 ) // light gray ground track? - { - ts.x = 8.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE4 ) // red ground track? - { - ts.x = 32.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE5 ) // pink ground track? - { - ts.x = 40.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE6 ) // violet ground track? - { - ts.x = 32.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE7 ) // orange ground track? - { - ts.x = 40.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE8 ) // yellow ground track? - { - ts.x = 16.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE9 ) // beige ground track? - { - ts.x = 24.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE10 ) // brown ground track? - { - ts.x = 16.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE11 ) // skin ground track? - { - ts.x = 24.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE12 ) // green ground track? - { - ts.x = 48.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE13 ) // light green ground track? - { - ts.x = 56.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE14 ) // blue ground track? - { - ts.x = 48.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE15 ) // light blue ground track? - { - ts.x = 56.0f/256.0f; - ts.y = 232.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE16 ) // black arrow ground track? - { - ts.x = 160.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else if ( m_wheelTrace[i].type == PARTITRACE17 ) // red arrow ground track? - { - ts.x = 176.0f/256.0f; - ts.y = 224.0f/256.0f; - } - else - { - return; - } - - if ( m_wheelTrace[i].type == PARTITRACE16 || - m_wheelTrace[i].type == PARTITRACE17 ) - { - ti.x = ts.x+16.0f/256.0f; - ti.y = ts.y+16.0f/256.0f; - } - else - { - ti.x = ts.x+8.0f/256.0f; - ti.y = ts.y+8.0f/256.0f; - } - - dp = (1.0f/256.0f)/2.0f; - ts.x = ts.x+dp; - ts.y = ts.y+dp; - ti.x = ti.x-dp; - ti.y = ti.y-dp; - - n = Math::Vector(0.0f, 1.0f, 0.0f); - - vertex[0] = D3DVERTEX2(pos[0], n, ts.x, ts.y); - vertex[1] = D3DVERTEX2(pos[1], n, ti.x, ts.y); - vertex[2] = D3DVERTEX2(pos[2], n, ts.x, ti.y); - vertex[3] = D3DVERTEX2(pos[3], n, ti.x, ti.y); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); -} - -// Draws all the particles. - -void CParticule::DrawParticule(int sheet) -{ - D3DMATERIAL7 mat; - Math::Matrix matrix; - bool bLoadTexture; - char name[20]; - int state, t, i, j, r; - - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, true); -//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, false); - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - - // Draw the basic particles of triangles. - if ( m_totalInterface[0][sheet] > 0 ) - { - for ( i=0 ; iSetTexture(m_triangle[i].texName1); - m_engine->SetMaterial(m_triangle[i].material); - m_engine->SetState(m_triangle[i].state); - DrawParticuleTriangle(i); - } - } - - // Draw the particles was calculated based on edge. - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, false); - - ZeroMemory( &mat, sizeof(D3DMATERIAL7) ); - mat.diffuse.r = 1.0f; - mat.diffuse.g = 1.0f; - mat.diffuse.b = 1.0f; // white - mat.ambient.r = 0.5f; - mat.ambient.g = 0.5f; - mat.ambient.b = 0.5f; - m_engine->SetMaterial(mat); - - // Draw tire marks. - if ( m_wheelTraceTotal > 0 && sheet == SH_WORLD ) - { -#if _POLISH - m_engine->SetTexture("textp.tga"); -#else - m_engine->SetTexture("text.tga"); -#endif - m_engine->SetState(D3DSTATETTw); -//? m_engine->SetState(D3DSTATENORMAL); - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - for ( i=0 ; i=1 ; t-- ) // black behind! - { - if ( m_totalInterface[t][sheet] == 0 ) continue; - - bLoadTexture = false; - - if ( t == 4 ) state = D3DSTATETTw; // text.tga - else state = D3DSTATETTb; // effect[00..02].tga - m_engine->SetState(state); - - for ( j=0 ; jSetTexture(name); - bLoadTexture = true; - } - - r = m_particule[i].trackRank; - if ( r != -1 ) - { - m_engine->SetState(state); - TrackDraw(r, m_particule[i].type); // draws the drag - if ( !m_track[r].bDrawParticule ) continue; - } - - m_engine->SetState(state, RetColor(m_particule[i].intensity)); - - if ( m_particule[i].bRay ) // ray? - { - DrawParticuleRay(i); - } - else if ( m_particule[i].type == PARTIFLIC || // circle in the water? - m_particule[i].type == PARTISHOW || - m_particule[i].type == PARTICHOC || - m_particule[i].type == PARTIGFLAT ) - { - DrawParticuleFlat(i); - } - else if ( m_particule[i].type >= PARTIFOG0 && - m_particule[i].type <= PARTIFOG9 ) - { - DrawParticuleFog(i); - } - else if ( m_particule[i].type >= PARTISPHERE0 && - m_particule[i].type <= PARTISPHERE9 ) // sphere? - { - DrawParticuleSphere(i); - } - else if ( m_particule[i].type >= PARTIPLOUF0 && - m_particule[i].type <= PARTIPLOUF4 ) // cylinder? - { - DrawParticuleCylinder(i); - } - else // normal? - { - DrawParticuleNorm(i); - } - } - } - -//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, true); - m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); -} - - -// Seeks if an object collided with a bullet. - -CObject* CParticule::SearchObjectGun(Math::Vector old, Math::Vector pos, - ParticuleType type, CObject *father) -{ - CObject *pObj, *pBest; - Math::Vector box1, box2, oPos, p; - ObjectType oType; - bool bShield; - float min, oRadius, dist, shieldRadius; - int i, j; - bool bHimself; - - if ( m_main->RetMovieLock() ) return 0; // current movie? - - bHimself = m_main->RetHimselfDamage(); - - min = 5.0f; - if ( type == PARTIGUN2 ) min = 2.0f; // shooting insect? - if ( type == PARTIGUN3 ) min = 3.0f; // suiciding spider? - - box1 = old; - box2 = pos; - if ( box1.x > box2.x ) Math::Swap(box1.x, box2.x); // box1 < box2 - if ( box1.y > box2.y ) Math::Swap(box1.y, box2.y); - if ( box1.z > box2.z ) Math::Swap(box1.z, box2.z); - box1.x -= min; - box1.y -= min; - box1.z -= min; - box2.x += min; - box2.y += min; - box2.z += min; - - pBest = 0; - bShield = false; - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( !pObj->RetActif() ) continue; // inactive? - if ( pObj == father ) continue; - - oType = pObj->RetType(); - - if ( oType == OBJECT_TOTO ) continue; - - if ( type == PARTIGUN1 ) // fireball shooting? - { - if ( oType == OBJECT_MOTHER ) continue; - if ( bHimself ) // damage is oneself? - { - if ( !IsAlien(oType) && - !IsSoft(oType) ) continue; - } - else // damage only to enemies? - { - if ( !IsAlien(oType) ) continue; - } - } - else if ( type == PARTIGUN2 ) // shooting insect? - { - if ( !IsSoft(oType) ) continue; - } - else if ( type == PARTIGUN3 ) // suiciding spider? - { - if ( !IsSoft(oType) ) continue; - } - else if ( type == PARTIGUN4 ) // orgaball shooting? - { - if ( oType == OBJECT_MOTHER ) continue; - if ( bHimself ) // damage is oneself? - { - if ( !IsAlien(oType) && - !IsSoft(oType) ) continue; - } - else // damage only to enemies? - { - if ( !IsAlien(oType) ) continue; - } - } - else if ( type == PARTITRACK11 ) // phazer shooting? - { - if ( bHimself ) // damage is oneself? - { - if ( !IsAlien(oType) && - !IsSoft(oType) ) continue; - } - else // damage only to enemies? - { - if ( !IsAlien(oType) ) continue; - } - } - else - { - continue; - } - - oPos = pObj->RetPosition(0); - - if ( type == PARTIGUN2 || // shooting insect? - type == PARTIGUN3 ) // suiciding spider? - { - // Test if the ball is entered into the sphere of a shield. - shieldRadius = pObj->RetShieldRadius(); - if ( shieldRadius > 0.0f ) - { - dist = Math::Distance(oPos, pos); - if ( dist <= shieldRadius ) - { - pBest = pObj; - bShield = true; - } - } - } - if ( bShield ) continue; - - // Test the center of the object, which is necessary for objects - // that have no sphere in the center (station). - dist = Math::Distance(oPos, pos)-4.0f; - if ( dist < min ) - { - pBest = pObj; - } - - // Test with all spheres of the object. - j = 0; - while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) - { - if ( oPos.x+oRadius < box1.x || oPos.x-oRadius > box2.x || // outside the box? - oPos.y+oRadius < box1.y || oPos.y-oRadius > box2.y || - oPos.z+oRadius < box1.z || oPos.z-oRadius > box2.z ) continue; - - p = Math::Projection(old, pos, oPos); - dist = Math::Distance(p, oPos)-oRadius; - if ( dist < min ) - { - pBest = pObj; - } - } - } - - return pBest; -} - -// Seeks if an object collided with a ray. - -CObject* CParticule::SearchObjectRay(Math::Vector pos, Math::Vector goal, - ParticuleType type, CObject *father) -{ - CObject* pObj; - Math::Vector box1, box2, oPos, p; - ObjectType oType; - float min, dist; - int i; - - if ( m_main->RetMovieLock() ) return 0; // current movie? - - min = 10.0f; - - box1 = pos; - box2 = goal; - if ( box1.x > box2.x ) Math::Swap(box1.x, box2.x); // box1 < box2 - if ( box1.y > box2.y ) Math::Swap(box1.y, box2.y); - if ( box1.z > box2.z ) Math::Swap(box1.z, box2.z); - box1.x -= min; - box1.y -= min; - box1.z -= min; - box2.x += min; - box2.y += min; - box2.z += min; - - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - if ( !pObj->RetActif() ) continue; // inactive? - if ( pObj == father ) continue; - - oType = pObj->RetType(); - - if ( oType == OBJECT_TOTO ) continue; - - if ( type == PARTIRAY1 && - oType != OBJECT_MOBILEtg && - oType != OBJECT_TEEN28 && - oType != OBJECT_TEEN31 && - oType != OBJECT_ANT && - oType != OBJECT_SPIDER && - oType != OBJECT_BEE && - oType != OBJECT_WORM && - oType != OBJECT_MOTHER && - oType != OBJECT_NEST ) continue; - - oPos = pObj->RetPosition(0); - - if ( oPos.x < box1.x || oPos.x > box2.x || // outside the box? - oPos.y < box1.y || oPos.y > box2.y || - oPos.z < box1.z || oPos.z > box2.z ) continue; - - p = Math::Projection(pos, goal, oPos); - dist = Math::Distance(p, oPos); - if ( dist < min ) return pObj; - } - - return 0; -} - - -// Sounded one. - -void CParticule::Play(Sound sound, Math::Vector pos, float amplitude) -{ - if ( m_sound == 0 ) - { - m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); - } - - m_sound->Play(sound, pos, amplitude); -} - - - -// Seeks the color if you're in the fog. -// Returns black if you're not in the fog. - -D3DCOLORVALUE CParticule::RetFogColor(Math::Vector pos) -{ - D3DCOLORVALUE result, color; - float dist, factor; - int fog, i; - - result.r = 0.0f; - result.g = 0.0f; - result.b = 0.0f; - result.a = 0.0f; - - for ( fog=0 ; fog= m_particule[i].pos.y+FOG_HSUP ) continue; - if ( pos.y <= m_particule[i].pos.y-FOG_HINF ) continue; - - dist = Math::DistanceProjected(pos, m_particule[i].pos); - if ( dist >= m_particule[i].dim.x*1.5f ) continue; - - // Calculates the horizontal distance. - factor = 1.0f-powf(dist/(m_particule[i].dim.x*1.5f), 4.0f); - - // Calculates the vertical distance. - if ( pos.y > m_particule[i].pos.y ) - { - factor *= 1.0f-(pos.y-m_particule[i].pos.y)/FOG_HSUP; - } - else - { - factor *= 1.0f-(m_particule[i].pos.y-pos.y)/FOG_HINF; - } - - factor *= 0.3f; - - if ( m_particule[i].type == PARTIFOG0 || - m_particule[i].type == PARTIFOG1 ) // blue? - { - color.r = 0.0f; - color.g = 0.5f; - color.b = 1.0f; - } - else if ( m_particule[i].type == PARTIFOG2 || - m_particule[i].type == PARTIFOG3 ) // red? - { - color.r = 2.0f; - color.g = 1.0f; - color.b = 0.0f; - } - else if ( m_particule[i].type == PARTIFOG4 || - m_particule[i].type == PARTIFOG5 ) // white? - { - color.r = 1.0f; - color.g = 1.0f; - color.b = 1.0f; - } - else if ( m_particule[i].type == PARTIFOG6 || - m_particule[i].type == PARTIFOG7 ) // yellow? - { - color.r = 0.8f; - color.g = 1.0f; - color.b = 0.4f; - } - else - { - color.r = 0.0f; - color.g = 0.0f; - color.b = 0.0f; - } - - result.r += color.r*factor; - result.g += color.g*factor; - result.b += color.b*factor; - } - - if ( result.r > 0.6f ) result.r = 0.6f; - if ( result.g > 0.6f ) result.g = 0.6f; - if ( result.b > 0.6f ) result.b = 0.6f; - - return result; -} - - -// Writes a file. BMP containing all the tire tracks. - -bool CParticule::WriteWheelTrace(char *filename, int width, int height, - Math::Vector dl, Math::Vector ur) -{ - HDC hDC; - HDC hDCImage; - HBITMAP hb; - PBITMAPINFO info; - HBRUSH hBrush; - HPEN hPen; - HGDIOBJ old; - RECT rect; - COLORREF color; - Math::Point pos[4]; - POINT list[4]; - int i; - - if ( !m_engine->GetRenderDC(hDC) ) return false; - - hDCImage = CreateCompatibleDC(hDC); - if ( hDCImage == 0 ) - { - m_engine->ReleaseRenderDC(hDC); - return false; - } - - hb = CreateCompatibleBitmap(hDC, width, height); - if ( hb == 0 ) - { - DeleteDC(hDCImage); - m_engine->ReleaseRenderDC(hDC); - return false; - } - - SelectObject(hDCImage, hb); - - rect.left = 0; - rect.right = width; - rect.top = 0; - rect.bottom = height; - FillRect(hDCImage, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); - - hPen = CreatePen(PS_NULL, 1, 0); - SelectObject(hDCImage, hPen); - - for ( i=0 ; iCreateBitmapInfoStruct(hb); - if ( info == 0 ) - { - DeleteObject(hb); - DeleteDC(hDCImage); - m_engine->ReleaseRenderDC(hDC); - return false; - } - - m_engine->CreateBMPFile(filename, info, hb, hDCImage); - - DeleteObject(hb); - DeleteDC(hDCImage); - m_engine->ReleaseRenderDC(hDC); - return true; -} - +// * 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/. + +// particule.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dmath.h" +#include "old/d3dtextr.h" +#include "old/d3dengine.h" +#include "old/d3dutil.h" +#include "common/language.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "common/event.h" +#include "object/object.h" +#include "physics/physics.h" +#include "object/auto/auto.h" +#include "object/robotmain.h" +#include "old/terrain.h" +#include "old/sound.h" +#include "old/water.h" +#include "old/particule.h" + + + +const float FOG_HSUP = 10.0f; +const float FOG_HINF = 100.0f; + + + + +// Check if an object can be destroyed, but is not an enemy. + +bool IsSoft(ObjectType type) +{ + return ( type == OBJECT_HUMAN || + type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr || // robot? + type == OBJECT_METAL || + type == OBJECT_POWER || + type == OBJECT_ATOMIC || // cargo? + type == OBJECT_DERRICK || + type == OBJECT_STATION || + type == OBJECT_FACTORY || + type == OBJECT_REPAIR || + type == OBJECT_DESTROYER|| + type == OBJECT_CONVERT || + type == OBJECT_TOWER || + type == OBJECT_RESEARCH || + type == OBJECT_RADAR || + type == OBJECT_INFO || + type == OBJECT_ENERGY || + type == OBJECT_LABO || + type == OBJECT_NUCLEAR || + type == OBJECT_PARA ); // building? +} + +// Check if an object is a destroyable enemy. + +bool IsAlien(ObjectType type) +{ + return ( type == OBJECT_ANT || + type == OBJECT_SPIDER || + type == OBJECT_BEE || + type == OBJECT_WORM || + type == OBJECT_MOTHER || + type == OBJECT_NEST || + type == OBJECT_BULLET || + type == OBJECT_EGG || + type == OBJECT_MOBILEtg || + type == OBJECT_TEEN28 || + type == OBJECT_TEEN31 ); +} + +// Returns the damping factor for friendly fire. + +float RetDecay(ObjectType type) +{ + if ( IsSoft(type) ) return 0.2f; + return 1.0f; +} + + + +// Application constructor. + +CParticule::CParticule(CInstanceManager *iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_PARTICULE, this); + + m_pD3DDevice = 0; + m_engine = engine; + m_main = 0; + m_terrain = 0; + m_water = 0; + m_sound = 0; + m_uniqueStamp = 0; + m_exploGunCounter = 0; + m_lastTimeGunDel = 0.0f; + m_absTime = 0.0f; + + FlushParticule(); +} + +// Application destructor. Free memory. + +CParticule::~CParticule() +{ + m_iMan->DeleteInstance(CLASS_PARTICULE, this); +} + + +void CParticule::SetD3DDevice(LPDIRECT3DDEVICE7 device) +{ + m_pD3DDevice = device; +} + + +// Removes all particles. + +void CParticule::FlushParticule() +{ + int i, j; + + for ( i=0 ; iSearchInstance(CLASS_MAIN); + } + +#if 0 + if ( sheet == SH_WORLD && + type != PARTISELY && + type != PARTISELR && + type != PARTIGUN1 && + type != PARTIGUN2 && + type != PARTIGUN3 && + type != PARTIGUN4 && + type != PARTIQUARTZ && + !m_main->RetMovieLock() ) + { + dist = Math::Distance(pos, m_engine->RetEyePt()); + if ( dist > 300.0f ) return -1; + } +#endif + + t = -1; + if ( type == PARTIEXPLOT || + type == PARTIEXPLOO || + type == PARTIMOTOR || + type == PARTIBLITZ || + type == PARTICRASH || + type == PARTIVAPOR || + type == PARTIGAS || + type == PARTIBASE || + type == PARTIFIRE || + type == PARTIFIREZ || + type == PARTIBLUE || + type == PARTIROOT || + type == PARTIRECOVER || + type == PARTIEJECT || + type == PARTISCRAPS || + type == PARTIGUN2 || + type == PARTIGUN3 || + type == PARTIGUN4 || + type == PARTIQUEUE || + type == PARTIORGANIC1 || + type == PARTIORGANIC2 || + type == PARTIFLAME || + type == PARTIBUBBLE || + type == PARTIERROR || + type == PARTIWARNING || + type == PARTIINFO || + type == PARTISPHERE1 || + type == PARTISPHERE2 || + type == PARTISPHERE4 || + type == PARTISPHERE5 || + type == PARTISPHERE6 || + type == PARTIPLOUF0 || + type == PARTITRACK1 || + type == PARTITRACK2 || + type == PARTITRACK3 || + type == PARTITRACK4 || + type == PARTITRACK5 || + type == PARTITRACK6 || + type == PARTITRACK7 || + type == PARTITRACK8 || + type == PARTITRACK9 || + type == PARTITRACK10 || + type == PARTITRACK11 || + type == PARTITRACK12 || + type == PARTILENS1 || + type == PARTILENS2 || + type == PARTILENS3 || + type == PARTILENS4 || + type == PARTIGFLAT || + type == PARTIDROP || + type == PARTIWATER || + type == PARTILIMIT1 || + type == PARTILIMIT2 || + type == PARTILIMIT3 || + type == PARTILIMIT4 || + type == PARTIEXPLOG1 || + type == PARTIEXPLOG2 ) + { + t = 1; // effect00 + } + if ( type == PARTIGLINT || + type == PARTIGLINTb || + type == PARTIGLINTr || + type == PARTITOTO || + type == PARTISELY || + type == PARTISELR || + type == PARTIQUARTZ || + type == PARTIGUNDEL || + type == PARTICONTROL || + type == PARTISHOW || + type == PARTICHOC || + type == PARTIFOG4 || + type == PARTIFOG5 || + type == PARTIFOG6 || + type == PARTIFOG7 ) + { + t = 2; // effect01 + } + if ( type == PARTIGUN1 || + type == PARTIFLIC || + type == PARTISPHERE0 || + type == PARTISPHERE3 || + type == PARTIFOG0 || + type == PARTIFOG1 || + type == PARTIFOG2 || + type == PARTIFOG3 ) + { + t = 3; // effect02 + } + if ( type == PARTISMOKE1 || + type == PARTISMOKE2 || + type == PARTISMOKE3 || + type == PARTIBLOOD || + type == PARTIBLOODM || + type == PARTIVIRUS1 || + type == PARTIVIRUS2 || + type == PARTIVIRUS3 || + type == PARTIVIRUS4 || + type == PARTIVIRUS5 || + type == PARTIVIRUS6 || + type == PARTIVIRUS7 || + type == PARTIVIRUS8 || + type == PARTIVIRUS9 || + type == PARTIVIRUS10 ) + { + t = 4; // text (D3DSTATETTw) + } + if ( t >= MAXPARTITYPE ) return -1; + if ( t == -1 ) return -1; + + for ( j=0 ; j= PARTIFOG0 && + type <= PARTIFOG9 ) + { + if ( m_fogTotal < MAXPARTIFOG ) + m_fog[m_fogTotal++] = i; + } + + return i | ((m_particule[i].uniqueStamp&0xffff)<<16); + } + } + + return -1; +} + +// Creates a new triangular particle (debris). +// Returns the channel of the particle created or -1 on error. + +int CParticule::CreateFrag(Math::Vector pos, Math::Vector speed, + D3DTriangle *triangle, + ParticuleType type, + float duration, float mass, + float windSensitivity, int sheet) +{ + Math::Vector p1, p2, p3, n; + float l1, l2, l3, dx, dy; + int i, j, t; + + t = 0; + for ( j=0 ; j= MAXPARTITYPE ) return -1; + if ( t == -1 ) return -1; + + for ( j=0 ; jRetWheelTraceQuantity()*MAXWHEELTRACE); + max = MAXWHEELTRACE; + i = m_wheelTraceIndex++; + if ( m_wheelTraceIndex > max ) m_wheelTraceIndex = 0; + + m_wheelTrace[i].type = type; + m_wheelTrace[i].pos[0] = p1; // ul + m_wheelTrace[i].pos[1] = p2; // dl + m_wheelTrace[i].pos[2] = p3; // ur + m_wheelTrace[i].pos[3] = p4; // dr + m_wheelTrace[i].startTime = m_absTime; + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + + m_terrain->MoveOnFloor(m_wheelTrace[i].pos[0]); + m_wheelTrace[i].pos[0].y += 0.2f; // just above the ground + + m_terrain->MoveOnFloor(m_wheelTrace[i].pos[1]); + m_wheelTrace[i].pos[1].y += 0.2f; // just above the ground + + m_terrain->MoveOnFloor(m_wheelTrace[i].pos[2]); + m_wheelTrace[i].pos[2].y += 0.2f; // just above the ground + + m_terrain->MoveOnFloor(m_wheelTrace[i].pos[3]); + m_wheelTrace[i].pos[3].y += 0.2f; // just above the ground + + if ( m_wheelTraceTotal < max ) + { + m_wheelTraceTotal ++; + } + else + { + m_wheelTraceTotal = max; + } +} + + +// Check a channel number. +// Adapts the channel so it can be used as an offset in m_particule. + +bool CParticule::CheckChannel(int &channel) +{ + int uniqueStamp; + + uniqueStamp = (channel>>16)&0xffff; + channel &= 0xffff; + + if ( channel < 0 ) return false; + if ( channel >= MAXPARTICULE*MAXPARTITYPE ) return false; +#if 0 + if ( !m_particule[channel].bUsed ) return false; + + if ( m_particule[channel].uniqueStamp != uniqueStamp ) return false; +#else + if ( !m_particule[channel].bUsed ) + { + OutputDebugString("CheckChannel bUsed=false !\n"); + return false; + } + + if ( m_particule[channel].uniqueStamp != uniqueStamp ) + { + OutputDebugString("CheckChannel uniqueStamp !\n"); + return false; + } +#endif + + return true; +} + +// Removes a particle after his rank. + +void CParticule::DeleteRank(int rank) +{ + int i; + + if ( m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] > 0 ) + { + m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] --; + } + + i = m_particule[rank].trackRank; + if ( i != -1 ) // drag associated? + { + m_track[i].bUsed = false; // frees the drag + } + + m_particule[rank].bUsed = false; +} + +// Removes all particles of a given type. + +void CParticule::DeleteParticule(ParticuleType type) +{ + int i; + + for ( i=0 ; i 0 ) + { + m_totalInterface[channel/MAXPARTICULE][m_particule[channel].sheet] --; + } + + i = m_particule[channel].trackRank; + if ( i != -1 ) // drag associated? + { + m_track[i].bUsed = false; // frees the drag + } + + m_particule[channel].bUsed = false; +} + + +// Specifies the object to which the particle is bound. + +void CParticule::SetObjectLink(int channel, CObject *object) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].objLink = object; +} + +// Specifies the parent object that created the particle. + +void CParticule::SetObjectFather(int channel, CObject *object) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].objFather = object; +} + +void CParticule::SetPosition(int channel, Math::Vector pos) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].pos = pos; +} + +void CParticule::SetDimension(int channel, Math::Point dim) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].dim = dim; +} + +void CParticule::SetZoom(int channel, float zoom) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].zoom = zoom; +} + +void CParticule::SetAngle(int channel, float angle) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].angle = angle; +} + +void CParticule::SetIntensity(int channel, float intensity) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].intensity = intensity; +} + +void CParticule::SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, + float angle, float intensity) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].pos = pos; + m_particule[channel].dim = dim; + m_particule[channel].zoom = zoom; + m_particule[channel].angle = angle; + m_particule[channel].intensity = intensity; +} + +void CParticule::SetPhase(int channel, ParticulePhase phase, float duration) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].phase = phase; + m_particule[channel].duration = duration; + m_particule[channel].phaseTime = m_particule[channel].time; +} + +// Returns the position of the particle. + +bool CParticule::GetPosition(int channel, Math::Vector &pos) +{ + if ( !CheckChannel(channel) ) return false; + pos = m_particule[channel].pos; + return true; +} + + +// Indicates whether a sheet evolves or not. + +void CParticule::SetFrameUpdate(int sheet, bool bUpdate) +{ + m_bFrameUpdate[sheet] = bUpdate; +} + +// Makes evolve all the particles. + +void CParticule::FrameParticule(float rTime) +{ + CObject* object; + Math::Vector eye, pos, speed, wind; + Math::Point ts, ti, dim; + bool bPause; + float progress, dp, h, duration, mass, amplitude; + int i, j, r, total; + + if ( m_main == 0 ) + { + m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN); + } + + bPause = ( m_engine->RetPause() && !m_main->RetInfoLock() ); + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + if ( m_water == 0 ) + { + m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); + } + + if ( !bPause ) + { + m_lastTimeGunDel += rTime; + m_absTime += rTime; + } + + wind = m_terrain->RetWind(); + eye = m_engine->RetEyePt(); + + for ( i=0 ; iRetFloorLevel(m_particule[i].pos, true); + } + h += m_particule[i].dim.y*0.75f; + if ( m_particule[i].pos.y < h ) // impact with the ground? + { + if ( m_particule[i].type == PARTIPART && + m_particule[i].weight > 3.0f && // heavy enough? + m_particule[i].bounce < 3 ) + { + amplitude = m_particule[i].weight*0.1f; + amplitude *= 1.0f-0.3f*m_particule[i].bounce; + if ( amplitude > 1.0f ) amplitude = 1.0f; + if ( amplitude > 0.0f ) + { + Play(SOUND_BOUM, m_particule[i].pos, amplitude); + } + } + + if ( m_particule[i].bounce < 3 ) + { + m_particule[i].pos.y = h; + m_particule[i].speed.y *= -0.4f; + m_particule[i].speed.x *= 0.4f; + m_particule[i].speed.z *= 0.4f; + m_particule[i].bounce ++; // more impact + } + else // disappears after 3 bounces? + { + if ( m_particule[i].pos.y < h-10.0f || + m_particule[i].time >= 20.0f ) + { + DeleteRank(i); + continue; + } + } + } + } + + // Manages drag associated. + r = m_particule[i].trackRank; + if ( r != -1 ) // drag exists? + { + if ( TrackMove(r, m_particule[i].pos, progress) ) + { + DeleteRank(i); + continue; + } + + m_track[r].bDrawParticule = (progress < 1.0f); + } + + if ( m_particule[i].type == PARTITRACK1 ) // explosion technique? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK2 ) // spray blue? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.500f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK3 ) // spider? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK4 ) // insect explosion? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.625f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK5 ) // derrick? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.750f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK6 ) // reset in/out? + { + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if ( m_particule[i].type == PARTITRACK7 || // win-1 ? + m_particule[i].type == PARTITRACK8 || // win-2 ? + m_particule[i].type == PARTITRACK9 || // win-3 ? + m_particule[i].type == PARTITRACK10 ) // win-4 ? + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.25f*(m_particule[i].type-PARTITRACK7); + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTITRACK11 ) // phazer shot? + { + object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); + m_particule[i].goal = m_particule[i].pos; + if ( object != 0 ) + { + if ( object->RetType() == OBJECT_MOTHER ) + { + object->ExploObject(EXPLO_BOUM, 0.1f); + } + else + { + object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType())); + } + } + + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTITRACK12 ) // drag reactor? + { + m_particule[i].zoom = 1.0f; + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIMOTOR ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.000f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIBLITZ ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + m_particule[i].angle = Math::Rand()*Math::PI*2.0f; + + ts.x = 0.125f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTICRASH ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + +//? m_particule[i].intensity = 1.0f-progress; + if ( progress < 0.25f ) + { + m_particule[i].zoom = progress/0.25f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + +//? ts.x = 0.250f; + ts.x = 0.000f; +//? ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIVAPOR ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + m_particule[i].zoom = 1.0f+progress*3.0f; + + ts.x = 0.000f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIGAS ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIBASE ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f+progress*7.0f; + m_particule[i].intensity = powf(1.0f-progress, 3.0f); + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIFIRE || + m_particule[i].type == PARTIFIREZ ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].type == PARTIFIRE ) + { + m_particule[i].zoom = 1.0f-progress; + } + else + { + m_particule[i].zoom = progress; + } + + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIGUN1 ) // fireball shot? + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].testTime >= 0.1f ) + { + m_particule[i].testTime = 0.0f; + + if ( m_terrain->RetFloorHeight(m_particule[i].pos, true) < -2.0f ) + { + m_exploGunCounter ++; + + if ( m_exploGunCounter%2 == 0 ) + { + pos = m_particule[i].goal; + m_terrain->MoveOnFloor(pos, true); + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = Math::Rand()*6.0f+6.0f; + dim.y = dim.x; + duration = Math::Rand()*1.0f+1.0f; + mass = 0.0f; + CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + + pos.y += 1.0f; + total = (int)(2.0f*m_engine->RetParticuleDensity()); + for ( j=0 ; jExploObject(EXPLO_BURN, 0.0f, RetDecay(object->RetType())); + + m_exploGunCounter ++; + + if ( m_exploGunCounter%2 == 0 ) + { + pos = m_particule[i].pos; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = Math::Rand()*6.0f+6.0f; + dim.y = dim.x; + duration = Math::Rand()*1.0f+1.0f; + mass = 0.0f; + CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f); + + pos.y += 1.0f; + total = (int)(2.0f*m_engine->RetParticuleDensity()); + for ( j=0 ; j= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].testTime >= 0.2f ) + { + m_particule[i].testTime = 0.0f; + object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); + m_particule[i].goal = m_particule[i].pos; + if ( object != 0 ) + { + if ( object->RetShieldRadius() > 0.0f ) // protected by shield? + { + CreateParticule(m_particule[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); + if ( m_lastTimeGunDel > 0.2f ) + { + m_lastTimeGunDel = 0.0f; + Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f); + } + DeleteRank(i); + continue; + } + else + { + if ( object->RetType() != OBJECT_HUMAN ) + { + Play(SOUND_TOUCH, m_particule[i].pos, 1.0f); + } + object->ExploObject(EXPLO_BOUM, 0.0f); // starts explosion + } + } + } + + m_particule[i].angle = Math::Rand()*Math::PI*2.0f; + m_particule[i].zoom = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIGUN3 ) // spider suicides? + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].testTime >= 0.2f ) + { + m_particule[i].testTime = 0.0f; + object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); + m_particule[i].goal = m_particule[i].pos; + if ( object != 0 ) + { + if ( object->RetShieldRadius() > 0.0f ) + { + CreateParticule(m_particule[i].pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f); + if ( m_lastTimeGunDel > 0.2f ) + { + m_lastTimeGunDel = 0.0f; + Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f); + } + DeleteRank(i); + continue; + } + else + { + object->ExploObject(EXPLO_BURN, 1.0f); // starts explosion + } + } + } + +//? ts.x = 0.875f; +//? ts.y = 0.750f; + ts.x = 0.500f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIGUN4 ) // orgaball shot? + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].testTime >= 0.1f ) + { + m_particule[i].testTime = 0.0f; + + if ( m_terrain->RetFloorHeight(m_particule[i].pos, true) < -2.0f ) + { + m_exploGunCounter ++; + + if ( m_exploGunCounter%2 == 0 ) + { + pos = m_particule[i].goal; + m_terrain->MoveOnFloor(pos, true); + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = Math::Rand()*4.0f+2.0f; + dim.y = dim.x; + duration = Math::Rand()*0.7f+0.7f; + mass = 0.0f; + CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); + } + + if ( m_exploGunCounter%4 == 0 ) + { + Play(SOUND_EXPLOg2, pos, 0.5f); + } + + DeleteRank(i); + continue; + } + + object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather); + m_particule[i].goal = m_particule[i].pos; + if ( object != 0 ) + { + object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType())); + + m_exploGunCounter ++; + + if ( m_exploGunCounter%2 == 0 ) + { + pos = m_particule[i].pos; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = Math::Rand()*4.0f+2.0f; + dim.y = dim.x; + duration = Math::Rand()*0.7f+0.7f; + mass = 0.0f; + CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f); + } + + if ( m_exploGunCounter%4 == 0 ) + { + Play(SOUND_EXPLOg2, pos, 0.5f); + } + + DeleteRank(i); + continue; + } + } + + m_particule[i].angle = Math::Rand()*Math::PI*2.0f; + m_particule[i].zoom = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIFLIC ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 0.1f+progress; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.00f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTISHOW ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.5f ) m_particule[i].intensity = progress/0.5f; + else m_particule[i].intensity = 2.0f-progress/0.5f; + m_particule[i].zoom = 1.0f-progress*0.8f; + m_particule[i].angle -= rTime*Math::PI*0.5f; + + ts.x = 0.50f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTICHOC ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 0.1f+progress; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.50f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIGFLAT ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 0.1f+progress; + m_particule[i].intensity = 1.0f-progress; + m_particule[i].angle -= rTime*Math::PI*2.0f; + + ts.x = 0.00f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTILIMIT1 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f; + m_particule[i].intensity = 1.0f; + + ts.x = 0.000f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if ( m_particule[i].type == PARTILIMIT2 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f; + m_particule[i].intensity = 1.0f; + + ts.x = 0.375f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if ( m_particule[i].type == PARTILIMIT3 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f; + m_particule[i].intensity = 1.0f; + + ts.x = 0.500f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIFOG0 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.3f+sinf(progress)*0.15f; + m_particule[i].angle += rTime*0.05f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if ( m_particule[i].type == PARTIFOG1 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.3f+sinf(progress)*0.15f; + m_particule[i].angle -= rTime*0.07f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIFOG2 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.6f+sinf(progress)*0.15f; + m_particule[i].angle += rTime*0.05f; + + ts.x = 0.75f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if ( m_particule[i].type == PARTIFOG3 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.6f+sinf(progress)*0.15f; + m_particule[i].angle -= rTime*0.07f; + + ts.x = 0.75f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIFOG4 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particule[i].angle += rTime*0.05f; + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if ( m_particule[i].type == PARTIFOG5 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particule[i].angle -= rTime*0.07f; + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIFOG6 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particule[i].angle += rTime*0.05f; + + ts.x = 0.50f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if ( m_particule[i].type == PARTIFOG7 ) + { + m_particule[i].zoom = progress; + m_particule[i].intensity = 0.5f+sinf(progress)*0.2f; + m_particule[i].angle -= rTime*0.07f; + + ts.x = 0.50f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + // Decreases the intensity if the camera + // is almost at the same height (fog was eye level). + if ( m_particule[i].type >= PARTIFOG0 && + m_particule[i].type <= PARTIFOG9 ) + { + h = 10.0f; + + if ( m_particule[i].pos.y >= eye.y && + m_particule[i].pos.y < eye.y+h ) + { + m_particule[i].intensity *= (m_particule[i].pos.y-eye.y)/h; + } + if ( m_particule[i].pos.y > eye.y-h && + m_particule[i].pos.y < eye.y ) + { + m_particule[i].intensity *= (eye.y-m_particule[i].pos.y)/h; + } + } + + if ( m_particule[i].type == PARTIEXPLOT || + m_particule[i].type == PARTIEXPLOO ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress/2.0f; + m_particule[i].intensity = 1.0f-progress; + + if ( m_particule[i].type == PARTIEXPLOT ) ts.x = 0.750f; + else ts.x = 0.875f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIEXPLOG1 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.375f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + if ( m_particule[i].type == PARTIEXPLOG2 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIFLAME ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress/2.0f; + if ( progress < 0.5f ) + { + m_particule[i].intensity = progress/0.5f; + } + else + { + m_particule[i].intensity = 2.0f-progress/0.5f; + } + + ts.x = 0.750f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIBUBBLE ) + { + if ( progress >= 1.0f || + m_particule[i].pos.y >= m_water->RetLevel() ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress/2.0f; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.250f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISMOKE1 || + m_particule[i].type == PARTISMOKE2 || + m_particule[i].type == PARTISMOKE3 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.25f ) + { + m_particule[i].zoom = progress/0.25f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.500f+0.125f*(m_particule[i].type-PARTISMOKE1); + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIBLOOD ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.750f+(rand()%2)*0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIBLOODM ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.875f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIVIRUS1 || + m_particule[i].type == PARTIVIRUS2 || + m_particule[i].type == PARTIVIRUS3 || + m_particule[i].type == PARTIVIRUS4 || + m_particule[i].type == PARTIVIRUS5 || + m_particule[i].type == PARTIVIRUS6 || + m_particule[i].type == PARTIVIRUS7 || + m_particule[i].type == PARTIVIRUS8 || + m_particule[i].type == PARTIVIRUS9 || + m_particule[i].type == PARTIVIRUS10 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.25f ) + { + m_particule[i].zoom = progress/0.25f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + m_particule[i].angle += rTime*Math::PI*1.0f; + + if ( m_particule[i].type == PARTIVIRUS1 ) // A ? + { + ts.x = 0.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 10.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS2 ) // C ? + { + ts.x = 19.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 28.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS3 ) // E ? + { + ts.x = 36.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 45.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS4 ) // N ? + { + ts.x = 110.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 120.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS5 ) // R ? + { + ts.x = 148.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 158.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS6 ) // T ? + { + ts.x = 166.0f/256.0f; ts.y = 19.0f/256.0f; + ti.x = 175.0f/256.0f; ti.y = 30.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS7 ) // 0 ? + { + ts.x = 90.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 98.0f/256.0f; ti.y = 13.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS8 ) // 2 ? + { + ts.x = 103.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 111.0f/256.0f; ti.y = 13.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS9 ) // 5 ? + { + ts.x = 125.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 132.0f/256.0f; ti.y = 13.0f/256.0f; + } + if ( m_particule[i].type == PARTIVIRUS10 ) // 9 ? + { + ts.x = 153.0f/256.0f; ts.y = 2.0f/256.0f; + ti.x = 161.0f/256.0f; ti.y = 13.0f/256.0f; + } + } + + if ( m_particule[i].type == PARTIBLUE ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIROOT ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.25f ) + { + m_particule[i].zoom = progress/0.25f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.000f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIRECOVER ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.25f ) + { + m_particule[i].zoom = progress/0.25f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f; + } + + ts.x = 0.875f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIEJECT ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f+powf(progress, 2.0f)*5.0f; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISCRAPS ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + + ts.x = 0.625f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIFRAG ) + { + m_particule[i].angle += rTime*Math::PI*0.5f; + + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if ( m_particule[i].type == PARTIPART ) + { + ts.x = 0.0f; + ts.y = 0.0f; + ti.x = 0.0f; + ti.y = 0.0f; + } + + if ( m_particule[i].type == PARTIQUEUE ) + { + if ( m_particule[i].testTime >= 0.05f ) + { + m_particule[i].testTime = 0.0f; + + Math::Vector pos, speed; + Math::Point dim; + + pos = m_particule[i].pos; +//? speed = -m_particule[i].speed*0.5f; + speed = Math::Vector(0.0f, 0.0f, 0.0f); + dim.x = 1.0f*(Math::Rand()*0.8f+0.6f); + dim.y = dim.x; + CreateParticule(pos, speed, dim, PARTIGAS, 0.5f); + } + + ts.x = 0.375f; + ts.y = 0.750f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIORGANIC1 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + + pos = m_particule[i].pos; + dim.x = m_particule[i].dim.x/4.0f; + dim.y = dim.x; + duration = m_particule[i].duration; + mass = m_particule[i].mass; + total = (int)(10.0f*m_engine->RetParticuleDensity()); + for ( i=0 ; iRetParticuleDensity()); + for ( i=0 ; i= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration); + + ts.x = 0.125f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIGLINT ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress > 0.5f ) + { +//? m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f); + m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; + } + m_particule[i].angle = m_particule[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIGLINTb ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress > 0.5f ) + { + m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; + } + m_particule[i].angle = m_particule[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIGLINTr ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress > 0.5f ) + { + m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f; + } + m_particule[i].angle = m_particule[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type >= PARTILENS1 && + m_particule[i].type <= PARTILENS4 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.5f ) + { + m_particule[i].zoom = progress*2.0f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.5f)*2.0f; + } +//? m_particule[i].angle = m_particule[i].time*Math::PI; + + ts.x = 0.25f*(m_particule[i].type-PARTILENS1); + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTICONTROL ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.3f ) + { + m_particule[i].zoom = progress/0.3f; + } + else + { + m_particule[i].zoom = 1.0f; + m_particule[i].intensity = 1.0f-(progress-0.3f)/0.7f; + } + + ts.x = 0.00f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIGUNDEL ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress > 0.5f ) + { + m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f); + } + m_particule[i].angle = m_particule[i].time*Math::PI; + + ts.x = 0.75f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIQUARTZ ) + { + if ( progress >= 1.0f ) + { + m_particule[i].time = 0.0f; + m_particule[i].duration = 0.5f+Math::Rand()*2.0f; + m_particule[i].pos.x = m_particule[i].speed.x + (Math::Rand()-0.5f)*m_particule[i].mass; + m_particule[i].pos.y = m_particule[i].speed.y + (Math::Rand()-0.5f)*m_particule[i].mass; + m_particule[i].pos.z = m_particule[i].speed.z + (Math::Rand()-0.5f)*m_particule[i].mass; + m_particule[i].dim.x = 0.5f+Math::Rand()*1.5f; + m_particule[i].dim.y = m_particule[i].dim.x; + progress = 0.0f; + } + + if ( progress < 0.2f ) + { + m_particule[i].zoom = progress/0.2f; + m_particule[i].intensity = 1.0f; + } + else + { + m_particule[i].zoom = 1.0f; + m_particule[i].intensity = 1.0f-(progress-0.2f)/0.8f; + } + + ts.x = 0.25f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTITOTO ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + if ( progress < 0.15f ) + { + m_particule[i].intensity = progress/0.15f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.15f)/0.85f; + } + m_particule[i].intensity *= 0.5f; + + ts.x = 0.25f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIERROR ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress*1.0f; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.500f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIWARNING ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress*1.0f; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.875f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIINFO ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress*1.0f; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.750f; + ts.y = 0.875f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISELY ) + { + ts.x = 0.75f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + if ( m_particule[i].type == PARTISELR ) + { + ts.x = 0.75f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTISPHERE0 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress*m_particule[i].dim.x; +//? m_particule[i].intensity = 1.0f-progress; + if ( progress < 0.65f ) + { + m_particule[i].intensity = progress/0.65f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f; + } + m_particule[i].intensity *= 0.5f; + + ts.x = 0.50f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTISPHERE1 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.30f ) + { + m_particule[i].intensity = progress/0.30f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.30f)/0.70f; + } + m_particule[i].zoom = progress*m_particule[i].dim.x; + m_particule[i].angle = m_particule[i].time*Math::PI*2.0f; + + ts.x = 0.000f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISPHERE2 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( progress < 0.20f ) + { + m_particule[i].intensity = 1.0f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.20f)/0.80f; + } + m_particule[i].zoom = progress*m_particule[i].dim.x; + m_particule[i].angle = m_particule[i].time*Math::PI*2.0f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISPHERE3 ) + { + if ( m_particule[i].phase == PARPHEND && + progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].phase == PARPHSTART ) + { + m_particule[i].intensity = progress; + if ( m_particule[i].intensity > 1.0f ) + { + m_particule[i].intensity = 1.0f; + } + } + + if ( m_particule[i].phase == PARPHEND ) + { + m_particule[i].intensity = 1.0f-progress; + } + + m_particule[i].zoom = m_particule[i].dim.x; + m_particule[i].angle = m_particule[i].time*Math::PI*0.2f; + + ts.x = 0.25f; + ts.y = 0.75f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTISPHERE4 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress*m_particule[i].dim.x; + if ( progress < 0.65f ) + { + m_particule[i].intensity = progress/0.65f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f; + } + m_particule[i].intensity *= 0.5f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTISPHERE5 ) + { + m_particule[i].intensity = 0.7f+sinf(progress)*0.3f; + m_particule[i].zoom = m_particule[i].dim.x*(1.0f+sinf(progress*0.7f)*0.01f); + m_particule[i].angle = m_particule[i].time*Math::PI*0.2f; + + ts.x = 0.25f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTISPHERE6 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = (1.0f-progress)*m_particule[i].dim.x; + m_particule[i].intensity = progress*0.5f; + + ts.x = 0.125f; + ts.y = 0.000f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIPLOUF0 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = progress; +#if 0 + if ( progress <= 0.5f ) + { + m_particule[i].intensity = 1.0f; + } + else + { + m_particule[i].intensity = 1.0f-(progress-0.5f)/0.5f; + } +#else +//? m_particule[i].intensity = 1.0f; + m_particule[i].intensity = 1.0f-progress; +#endif + + ts.x = 0.50f; + ts.y = 0.50f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIDROP ) + { + if ( progress >= 1.0f || + m_particule[i].pos.y < m_water->RetLevel() ) + { + DeleteRank(i); + continue; + } + + m_particule[i].zoom = 1.0f-progress; + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.750f; + ts.y = 0.500f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIWATER ) + { + if ( progress >= 1.0f || + m_particule[i].pos.y < m_water->RetLevel() ) + { + DeleteRank(i); + continue; + } + + m_particule[i].intensity = 1.0f-progress; + + ts.x = 0.125f; + ts.y = 0.125f; + ti.x = ts.x+0.125f; + ti.y = ts.y+0.125f; + } + + if ( m_particule[i].type == PARTIRAY1 ) // rayon tour ? + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + if ( m_particule[i].testTime >= 0.2f ) + { + m_particule[i].testTime = 0.0f; + object = SearchObjectRay(m_particule[i].pos, m_particule[i].goal, + m_particule[i].type, m_particule[i].objFather); + if ( object != 0 ) + { + object->ExploObject(EXPLO_BOUM, 0.0f); + } + } + + ts.x = 0.00f; + ts.y = 0.00f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + if ( m_particule[i].type == PARTIRAY2 || + m_particule[i].type == PARTIRAY3 ) + { + if ( progress >= 1.0f ) + { + DeleteRank(i); + continue; + } + + ts.x = 0.00f; + ts.y = 0.25f; + ti.x = ts.x+0.25f; + ti.y = ts.y+0.25f; + } + + dp = (1.0f/256.0f)/2.0f; + m_particule[i].texSup.x = ts.x+dp; + m_particule[i].texSup.y = ts.y+dp; + m_particule[i].texInf.x = ti.x-dp; + m_particule[i].texInf.y = ti.y-dp; + m_particule[i].time += rTime; + m_particule[i].testTime += rTime; + } +} + + +// Moves a drag. +// Returns true if the drag is finished. + +bool CParticule::TrackMove(int i, Math::Vector pos, float progress) +{ + Math::Vector last; + int h, hh; + + if ( i < 0 || i >= MAXTRACK ) return true; + if ( m_track[i].bUsed == false ) return true; + + if ( progress < 1.0f ) // particle exists? + { + h = m_track[i].head; + + if ( m_track[i].used == 1 || + m_track[i].last+m_track[i].step <= progress ) + { + m_track[i].last = progress; + last = m_track[i].pos[h]; + h ++; + if ( h == MAXTRACKLEN ) h = 0; + if ( m_track[i].used < MAXTRACKLEN ) m_track[i].used ++; + } + else + { + hh = h-1; + if ( hh < 0 ) hh = MAXTRACKLEN-1; + last = m_track[i].pos[hh]; + } + m_track[i].pos[h] = pos; + m_track[i].len[h] = Math::Distance(pos, last); + + m_track[i].head = h; + +//? m_track[i].intensity = 1.0f; + m_track[i].intensity = 1.0f-progress; + } + else // mort lente de la tra�n�e ? + { +//? m_track[i].intensity = 1.0f-(progress-1.0f)/(m_track[i].step*MAXTRACKLEN); + m_track[i].intensity = 0.0f; + } + + return (m_track[i].intensity <= 0.0f); +} + +// Draws a drag. + +void CParticule::TrackDraw(int i, ParticuleType type) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector corner[4], p1, p2, p, n, eye; + Math::Matrix matrix; + Math::Point texInf, texSup, rot; + float lTotal, f1, f2, a; + int counter, h; + + // Calculates the total length memorized. + lTotal = 0.0f; + h = m_track[i].head; + for ( counter=0 ; counterSetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + if ( type == PARTITRACK1 ) // explosion technique? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + if ( type == PARTITRACK2 ) // blue spray? + { + texInf.x = 64.5f/256.0f; + texInf.y = 13.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 14.0f/256.0f; // blue + } + if ( type == PARTITRACK3 ) // spider? + { + texInf.x = 64.5f/256.0f; + texInf.y = 5.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 6.0f/256.0f; // brown + } + if ( type == PARTITRACK4 ) // insect explosion? + { + texInf.x = 64.5f/256.0f; + texInf.y = 9.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 10.0f/256.0f; // dark green + } + if ( type == PARTITRACK5 ) // derrick? + { + texInf.x = 64.5f/256.0f; + texInf.y = 29.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 30.0f/256.0f; // dark brown + } + if ( type == PARTITRACK6 ) // reset in/out? + { + texInf.x = 64.5f/256.0f; + texInf.y = 17.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 18.0f/256.0f; // cyan + } + if ( type == PARTITRACK7 ) // win-1? + { + texInf.x = 64.5f/256.0f; + texInf.y = 41.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 42.0f/256.0f; // orange + } + if ( type == PARTITRACK8 ) // win-2? + { + texInf.x = 64.5f/256.0f; + texInf.y = 45.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 46.0f/256.0f; // yellow + } + if ( type == PARTITRACK9 ) // win-3? + { + texInf.x = 64.5f/256.0f; + texInf.y = 49.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 50.0f/256.0f; // red + } + if ( type == PARTITRACK10 ) // win-4? + { + texInf.x = 64.5f/256.0f; + texInf.y = 53.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 54.0f/256.0f; // violet + } + if ( type == PARTITRACK11 ) // phazer shot? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + if ( type == PARTITRACK12 ) // drag reactor? + { + texInf.x = 64.5f/256.0f; + texInf.y = 21.0f/256.0f; + texSup.x = 95.5f/256.0f; + texSup.y = 22.0f/256.0f; // orange + } + + h = m_track[i].head; + p1 = m_track[i].pos[h]; + f1 = m_track[i].intensity; + + eye = m_engine->RetEyePt(); + a = Math::RotateAngle(eye.x-p1.x, eye.z-p1.z); + + for ( counter=0 ; counterDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + if ( f2 < 0.0f ) break; + f1 = f2; + p1 = p2; + } +} + +// Draws a triangular particle. + +void CParticule::DrawParticuleTriangle(int i) +{ + CObject* object; + Math::Matrix matrix; + Math::Vector eye, pos, angle; + + if ( m_particule[i].zoom == 0.0f ) return; + + eye = m_engine->RetEyePt(); + pos = m_particule[i].pos; + + object = m_particule[i].objLink; + if ( object != 0 ) + { + pos += object->RetPosition(0); + } + + angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); + angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particule[i].angle; + + Math::LoadRotationXZYMatrix(matrix, angle); + matrix.Set(1, 4, pos.x); + matrix.Set(2, 4, pos.y); + matrix.Set(3, 4, pos.z); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2, + m_triangle[i].triangle, 3, NULL); + m_engine->AddStatisticTriangle(1); +} + +// Draw a normal particle. + +void CParticule::DrawParticuleNorm(int i) +{ + CObject* object; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Matrix matrix; + Math::Vector corner[4], eye, pos, n, angle; + Math::Point dim; + float zoom; + + zoom = m_particule[i].zoom; + if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f ) + { + zoom *= m_particule[i].intensity/0.5f; + } + + if ( zoom == 0.0f ) return; + if ( m_particule[i].intensity == 0.0f ) return; + + if ( m_particule[i].sheet == SH_INTERFACE ) + { + pos = m_particule[i].pos; + + n = Math::Vector(0.0f, 0.0f, -1.0f); + + dim.x = m_particule[i].dim.x * zoom; + dim.y = m_particule[i].dim.y * zoom; + + corner[0].x = pos.x+dim.x; + corner[0].y = pos.y+dim.y; + corner[0].z = 0.0f; + + corner[1].x = pos.x-dim.x; + corner[1].y = pos.y+dim.y; + corner[1].z = 0.0f; + + corner[2].x = pos.x+dim.x; + corner[2].y = pos.y-dim.y; + corner[2].z = 0.0f; + + corner[3].x = pos.x-dim.x; + corner[3].y = pos.y-dim.y; + corner[3].z = 0.0f; + + vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); + vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); + vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); + vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + } + else + { + eye = m_engine->RetEyePt(); + pos = m_particule[i].pos; + + object = m_particule[i].objLink; + if ( object != 0 ) + { + pos += object->RetPosition(0); + } + + angle.x = -Math::RotateAngle(Math::DistanceProjected(pos, eye), pos.y-eye.y); + angle.y = Math::RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particule[i].angle; + + Math::LoadRotationXZYMatrix(matrix, angle); + matrix.Set(1, 4, pos.x); + matrix.Set(2, 4, pos.y); + matrix.Set(3, 4, pos.z); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + n = Math::Vector(0.0f, 0.0f, -1.0f); + + dim.x = m_particule[i].dim.x * zoom; + dim.y = m_particule[i].dim.y * zoom; + + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); + vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); + vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); + vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + } +} + +// Draw a particle flat (horizontal). + +void CParticule::DrawParticuleFlat(int i) +{ + CObject* object; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Matrix matrix; + Math::Vector corner[4], pos, n, angle, eye; + Math::Point dim; + + if ( m_particule[i].zoom == 0.0f ) return; + if ( m_particule[i].intensity == 0.0f ) return; + + pos = m_particule[i].pos; + + object = m_particule[i].objLink; + if ( object != 0 ) + { + pos += object->RetPosition(0); + } + + angle.x = Math::PI/2.0f; + angle.y = 0.0f; + angle.z = m_particule[i].angle; + +#if 0 + if ( m_engine->RetRankView() == 1 ) // underwater? + { + angle.x = -Math::PI/2.0f; + pos.y -= 1.0f; + } +#else + if ( m_engine->RetRankView() == 1 ) // underwater? + { + pos.y -= 1.0f; + } + + eye = m_engine->RetEyePt(); + if ( pos.y > eye.y ) // seen from below? + { + angle.x = -Math::PI/2.0f; + } +#endif + + Math::LoadRotationXZYMatrix(matrix, angle); + matrix.Set(1, 4, pos.x); + matrix.Set(2, 4, pos.y); + matrix.Set(3, 4, pos.z); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + n = Math::Vector(0.0f, 0.0f, -1.0f); + + dim.x = m_particule[i].dim.x * m_particule[i].zoom; + dim.y = m_particule[i].dim.y * m_particule[i].zoom; + + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); + vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); + vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); + vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); +} + +// Draw a particle to a flat sheet of fog. + +void CParticule::DrawParticuleFog(int i) +{ + CObject* object; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Matrix matrix; + Math::Vector corner[4], pos, n, angle, eye; + Math::Point dim, zoom; + + if ( !m_engine->RetFog() ) return; + if ( m_particule[i].intensity == 0.0f ) return; + + pos = m_particule[i].pos; + + dim.x = m_particule[i].dim.x; + dim.y = m_particule[i].dim.y; + + if ( m_particule[i].type == PARTIFOG0 || + m_particule[i].type == PARTIFOG2 || + m_particule[i].type == PARTIFOG4 || + m_particule[i].type == PARTIFOG6 ) + { +//? pos.x += sinf(m_particule[i].zoom*1.2f)*dim.x*0.1f; +//? pos.y += cosf(m_particule[i].zoom*1.5f)*dim.y*0.1f; + zoom.x = 1.0f+sinf(m_particule[i].zoom*2.0f)/6.0f; + zoom.y = 1.0f+cosf(m_particule[i].zoom*2.7f)/6.0f; + } + if ( m_particule[i].type == PARTIFOG1 || + m_particule[i].type == PARTIFOG3 || + m_particule[i].type == PARTIFOG5 || + m_particule[i].type == PARTIFOG7 ) + { +//? pos.x += sinf(m_particule[i].zoom*1.0f)*dim.x*0.1f; +//? pos.y += cosf(m_particule[i].zoom*1.3f)*dim.y*0.1f; + zoom.x = 1.0f+sinf(m_particule[i].zoom*3.0f)/6.0f; + zoom.y = 1.0f+cosf(m_particule[i].zoom*3.7f)/6.0f; + } + + dim.x *= zoom.x; + dim.y *= zoom.y; + + object = m_particule[i].objLink; + if ( object != 0 ) + { + pos += object->RetPosition(0); + } + + angle.x = Math::PI/2.0f; + angle.y = 0.0f; + angle.z = m_particule[i].angle; + + if ( m_engine->RetRankView() == 1 ) // underwater? + { + pos.y -= 1.0f; + } + + eye = m_engine->RetEyePt(); + if ( pos.y > eye.y ) // seen from below? + { + angle.x = -Math::PI/2.0f; + } + + Math::LoadRotationXZYMatrix(matrix, angle); + matrix.Set(1, 4, pos.x); + matrix.Set(2, 4, pos.y); + matrix.Set(3, 4, pos.z); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + n = Math::Vector(0.0f, 0.0f, -1.0f); + + corner[0].x = dim.x; + corner[0].y = dim.y; + corner[0].z = 0.0f; + + corner[1].x = -dim.x; + corner[1].y = dim.y; + corner[1].z = 0.0f; + + corner[2].x = dim.x; + corner[2].y = -dim.y; + corner[2].z = 0.0f; + + corner[3].x = -dim.x; + corner[3].y = -dim.y; + corner[3].z = 0.0f; + + vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y); + vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y); + vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y); + vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); +} + +// Draw a particle in the form of radius. + +void CParticule::DrawParticuleRay(int i) +{ + CObject* object; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Matrix matrix; + Math::Vector corner[4], eye, pos, goal, n, angle, proj; + Math::Point dim, texInf, texSup; + bool bLeft; + float a, len, adv, prop, vario1, vario2; + int r, rank, step, first, last; + + if ( m_particule[i].zoom == 0.0f ) return; + if ( m_particule[i].intensity == 0.0f ) return; + + eye = m_engine->RetEyePt(); + pos = m_particule[i].pos; + goal = m_particule[i].goal; + + object = m_particule[i].objLink; + if ( object != 0 ) + { + pos += object->RetPosition(0); + } + + a = Math::RotateAngle(Math::Point(pos.x,pos.z), Math::Point(goal.x,goal.z), Math::Point(eye.x,eye.z)); + bLeft = (a < Math::PI); + + proj = Math::Projection(pos, goal, eye); + angle.x = -Math::RotateAngle(Math::DistanceProjected(proj, eye), proj.y-eye.y); + angle.y = Math::RotateAngle(pos.z-goal.z, pos.x-goal.x)+Math::PI/2.0f; + angle.z = -Math::RotateAngle(Math::DistanceProjected(pos, goal), pos.y-goal.y); + if ( bLeft ) angle.x = -angle.x; + + Math::LoadRotationZXYMatrix(matrix, angle); + matrix.Set(1, 4, pos.x); + matrix.Set(2, 4, pos.y); + matrix.Set(3, 4, pos.z); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + n = Math::Vector(0.0f, 0.0f, bLeft?1.0f:-1.0f); + + dim.x = m_particule[i].dim.x * m_particule[i].zoom; + dim.y = m_particule[i].dim.y * m_particule[i].zoom; + + if ( bLeft ) dim.y = -dim.y; + + len = Math::Distance(pos, goal); + adv = 0.0f; + + step = (int)(len/(dim.x*2.0f))+1; + + if ( step == 1 ) + { + vario1 = 1.0f; + vario2 = 1.0f; + } + else + { + vario1 = 0.0f; + vario2 = 2.0f; + } + + if ( m_particule[i].type == PARTIRAY2 ) + { + first = 0; + last = step; + vario1 = 0.0f; + vario2 = 0.0f; + } + else if ( m_particule[i].type == PARTIRAY3 ) + { + if ( m_particule[i].time < m_particule[i].duration*0.40f ) + { + prop = m_particule[i].time / (m_particule[i].duration*0.40f); + first = 0; + last = (int)(prop*step); + } + else if ( m_particule[i].time < m_particule[i].duration*0.60f ) + { + first = 0; + last = step; + } + else + { + prop = (m_particule[i].time-m_particule[i].duration*0.60f) / (m_particule[i].duration*0.40f); + first = (int)(prop*step); + last = step; + } + } + else + { + if ( m_particule[i].time < m_particule[i].duration*0.50f ) + { + prop = m_particule[i].time / (m_particule[i].duration*0.50f); + first = 0; + last = (int)(prop*step); + } + else if ( m_particule[i].time < m_particule[i].duration*0.75f ) + { + first = 0; + last = step; + } + else + { + prop = (m_particule[i].time-m_particule[i].duration*0.75f) / (m_particule[i].duration*0.25f); + first = (int)(prop*step); + last = step; + } + } + + corner[0].x = adv; + corner[2].x = adv; + corner[0].y = dim.y; + corner[2].y = -dim.y; + corner[0].z = (Math::Rand()-0.5f)*vario1; + corner[1].z = (Math::Rand()-0.5f)*vario1; + corner[2].z = (Math::Rand()-0.5f)*vario1; + corner[3].z = (Math::Rand()-0.5f)*vario1; + + for ( rank=0 ; rank= first && rank <= last ) + { +#if 1 + texInf = m_particule[i].texInf; + texSup = m_particule[i].texSup; + + r = rand()%16; + texInf.x += 0.25f*(r/4); + texSup.x += 0.25f*(r/4); + if ( r%2 < 1 && adv > 0.0f && m_particule[i].type != PARTIRAY1 ) + { + Math::Swap(texInf.x, texSup.x); + } + if ( r%4 < 2 ) + { + Math::Swap(texInf.y, texSup.y); + } +#else + texInf.x = Math::Mod(texInf.x+0.25f, 1.0f); + texSup.x = Math::Mod(texSup.x+0.25f, 1.0f); +#endif + + vertex[0] = D3DVERTEX2(corner[1], n, texSup.x, texSup.y); + vertex[1] = D3DVERTEX2(corner[0], n, texInf.x, texSup.y); + vertex[2] = D3DVERTEX2(corner[3], n, texSup.x, texInf.y); + vertex[3] = D3DVERTEX2(corner[2], n, texInf.x, texInf.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + } + adv += dim.x*2.0f; + } +} + +// Draws a spherical particle. + +void CParticule::DrawParticuleSphere(int i) +{ + D3DVERTEX2 vertex[2*16*(16+1)]; // triangles + Math::Matrix matrix, rot; + Math::Vector angle, v0, v1; + Math::Point ts, ti; + float zoom, deltaRingAngle, deltaSegAngle; + float r0,r1, tu0,tv0, tu1,tv1; + int j, ring, seg, numRings, numSegments; + + zoom = m_particule[i].zoom; +#if 0 + if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f ) + { + zoom *= m_particule[i].intensity/0.5f; + } +#endif + + if ( zoom == 0.0f ) return; + + m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity)); + + matrix.LoadIdentity(); + matrix.Set(1, 1, zoom); + matrix.Set(2, 2, zoom); + matrix.Set(3, 3, zoom); + matrix.Set(1, 4, m_particule[i].pos.x); + matrix.Set(2, 4, m_particule[i].pos.y); + matrix.Set(3, 4, m_particule[i].pos.z); + + if ( m_particule[i].angle != 0.0f ) + { + angle.x = m_particule[i].angle*0.4f; + angle.y = m_particule[i].angle*1.0f; + angle.z = m_particule[i].angle*0.7f; + Math::LoadRotationZXYMatrix(rot, angle); + matrix = Math::MultiplyMatrices(rot, matrix); + } + + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + ts.x = m_particule[i].texSup.x; + ts.y = m_particule[i].texSup.y; + ti.x = m_particule[i].texInf.x; + ti.y = m_particule[i].texInf.y; + + // Choose a tesselation level. + if ( m_particule[i].type == PARTISPHERE3 || + m_particule[i].type == PARTISPHERE5 ) + { + numRings = 16; + numSegments = 16; + } + else + { + numRings = 8; + numSegments = 10; + } + + // Establish constants used in sphere generation. + deltaRingAngle = Math::PI/numRings; + deltaSegAngle = 2.0f*Math::PI/numSegments; + + // Generate the group of rings for the sphere. + j = 0; + for ( ring=0 ; ringDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL); + m_engine->AddStatisticTriangle(j); + + m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity)); +} + +// Returns the height depending on the progress. + +float ProgressCylinder(float progress) +{ + if ( progress < 0.5f ) + { + return 1.0f - (powf(1.0f-progress*2.0f, 2.0f)); + } + else + { + return 1.0f - (powf(progress*2.0f-1.0f, 2.0f)); + } +} + +// Draws a cylindrical particle. + +void CParticule::DrawParticuleCylinder(int i) +{ + D3DVERTEX2 vertex[2*5*(10+1)]; // triangles + Math::Matrix matrix, rot; + Math::Vector angle, v0, v1; + Math::Point ts, ti; + float progress, zoom, diam, deltaSegAngle, h[6], d[6]; + float r0,r1, tu0,tv0, tu1,tv1, p1, p2, pp; + int j, ring, seg, numRings, numSegments; + + progress = m_particule[i].zoom; + zoom = m_particule[i].dim.x; + diam = m_particule[i].dim.y; + if ( progress >= 1.0f || zoom == 0.0f ) return; + + m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity)); + + matrix.LoadIdentity(); + matrix.Set(1, 1, zoom); + matrix.Set(2, 2, zoom); + matrix.Set(3, 3, zoom); + matrix.Set(1, 4, m_particule[i].pos.x); + matrix.Set(2, 4, m_particule[i].pos.y); + matrix.Set(3, 4, m_particule[i].pos.z); + + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + ts.x = m_particule[i].texSup.x; + ts.y = m_particule[i].texSup.y; + ti.x = m_particule[i].texInf.x; + ti.y = m_particule[i].texInf.y; + + numRings = 5; + numSegments = 10; + deltaSegAngle = 2.0f*Math::PI/numSegments; + + if ( m_particule[i].type == PARTIPLOUF0 ) + { +#if 0 + if ( progress <= 0.5f ) + { + p1 = progress/0.5f; // front + p2 = 0.0f; // back + } + else + { + p1 = 1.0f; // front + p2 = (progress-0.5f)/0.5f; // back + ts.y += (ti.y-ts.y)*p2; + } +#else + p1 = progress; // front + p2 = powf(progress, 5.0f); // back +#endif + + for ( ring=0 ; ring<=numRings ; ring++ ) + { + pp = p2+(p1-p2)*((float)ring/numRings); + d[ring] = diam/zoom+pp*2.0f; + h[ring] = ProgressCylinder(pp); + } + } + + j = 0; + for ( ring=0 ; ringDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL); + m_engine->AddStatisticTriangle(j); + + m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity)); +} + +// Draws a tire mark. + +void CParticule::DrawParticuleWheel(int i) +{ + Math::Vector pos[4], center; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector n; + Math::Point ts, ti; + float dist, dp; + + dist = Math::DistanceProjected(m_engine->RetEyePt(), m_wheelTrace[i].pos[0]); + if ( dist > 300.0f ) return; + + pos[0] = m_wheelTrace[i].pos[0]; + pos[1] = m_wheelTrace[i].pos[1]; + pos[2] = m_wheelTrace[i].pos[2]; + pos[3] = m_wheelTrace[i].pos[3]; + + if ( m_wheelTrace[i].type == PARTITRACE0 ) // white ground track? + { + ts.x = 8.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE1 ) // black ground track? + { + ts.x = 0.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE2 ) // gray ground track? + { + ts.x = 0.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE3 ) // light gray ground track? + { + ts.x = 8.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE4 ) // red ground track? + { + ts.x = 32.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE5 ) // pink ground track? + { + ts.x = 40.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE6 ) // violet ground track? + { + ts.x = 32.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE7 ) // orange ground track? + { + ts.x = 40.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE8 ) // yellow ground track? + { + ts.x = 16.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE9 ) // beige ground track? + { + ts.x = 24.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE10 ) // brown ground track? + { + ts.x = 16.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE11 ) // skin ground track? + { + ts.x = 24.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE12 ) // green ground track? + { + ts.x = 48.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE13 ) // light green ground track? + { + ts.x = 56.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE14 ) // blue ground track? + { + ts.x = 48.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE15 ) // light blue ground track? + { + ts.x = 56.0f/256.0f; + ts.y = 232.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE16 ) // black arrow ground track? + { + ts.x = 160.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else if ( m_wheelTrace[i].type == PARTITRACE17 ) // red arrow ground track? + { + ts.x = 176.0f/256.0f; + ts.y = 224.0f/256.0f; + } + else + { + return; + } + + if ( m_wheelTrace[i].type == PARTITRACE16 || + m_wheelTrace[i].type == PARTITRACE17 ) + { + ti.x = ts.x+16.0f/256.0f; + ti.y = ts.y+16.0f/256.0f; + } + else + { + ti.x = ts.x+8.0f/256.0f; + ti.y = ts.y+8.0f/256.0f; + } + + dp = (1.0f/256.0f)/2.0f; + ts.x = ts.x+dp; + ts.y = ts.y+dp; + ti.x = ti.x-dp; + ti.y = ti.y-dp; + + n = Math::Vector(0.0f, 1.0f, 0.0f); + + vertex[0] = D3DVERTEX2(pos[0], n, ts.x, ts.y); + vertex[1] = D3DVERTEX2(pos[1], n, ti.x, ts.y); + vertex[2] = D3DVERTEX2(pos[2], n, ts.x, ti.y); + vertex[3] = D3DVERTEX2(pos[3], n, ti.x, ti.y); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); +} + +// Draws all the particles. + +void CParticule::DrawParticule(int sheet) +{ + D3DMATERIAL7 mat; + Math::Matrix matrix; + bool bLoadTexture; + char name[20]; + int state, t, i, j, r; + + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, true); +//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + + // Draw the basic particles of triangles. + if ( m_totalInterface[0][sheet] > 0 ) + { + for ( i=0 ; iSetTexture(m_triangle[i].texName1); + m_engine->SetMaterial(m_triangle[i].material); + m_engine->SetState(m_triangle[i].state); + DrawParticuleTriangle(i); + } + } + + // Draw the particles was calculated based on edge. + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + + ZeroMemory( &mat, sizeof(D3DMATERIAL7) ); + mat.diffuse.r = 1.0f; + mat.diffuse.g = 1.0f; + mat.diffuse.b = 1.0f; // white + mat.ambient.r = 0.5f; + mat.ambient.g = 0.5f; + mat.ambient.b = 0.5f; + m_engine->SetMaterial(mat); + + // Draw tire marks. + if ( m_wheelTraceTotal > 0 && sheet == SH_WORLD ) + { +#if _POLISH + m_engine->SetTexture("textp.tga"); +#else + m_engine->SetTexture("text.tga"); +#endif + m_engine->SetState(D3DSTATETTw); +//? m_engine->SetState(D3DSTATENORMAL); + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + for ( i=0 ; i=1 ; t-- ) // black behind! + { + if ( m_totalInterface[t][sheet] == 0 ) continue; + + bLoadTexture = false; + + if ( t == 4 ) state = D3DSTATETTw; // text.tga + else state = D3DSTATETTb; // effect[00..02].tga + m_engine->SetState(state); + + for ( j=0 ; jSetTexture(name); + bLoadTexture = true; + } + + r = m_particule[i].trackRank; + if ( r != -1 ) + { + m_engine->SetState(state); + TrackDraw(r, m_particule[i].type); // draws the drag + if ( !m_track[r].bDrawParticule ) continue; + } + + m_engine->SetState(state, RetColor(m_particule[i].intensity)); + + if ( m_particule[i].bRay ) // ray? + { + DrawParticuleRay(i); + } + else if ( m_particule[i].type == PARTIFLIC || // circle in the water? + m_particule[i].type == PARTISHOW || + m_particule[i].type == PARTICHOC || + m_particule[i].type == PARTIGFLAT ) + { + DrawParticuleFlat(i); + } + else if ( m_particule[i].type >= PARTIFOG0 && + m_particule[i].type <= PARTIFOG9 ) + { + DrawParticuleFog(i); + } + else if ( m_particule[i].type >= PARTISPHERE0 && + m_particule[i].type <= PARTISPHERE9 ) // sphere? + { + DrawParticuleSphere(i); + } + else if ( m_particule[i].type >= PARTIPLOUF0 && + m_particule[i].type <= PARTIPLOUF4 ) // cylinder? + { + DrawParticuleCylinder(i); + } + else // normal? + { + DrawParticuleNorm(i); + } + } + } + +//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, true); + m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true); +} + + +// Seeks if an object collided with a bullet. + +CObject* CParticule::SearchObjectGun(Math::Vector old, Math::Vector pos, + ParticuleType type, CObject *father) +{ + CObject *pObj, *pBest; + Math::Vector box1, box2, oPos, p; + ObjectType oType; + bool bShield; + float min, oRadius, dist, shieldRadius; + int i, j; + bool bHimself; + + if ( m_main->RetMovieLock() ) return 0; // current movie? + + bHimself = m_main->RetHimselfDamage(); + + min = 5.0f; + if ( type == PARTIGUN2 ) min = 2.0f; // shooting insect? + if ( type == PARTIGUN3 ) min = 3.0f; // suiciding spider? + + box1 = old; + box2 = pos; + if ( box1.x > box2.x ) Math::Swap(box1.x, box2.x); // box1 < box2 + if ( box1.y > box2.y ) Math::Swap(box1.y, box2.y); + if ( box1.z > box2.z ) Math::Swap(box1.z, box2.z); + box1.x -= min; + box1.y -= min; + box1.z -= min; + box2.x += min; + box2.y += min; + box2.z += min; + + pBest = 0; + bShield = false; + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( !pObj->RetActif() ) continue; // inactive? + if ( pObj == father ) continue; + + oType = pObj->RetType(); + + if ( oType == OBJECT_TOTO ) continue; + + if ( type == PARTIGUN1 ) // fireball shooting? + { + if ( oType == OBJECT_MOTHER ) continue; + if ( bHimself ) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if ( !IsAlien(oType) ) continue; + } + } + else if ( type == PARTIGUN2 ) // shooting insect? + { + if ( !IsSoft(oType) ) continue; + } + else if ( type == PARTIGUN3 ) // suiciding spider? + { + if ( !IsSoft(oType) ) continue; + } + else if ( type == PARTIGUN4 ) // orgaball shooting? + { + if ( oType == OBJECT_MOTHER ) continue; + if ( bHimself ) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if ( !IsAlien(oType) ) continue; + } + } + else if ( type == PARTITRACK11 ) // phazer shooting? + { + if ( bHimself ) // damage is oneself? + { + if ( !IsAlien(oType) && + !IsSoft(oType) ) continue; + } + else // damage only to enemies? + { + if ( !IsAlien(oType) ) continue; + } + } + else + { + continue; + } + + oPos = pObj->RetPosition(0); + + if ( type == PARTIGUN2 || // shooting insect? + type == PARTIGUN3 ) // suiciding spider? + { + // Test if the ball is entered into the sphere of a shield. + shieldRadius = pObj->RetShieldRadius(); + if ( shieldRadius > 0.0f ) + { + dist = Math::Distance(oPos, pos); + if ( dist <= shieldRadius ) + { + pBest = pObj; + bShield = true; + } + } + } + if ( bShield ) continue; + + // Test the center of the object, which is necessary for objects + // that have no sphere in the center (station). + dist = Math::Distance(oPos, pos)-4.0f; + if ( dist < min ) + { + pBest = pObj; + } + + // Test with all spheres of the object. + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + if ( oPos.x+oRadius < box1.x || oPos.x-oRadius > box2.x || // outside the box? + oPos.y+oRadius < box1.y || oPos.y-oRadius > box2.y || + oPos.z+oRadius < box1.z || oPos.z-oRadius > box2.z ) continue; + + p = Math::Projection(old, pos, oPos); + dist = Math::Distance(p, oPos)-oRadius; + if ( dist < min ) + { + pBest = pObj; + } + } + } + + return pBest; +} + +// Seeks if an object collided with a ray. + +CObject* CParticule::SearchObjectRay(Math::Vector pos, Math::Vector goal, + ParticuleType type, CObject *father) +{ + CObject* pObj; + Math::Vector box1, box2, oPos, p; + ObjectType oType; + float min, dist; + int i; + + if ( m_main->RetMovieLock() ) return 0; // current movie? + + min = 10.0f; + + box1 = pos; + box2 = goal; + if ( box1.x > box2.x ) Math::Swap(box1.x, box2.x); // box1 < box2 + if ( box1.y > box2.y ) Math::Swap(box1.y, box2.y); + if ( box1.z > box2.z ) Math::Swap(box1.z, box2.z); + box1.x -= min; + box1.y -= min; + box1.z -= min; + box2.x += min; + box2.y += min; + box2.z += min; + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + if ( !pObj->RetActif() ) continue; // inactive? + if ( pObj == father ) continue; + + oType = pObj->RetType(); + + if ( oType == OBJECT_TOTO ) continue; + + if ( type == PARTIRAY1 && + oType != OBJECT_MOBILEtg && + oType != OBJECT_TEEN28 && + oType != OBJECT_TEEN31 && + oType != OBJECT_ANT && + oType != OBJECT_SPIDER && + oType != OBJECT_BEE && + oType != OBJECT_WORM && + oType != OBJECT_MOTHER && + oType != OBJECT_NEST ) continue; + + oPos = pObj->RetPosition(0); + + if ( oPos.x < box1.x || oPos.x > box2.x || // outside the box? + oPos.y < box1.y || oPos.y > box2.y || + oPos.z < box1.z || oPos.z > box2.z ) continue; + + p = Math::Projection(pos, goal, oPos); + dist = Math::Distance(p, oPos); + if ( dist < min ) return pObj; + } + + return 0; +} + + +// Sounded one. + +void CParticule::Play(Sound sound, Math::Vector pos, float amplitude) +{ + if ( m_sound == 0 ) + { + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + } + + m_sound->Play(sound, pos, amplitude); +} + + + +// Seeks the color if you're in the fog. +// Returns black if you're not in the fog. + +D3DCOLORVALUE CParticule::RetFogColor(Math::Vector pos) +{ + D3DCOLORVALUE result, color; + float dist, factor; + int fog, i; + + result.r = 0.0f; + result.g = 0.0f; + result.b = 0.0f; + result.a = 0.0f; + + for ( fog=0 ; fog= m_particule[i].pos.y+FOG_HSUP ) continue; + if ( pos.y <= m_particule[i].pos.y-FOG_HINF ) continue; + + dist = Math::DistanceProjected(pos, m_particule[i].pos); + if ( dist >= m_particule[i].dim.x*1.5f ) continue; + + // Calculates the horizontal distance. + factor = 1.0f-powf(dist/(m_particule[i].dim.x*1.5f), 4.0f); + + // Calculates the vertical distance. + if ( pos.y > m_particule[i].pos.y ) + { + factor *= 1.0f-(pos.y-m_particule[i].pos.y)/FOG_HSUP; + } + else + { + factor *= 1.0f-(m_particule[i].pos.y-pos.y)/FOG_HINF; + } + + factor *= 0.3f; + + if ( m_particule[i].type == PARTIFOG0 || + m_particule[i].type == PARTIFOG1 ) // blue? + { + color.r = 0.0f; + color.g = 0.5f; + color.b = 1.0f; + } + else if ( m_particule[i].type == PARTIFOG2 || + m_particule[i].type == PARTIFOG3 ) // red? + { + color.r = 2.0f; + color.g = 1.0f; + color.b = 0.0f; + } + else if ( m_particule[i].type == PARTIFOG4 || + m_particule[i].type == PARTIFOG5 ) // white? + { + color.r = 1.0f; + color.g = 1.0f; + color.b = 1.0f; + } + else if ( m_particule[i].type == PARTIFOG6 || + m_particule[i].type == PARTIFOG7 ) // yellow? + { + color.r = 0.8f; + color.g = 1.0f; + color.b = 0.4f; + } + else + { + color.r = 0.0f; + color.g = 0.0f; + color.b = 0.0f; + } + + result.r += color.r*factor; + result.g += color.g*factor; + result.b += color.b*factor; + } + + if ( result.r > 0.6f ) result.r = 0.6f; + if ( result.g > 0.6f ) result.g = 0.6f; + if ( result.b > 0.6f ) result.b = 0.6f; + + return result; +} + + +// Writes a file. BMP containing all the tire tracks. + +bool CParticule::WriteWheelTrace(char *filename, int width, int height, + Math::Vector dl, Math::Vector ur) +{ + HDC hDC; + HDC hDCImage; + HBITMAP hb; + PBITMAPINFO info; + HBRUSH hBrush; + HPEN hPen; + HGDIOBJ old; + RECT rect; + COLORREF color; + Math::Point pos[4]; + POINT list[4]; + int i; + + if ( !m_engine->GetRenderDC(hDC) ) return false; + + hDCImage = CreateCompatibleDC(hDC); + if ( hDCImage == 0 ) + { + m_engine->ReleaseRenderDC(hDC); + return false; + } + + hb = CreateCompatibleBitmap(hDC, width, height); + if ( hb == 0 ) + { + DeleteDC(hDCImage); + m_engine->ReleaseRenderDC(hDC); + return false; + } + + SelectObject(hDCImage, hb); + + rect.left = 0; + rect.right = width; + rect.top = 0; + rect.bottom = height; + FillRect(hDCImage, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); + + hPen = CreatePen(PS_NULL, 1, 0); + SelectObject(hDCImage, hPen); + + for ( i=0 ; iCreateBitmapInfoStruct(hb); + if ( info == 0 ) + { + DeleteObject(hb); + DeleteDC(hDCImage); + m_engine->ReleaseRenderDC(hDC); + return false; + } + + m_engine->CreateBMPFile(filename, info, hb, hDCImage); + + DeleteObject(hb); + DeleteDC(hDCImage); + m_engine->ReleaseRenderDC(hDC); + return true; +} + diff --git a/src/old/particule.h b/src/old/particule.h index 23d0899..23c9838 100644 --- a/src/old/particule.h +++ b/src/old/particule.h @@ -1,337 +1,337 @@ -// * 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/. - -// particule.h - -#pragma once - - -#include "math/point.h" -#include "old/d3dengine.h" -#include "old/sound.h" - - -class CInstanceManager; -class CRobotMain; -class CTerrain; -class CWater; -class CObject; - - -const int MAXPARTICULE = 500; -const int MAXPARTITYPE = 5; -const int MAXTRACK = 100; -const int MAXTRACKLEN = 10; -const int MAXPARTIFOG = 100; -const int MAXWHEELTRACE = 1000; - -enum ParticulePlace -{ - SH_WORLD = 0, // particle in the world in the interface - SH_FRONT = 1, // particle in the world on the interface - SH_INTERFACE = 2, // particle in the interface - SH_MAX = 3 -}; - -// type == 0 -> triangles -// type == 1 -> effect00 (black background) -// type == 2 -> effect01 (black background) -// type == 3 -> effect02 (black background) -// type == 4 -> text (white background) - - -enum ParticuleType -{ - PARTIEXPLOT = 1, // technology explosion - PARTIEXPLOO = 2, // organic explosion - PARTIMOTOR = 3, // the engine exhaust gas - PARTIGLINT = 4, // reflection - PARTIBLITZ = 5, // lightning recharging battery - PARTICRASH = 6, // dust after fall - PARTIGAS = 7, // gas from the reactor - PARTIFIRE = 9, // fireball shrinks - PARTIFIREZ = 10, // fireball grows - PARTIBLUE = 11, // blue ball - PARTISELY = 12, // yellow selection - PARTISELR = 13, // red selection - PARTIGUN1 = 18, // a bullet (fireball) - PARTIGUN2 = 19, // bullet 2 (ant) - PARTIGUN3 = 20, // bullet 3 (spider) - PARTIGUN4 = 21, // bullet 4 (orgaball) - PARTIFRAG = 22, // triangular fragment - PARTIQUEUE = 23, // inflamed tail - PARTIORGANIC1 = 24, // organic ball mother - PARTIORGANIC2 = 25, // organic ball daughter - PARTISMOKE1 = 26, // black smoke - PARTISMOKE2 = 27, // black smoke - PARTISMOKE3 = 28, // black smoke - PARTISMOKE4 = 29, // black smoke - PARTIBLOOD = 30, // human blood - PARTIBLOODM = 31, // blood laying - PARTIVAPOR = 32, // steam - PARTIVIRUS1 = 33, // virus 1 - PARTIVIRUS2 = 34, // virus 2 - PARTIVIRUS3 = 35, // virus 3 - PARTIVIRUS4 = 36, // virus 4 - PARTIVIRUS5 = 37, // virus 5 - PARTIVIRUS6 = 38, // virus 6 - PARTIVIRUS7 = 39, // virus 7 - PARTIVIRUS8 = 40, // virus 8 - PARTIVIRUS9 = 41, // virus 9 - PARTIVIRUS10 = 42, // virus 10 - PARTIRAY1 = 43, // ray 1 (turn) - PARTIRAY2 = 44, // ray 2 (electric arc) - PARTIRAY3 = 45, // ray 3 - PARTIRAY4 = 46, // ray 4 - PARTIFLAME = 47, // flame - PARTIBUBBLE = 48, // bubble - PARTIFLIC = 49, // circles in the water - PARTIEJECT = 50, // ejection from the reactor - PARTISCRAPS = 51, // waste from the reactor - PARTITOTO = 52, // reactor of tot - PARTIERROR = 53, // toto says no - PARTIWARNING = 54, // foo says blah - PARTIINFO = 54, // toto says yes - PARTIQUARTZ = 55, // reflection crystal - PARTISPHERE0 = 56, // explosion sphere - PARTISPHERE1 = 57, // energy sphere - PARTISPHERE2 = 58, // analysis sphere - PARTISPHERE3 = 59, // shield sphere - PARTISPHERE4 = 60, // information sphere (emit) - PARTISPHERE5 = 61, // botanical sphere (gravity root) - PARTISPHERE6 = 62, // information sphere (receive) - PARTISPHERE7 = 63, // sphere - PARTISPHERE8 = 64, // sphere - PARTISPHERE9 = 65, // sphere - PARTIGUNDEL = 66, // bullet destroyed by shield - PARTIPART = 67, // object part - PARTITRACK1 = 68, // drag 1 - PARTITRACK2 = 69, // drag 2 - PARTITRACK3 = 70, // drag 3 - PARTITRACK4 = 71, // drag 4 - PARTITRACK5 = 72, // drag 5 - PARTITRACK6 = 73, // drag 6 - PARTITRACK7 = 74, // drag 7 - PARTITRACK8 = 75, // drag 8 - PARTITRACK9 = 76, // drag 9 - PARTITRACK10 = 77, // drag 10 - PARTITRACK11 = 78, // drag 11 - PARTITRACK12 = 79, // drag 12 - PARTITRACK13 = 80, // drag 13 - PARTITRACK14 = 81, // drag 14 - PARTITRACK15 = 82, // drag 15 - PARTITRACK16 = 83, // drag 16 - PARTITRACK17 = 84, // drag 17 - PARTITRACK18 = 85, // drag 18 - PARTITRACK19 = 86, // drag 19 - PARTITRACK20 = 87, // drag 20 - PARTIGLINTb = 88, // blue reflection - PARTIGLINTr = 89, // red reflection - PARTILENS1 = 90, // brilliance 1 (orange) - PARTILENS2 = 91, // brilliance 2 (yellow) - PARTILENS3 = 92, // brilliance 3 (red) - PARTILENS4 = 93, // brilliance 4 (violet) - PARTICONTROL = 94, // reflection on button - PARTISHOW = 95, // shows a place - PARTICHOC = 96, // shock wave - PARTIGFLAT = 97, // shows if the ground is flat - PARTIRECOVER = 98, // blue ball recycler - PARTIROOT = 100, // gravity root smoke - PARTIPLOUF0 = 101, // splash - PARTIPLOUF1 = 102, // splash - PARTIPLOUF2 = 103, // splash - PARTIPLOUF3 = 104, // splash - PARTIPLOUF4 = 105, // splash - PARTIDROP = 106, // drop - PARTIFOG0 = 107, // fog 0 - PARTIFOG1 = 108, // fog 1 - PARTIFOG2 = 109, // fog 2 - PARTIFOG3 = 110, // fog 3 - PARTIFOG4 = 111, // fog 4 - PARTIFOG5 = 112, // fog 5 - PARTIFOG6 = 113, // fog 6 - PARTIFOG7 = 114, // fog 7 - PARTIFOG8 = 115, // fog 8 - PARTIFOG9 = 116, // fog 9 - PARTILIMIT1 = 117, // shows the limits 1 - PARTILIMIT2 = 118, // shows the limits 2 - PARTILIMIT3 = 119, // shows the limits 3 - PARTILIMIT4 = 120, // shows the limits 4 - PARTIWATER = 121, // drop of water - PARTIEXPLOG1 = 122, // ball explosion 1 - PARTIEXPLOG2 = 123, // ball explosion 2 - PARTIBASE = 124, // gases of spaceship - PARTITRACE0 = 140, // trace - PARTITRACE1 = 141, // trace - PARTITRACE2 = 142, // trace - PARTITRACE3 = 143, // trace - PARTITRACE4 = 144, // trace - PARTITRACE5 = 145, // trace - PARTITRACE6 = 146, // trace - PARTITRACE7 = 147, // trace - PARTITRACE8 = 148, // trace - PARTITRACE9 = 149, // trace - PARTITRACE10 = 150, // trace - PARTITRACE11 = 151, // trace - PARTITRACE12 = 152, // trace - PARTITRACE13 = 153, // trace - PARTITRACE14 = 154, // trace - PARTITRACE15 = 155, // trace - PARTITRACE16 = 156, // trace - PARTITRACE17 = 157, // trace - PARTITRACE18 = 158, // trace - PARTITRACE19 = 159, // trace -}; - -enum ParticulePhase -{ - PARPHSTART = 0, - PARPHEND = 1, -}; - -struct Particule -{ - char bUsed; // true -> particle used - char bRay; // true -> ray with goal - unsigned short uniqueStamp; // unique mark - short sheet; // sheet (0..n) - ParticuleType type; // type PARTI* - ParticulePhase phase; // phase PARPH* - float mass; // mass of the particle (in rebounding) - float weight; // weight of the particle (for noise) - float duration; // length of life - Math::Vector pos; // absolute position (relative if object links) - Math::Vector goal; // goal position (if bRay) - Math::Vector speed; // speed of displacement - float windSensitivity; - short bounce; // number of rebounds - Math::Point dim; // dimensions of the rectangle - float zoom; // zoom (0..1) - float angle; // angle of rotation - float intensity; // intensity - Math::Point texSup; // coordinated upper texture - Math::Point texInf; // coordinated lower texture - float time; // age of the particle (0..n) - float phaseTime; // age at the beginning of phase - float testTime; // time since last test - CObject* objLink; // father object (for example reactor) - CObject* objFather; // father object (for example reactor) - short objRank; // rank of the object, or -1 - short trackRank; // rank of the drag -}; - -struct Track -{ - char bUsed; // true -> drag used - char bDrawParticule; - float step; // duration of not - float last; // increase last not memorized - float intensity; // intensity at starting (0..1) - float width; // tail width - int used; // number of positions in "pos" - int head; // head to write index - Math::Vector pos[MAXTRACKLEN]; - float len[MAXTRACKLEN]; -}; - -struct WheelTrace -{ - ParticuleType type; // type PARTI* - Math::Vector pos[4]; // rectangle positions - float startTime; // beginning of life -}; - - - -class CParticule -{ -public: - CParticule(CInstanceManager* iMan, CD3DEngine* engine); - ~CParticule(); - - void SetD3DDevice(LPDIRECT3DDEVICE7 device); - - void FlushParticule(); - void FlushParticule(int sheet); - int CreateParticule(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreateFrag(Math::Vector pos, Math::Vector speed, D3DTriangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreatePart(Math::Vector pos, Math::Vector speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0); - int CreateRay(Math::Vector pos, Math::Vector goal, ParticuleType type, Math::Point dim, float duration=1.0f, int sheet=0); - int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); - void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticuleType type); - void DeleteParticule(ParticuleType type); - void DeleteParticule(int channel); - void SetObjectLink(int channel, CObject *object); - void SetObjectFather(int channel, CObject *object); - void SetPosition(int channel, Math::Vector pos); - void SetDimension(int channel, Math::Point dim); - void SetZoom(int channel, float zoom); - void SetAngle(int channel, float angle); - void SetIntensity(int channel, float intensity); - void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity); - void SetPhase(int channel, ParticulePhase phase, float duration); - bool GetPosition(int channel, Math::Vector &pos); - - D3DCOLORVALUE RetFogColor(Math::Vector pos); - - void SetFrameUpdate(int sheet, bool bUpdate); - void FrameParticule(float rTime); - void DrawParticule(int sheet); - - bool WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur); - -protected: - void DeleteRank(int rank); - bool CheckChannel(int &channel); - void DrawParticuleTriangle(int i); - void DrawParticuleNorm(int i); - void DrawParticuleFlat(int i); - void DrawParticuleFog(int i); - void DrawParticuleRay(int i); - void DrawParticuleSphere(int i); - void DrawParticuleCylinder(int i); - void DrawParticuleWheel(int i); - CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father); - CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father); - void Play(Sound sound, Math::Vector pos, float amplitude); - bool TrackMove(int i, Math::Vector pos, float progress); - void TrackDraw(int i, ParticuleType type); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - LPDIRECT3DDEVICE7 m_pD3DDevice; - CRobotMain* m_main; - CTerrain* m_terrain; - CWater* m_water; - CSound* m_sound; - - Particule m_particule[MAXPARTICULE*MAXPARTITYPE]; - D3DTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0 - Track m_track[MAXTRACK]; - int m_wheelTraceTotal; - int m_wheelTraceIndex; - WheelTrace m_wheelTrace[MAXWHEELTRACE]; - int m_totalInterface[MAXPARTITYPE][SH_MAX]; - bool m_bFrameUpdate[SH_MAX]; - int m_fogTotal; - int m_fog[MAXPARTIFOG]; - int m_uniqueStamp; - int m_exploGunCounter; - float m_lastTimeGunDel; - float m_absTime; -}; - +// * 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/. + +// particule.h + +#pragma once + + +#include "math/point.h" +#include "old/d3dengine.h" +#include "old/sound.h" + + +class CInstanceManager; +class CRobotMain; +class CTerrain; +class CWater; +class CObject; + + +const int MAXPARTICULE = 500; +const int MAXPARTITYPE = 5; +const int MAXTRACK = 100; +const int MAXTRACKLEN = 10; +const int MAXPARTIFOG = 100; +const int MAXWHEELTRACE = 1000; + +enum ParticulePlace +{ + SH_WORLD = 0, // particle in the world in the interface + SH_FRONT = 1, // particle in the world on the interface + SH_INTERFACE = 2, // particle in the interface + SH_MAX = 3 +}; + +// type == 0 -> triangles +// type == 1 -> effect00 (black background) +// type == 2 -> effect01 (black background) +// type == 3 -> effect02 (black background) +// type == 4 -> text (white background) + + +enum ParticuleType +{ + PARTIEXPLOT = 1, // technology explosion + PARTIEXPLOO = 2, // organic explosion + PARTIMOTOR = 3, // the engine exhaust gas + PARTIGLINT = 4, // reflection + PARTIBLITZ = 5, // lightning recharging battery + PARTICRASH = 6, // dust after fall + PARTIGAS = 7, // gas from the reactor + PARTIFIRE = 9, // fireball shrinks + PARTIFIREZ = 10, // fireball grows + PARTIBLUE = 11, // blue ball + PARTISELY = 12, // yellow selection + PARTISELR = 13, // red selection + PARTIGUN1 = 18, // a bullet (fireball) + PARTIGUN2 = 19, // bullet 2 (ant) + PARTIGUN3 = 20, // bullet 3 (spider) + PARTIGUN4 = 21, // bullet 4 (orgaball) + PARTIFRAG = 22, // triangular fragment + PARTIQUEUE = 23, // inflamed tail + PARTIORGANIC1 = 24, // organic ball mother + PARTIORGANIC2 = 25, // organic ball daughter + PARTISMOKE1 = 26, // black smoke + PARTISMOKE2 = 27, // black smoke + PARTISMOKE3 = 28, // black smoke + PARTISMOKE4 = 29, // black smoke + PARTIBLOOD = 30, // human blood + PARTIBLOODM = 31, // blood laying + PARTIVAPOR = 32, // steam + PARTIVIRUS1 = 33, // virus 1 + PARTIVIRUS2 = 34, // virus 2 + PARTIVIRUS3 = 35, // virus 3 + PARTIVIRUS4 = 36, // virus 4 + PARTIVIRUS5 = 37, // virus 5 + PARTIVIRUS6 = 38, // virus 6 + PARTIVIRUS7 = 39, // virus 7 + PARTIVIRUS8 = 40, // virus 8 + PARTIVIRUS9 = 41, // virus 9 + PARTIVIRUS10 = 42, // virus 10 + PARTIRAY1 = 43, // ray 1 (turn) + PARTIRAY2 = 44, // ray 2 (electric arc) + PARTIRAY3 = 45, // ray 3 + PARTIRAY4 = 46, // ray 4 + PARTIFLAME = 47, // flame + PARTIBUBBLE = 48, // bubble + PARTIFLIC = 49, // circles in the water + PARTIEJECT = 50, // ejection from the reactor + PARTISCRAPS = 51, // waste from the reactor + PARTITOTO = 52, // reactor of tot + PARTIERROR = 53, // toto says no + PARTIWARNING = 54, // foo says blah + PARTIINFO = 54, // toto says yes + PARTIQUARTZ = 55, // reflection crystal + PARTISPHERE0 = 56, // explosion sphere + PARTISPHERE1 = 57, // energy sphere + PARTISPHERE2 = 58, // analysis sphere + PARTISPHERE3 = 59, // shield sphere + PARTISPHERE4 = 60, // information sphere (emit) + PARTISPHERE5 = 61, // botanical sphere (gravity root) + PARTISPHERE6 = 62, // information sphere (receive) + PARTISPHERE7 = 63, // sphere + PARTISPHERE8 = 64, // sphere + PARTISPHERE9 = 65, // sphere + PARTIGUNDEL = 66, // bullet destroyed by shield + PARTIPART = 67, // object part + PARTITRACK1 = 68, // drag 1 + PARTITRACK2 = 69, // drag 2 + PARTITRACK3 = 70, // drag 3 + PARTITRACK4 = 71, // drag 4 + PARTITRACK5 = 72, // drag 5 + PARTITRACK6 = 73, // drag 6 + PARTITRACK7 = 74, // drag 7 + PARTITRACK8 = 75, // drag 8 + PARTITRACK9 = 76, // drag 9 + PARTITRACK10 = 77, // drag 10 + PARTITRACK11 = 78, // drag 11 + PARTITRACK12 = 79, // drag 12 + PARTITRACK13 = 80, // drag 13 + PARTITRACK14 = 81, // drag 14 + PARTITRACK15 = 82, // drag 15 + PARTITRACK16 = 83, // drag 16 + PARTITRACK17 = 84, // drag 17 + PARTITRACK18 = 85, // drag 18 + PARTITRACK19 = 86, // drag 19 + PARTITRACK20 = 87, // drag 20 + PARTIGLINTb = 88, // blue reflection + PARTIGLINTr = 89, // red reflection + PARTILENS1 = 90, // brilliance 1 (orange) + PARTILENS2 = 91, // brilliance 2 (yellow) + PARTILENS3 = 92, // brilliance 3 (red) + PARTILENS4 = 93, // brilliance 4 (violet) + PARTICONTROL = 94, // reflection on button + PARTISHOW = 95, // shows a place + PARTICHOC = 96, // shock wave + PARTIGFLAT = 97, // shows if the ground is flat + PARTIRECOVER = 98, // blue ball recycler + PARTIROOT = 100, // gravity root smoke + PARTIPLOUF0 = 101, // splash + PARTIPLOUF1 = 102, // splash + PARTIPLOUF2 = 103, // splash + PARTIPLOUF3 = 104, // splash + PARTIPLOUF4 = 105, // splash + PARTIDROP = 106, // drop + PARTIFOG0 = 107, // fog 0 + PARTIFOG1 = 108, // fog 1 + PARTIFOG2 = 109, // fog 2 + PARTIFOG3 = 110, // fog 3 + PARTIFOG4 = 111, // fog 4 + PARTIFOG5 = 112, // fog 5 + PARTIFOG6 = 113, // fog 6 + PARTIFOG7 = 114, // fog 7 + PARTIFOG8 = 115, // fog 8 + PARTIFOG9 = 116, // fog 9 + PARTILIMIT1 = 117, // shows the limits 1 + PARTILIMIT2 = 118, // shows the limits 2 + PARTILIMIT3 = 119, // shows the limits 3 + PARTILIMIT4 = 120, // shows the limits 4 + PARTIWATER = 121, // drop of water + PARTIEXPLOG1 = 122, // ball explosion 1 + PARTIEXPLOG2 = 123, // ball explosion 2 + PARTIBASE = 124, // gases of spaceship + PARTITRACE0 = 140, // trace + PARTITRACE1 = 141, // trace + PARTITRACE2 = 142, // trace + PARTITRACE3 = 143, // trace + PARTITRACE4 = 144, // trace + PARTITRACE5 = 145, // trace + PARTITRACE6 = 146, // trace + PARTITRACE7 = 147, // trace + PARTITRACE8 = 148, // trace + PARTITRACE9 = 149, // trace + PARTITRACE10 = 150, // trace + PARTITRACE11 = 151, // trace + PARTITRACE12 = 152, // trace + PARTITRACE13 = 153, // trace + PARTITRACE14 = 154, // trace + PARTITRACE15 = 155, // trace + PARTITRACE16 = 156, // trace + PARTITRACE17 = 157, // trace + PARTITRACE18 = 158, // trace + PARTITRACE19 = 159, // trace +}; + +enum ParticulePhase +{ + PARPHSTART = 0, + PARPHEND = 1, +}; + +struct Particule +{ + char bUsed; // true -> particle used + char bRay; // true -> ray with goal + unsigned short uniqueStamp; // unique mark + short sheet; // sheet (0..n) + ParticuleType type; // type PARTI* + ParticulePhase phase; // phase PARPH* + float mass; // mass of the particle (in rebounding) + float weight; // weight of the particle (for noise) + float duration; // length of life + Math::Vector pos; // absolute position (relative if object links) + Math::Vector goal; // goal position (if bRay) + Math::Vector speed; // speed of displacement + float windSensitivity; + short bounce; // number of rebounds + Math::Point dim; // dimensions of the rectangle + float zoom; // zoom (0..1) + float angle; // angle of rotation + float intensity; // intensity + Math::Point texSup; // coordinated upper texture + Math::Point texInf; // coordinated lower texture + float time; // age of the particle (0..n) + float phaseTime; // age at the beginning of phase + float testTime; // time since last test + CObject* objLink; // father object (for example reactor) + CObject* objFather; // father object (for example reactor) + short objRank; // rank of the object, or -1 + short trackRank; // rank of the drag +}; + +struct Track +{ + char bUsed; // true -> drag used + char bDrawParticule; + float step; // duration of not + float last; // increase last not memorized + float intensity; // intensity at starting (0..1) + float width; // tail width + int used; // number of positions in "pos" + int head; // head to write index + Math::Vector pos[MAXTRACKLEN]; + float len[MAXTRACKLEN]; +}; + +struct WheelTrace +{ + ParticuleType type; // type PARTI* + Math::Vector pos[4]; // rectangle positions + float startTime; // beginning of life +}; + + + +class CParticule +{ +public: + CParticule(CInstanceManager* iMan, CD3DEngine* engine); + ~CParticule(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + + void FlushParticule(); + void FlushParticule(int sheet); + int CreateParticule(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateFrag(Math::Vector pos, Math::Vector speed, D3DTriangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreatePart(Math::Vector pos, Math::Vector speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateRay(Math::Vector pos, Math::Vector goal, ParticuleType type, Math::Point dim, float duration=1.0f, int sheet=0); + int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); + void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticuleType type); + void DeleteParticule(ParticuleType type); + void DeleteParticule(int channel); + void SetObjectLink(int channel, CObject *object); + void SetObjectFather(int channel, CObject *object); + void SetPosition(int channel, Math::Vector pos); + void SetDimension(int channel, Math::Point dim); + void SetZoom(int channel, float zoom); + void SetAngle(int channel, float angle); + void SetIntensity(int channel, float intensity); + void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity); + void SetPhase(int channel, ParticulePhase phase, float duration); + bool GetPosition(int channel, Math::Vector &pos); + + D3DCOLORVALUE RetFogColor(Math::Vector pos); + + void SetFrameUpdate(int sheet, bool bUpdate); + void FrameParticule(float rTime); + void DrawParticule(int sheet); + + bool WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur); + +protected: + void DeleteRank(int rank); + bool CheckChannel(int &channel); + void DrawParticuleTriangle(int i); + void DrawParticuleNorm(int i); + void DrawParticuleFlat(int i); + void DrawParticuleFog(int i); + void DrawParticuleRay(int i); + void DrawParticuleSphere(int i); + void DrawParticuleCylinder(int i); + void DrawParticuleWheel(int i); + CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father); + CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father); + void Play(Sound sound, Math::Vector pos, float amplitude); + bool TrackMove(int i, Math::Vector pos, float progress); + void TrackDraw(int i, ParticuleType type); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + LPDIRECT3DDEVICE7 m_pD3DDevice; + CRobotMain* m_main; + CTerrain* m_terrain; + CWater* m_water; + CSound* m_sound; + + Particule m_particule[MAXPARTICULE*MAXPARTITYPE]; + D3DTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0 + Track m_track[MAXTRACK]; + int m_wheelTraceTotal; + int m_wheelTraceIndex; + WheelTrace m_wheelTrace[MAXWHEELTRACE]; + int m_totalInterface[MAXPARTITYPE][SH_MAX]; + bool m_bFrameUpdate[SH_MAX]; + int m_fogTotal; + int m_fog[MAXPARTIFOG]; + int m_uniqueStamp; + int m_exploGunCounter; + float m_lastTimeGunDel; + float m_absTime; +}; + diff --git a/src/old/planet.cpp b/src/old/planet.cpp index 0733459..48a3d4d 100644 --- a/src/old/planet.cpp +++ b/src/old/planet.cpp @@ -1,247 +1,247 @@ -// * 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/. - -// planet.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/planet.h" - - - - -// Constructor of the terrain. - -CPlanet::CPlanet(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_PLANET, this); - - m_engine = engine; - Flush(); - -} - -// Destructor of the terrain. - -CPlanet::~CPlanet() -{ -} - - -// Removes all the planets. - -void CPlanet::Flush() -{ - int i, j; - - for ( j=0 ; j<2 ; j++ ) - { - for ( i=0 ; iRetPause() ) return true; - - m_time += event.rTime; - - for ( i=0 ; iLoadTexture(m_planet[j][i].name); - } - } -} - -// Draws all the planets. - -void CPlanet::Draw() -{ - LPDIRECT3DDEVICE7 device; - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Vector n; - Math::Point p1, p2; - float eyeDirH, eyeDirV, dp, u1, u2, v1, v2, a; - int i; - - device = m_engine->RetD3DDevice(); - eyeDirH = m_engine->RetEyeDirH(); - eyeDirV = m_engine->RetEyeDirV(); - - n = Math::Vector(0.0f, 0.0f, -1.0f); // normal - dp = 0.5f/256.0f; - - for ( i=0 ; iSetTexture(m_planet[m_mode][i].name); - - if ( m_planet[m_mode][i].bTGA ) - { - m_engine->SetState(D3DSTATEWRAP|D3DSTATEALPHA); - } - else - { - m_engine->SetState(D3DSTATEWRAP|D3DSTATETTb); - } - - a = eyeDirH + m_planet[m_mode][i].angle.x; - p1.x = Math::Mod(a, Math::PI*2.0f)-0.5f; - - a = eyeDirV + m_planet[m_mode][i].angle.y; - p1.y = 0.4f+(Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI)*(2.0f/Math::PI); - - p1.x -= m_planet[m_mode][i].dim/2.0f*0.75f; - p1.y -= m_planet[m_mode][i].dim/2.0f; - p2.x = p1.x+m_planet[m_mode][i].dim*0.75f; - p2.y = p1.y+m_planet[m_mode][i].dim; - - u1 = m_planet[m_mode][i].uv1.x + dp; - v1 = m_planet[m_mode][i].uv1.y + dp; - u2 = m_planet[m_mode][i].uv2.x - dp; - v2 = m_planet[m_mode][i].uv2.y - dp; - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - } -} - - -// Creates a new planet. - -bool CPlanet::Create(int mode, Math::Point start, float dim, float speed, - float dir, char *name, Math::Point uv1, Math::Point uv2) -{ - int i; - - if ( mode < 0 ) mode = 0; - if ( mode > 1 ) mode = 1; - - for ( i=0 ; i 1 ) mode = 1; - m_mode = mode; -} - -int CPlanet::RetMode() -{ - return m_mode; -} - +// * 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/. + +// planet.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/planet.h" + + + + +// Constructor of the terrain. + +CPlanet::CPlanet(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_PLANET, this); + + m_engine = engine; + Flush(); + +} + +// Destructor of the terrain. + +CPlanet::~CPlanet() +{ +} + + +// Removes all the planets. + +void CPlanet::Flush() +{ + int i, j; + + for ( j=0 ; j<2 ; j++ ) + { + for ( i=0 ; iRetPause() ) return true; + + m_time += event.rTime; + + for ( i=0 ; iLoadTexture(m_planet[j][i].name); + } + } +} + +// Draws all the planets. + +void CPlanet::Draw() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Vector n; + Math::Point p1, p2; + float eyeDirH, eyeDirV, dp, u1, u2, v1, v2, a; + int i; + + device = m_engine->RetD3DDevice(); + eyeDirH = m_engine->RetEyeDirH(); + eyeDirV = m_engine->RetEyeDirV(); + + n = Math::Vector(0.0f, 0.0f, -1.0f); // normal + dp = 0.5f/256.0f; + + for ( i=0 ; iSetTexture(m_planet[m_mode][i].name); + + if ( m_planet[m_mode][i].bTGA ) + { + m_engine->SetState(D3DSTATEWRAP|D3DSTATEALPHA); + } + else + { + m_engine->SetState(D3DSTATEWRAP|D3DSTATETTb); + } + + a = eyeDirH + m_planet[m_mode][i].angle.x; + p1.x = Math::Mod(a, Math::PI*2.0f)-0.5f; + + a = eyeDirV + m_planet[m_mode][i].angle.y; + p1.y = 0.4f+(Math::Mod(a+Math::PI, Math::PI*2.0f)-Math::PI)*(2.0f/Math::PI); + + p1.x -= m_planet[m_mode][i].dim/2.0f*0.75f; + p1.y -= m_planet[m_mode][i].dim/2.0f; + p2.x = p1.x+m_planet[m_mode][i].dim*0.75f; + p2.y = p1.y+m_planet[m_mode][i].dim; + + u1 = m_planet[m_mode][i].uv1.x + dp; + v1 = m_planet[m_mode][i].uv1.y + dp; + u2 = m_planet[m_mode][i].uv2.x - dp; + v2 = m_planet[m_mode][i].uv2.y - dp; + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + } +} + + +// Creates a new planet. + +bool CPlanet::Create(int mode, Math::Point start, float dim, float speed, + float dir, char *name, Math::Point uv1, Math::Point uv2) +{ + int i; + + if ( mode < 0 ) mode = 0; + if ( mode > 1 ) mode = 1; + + for ( i=0 ; i 1 ) mode = 1; + m_mode = mode; +} + +int CPlanet::RetMode() +{ + return m_mode; +} + diff --git a/src/old/planet.h b/src/old/planet.h index 14c8111..36f5586 100644 --- a/src/old/planet.h +++ b/src/old/planet.h @@ -1,76 +1,76 @@ -// * 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/. - -// planet.h - -#pragma once - - -#include "common/event.h" -#include "math/point.h" - - -class CInstanceManager; -class CD3DEngine; - - - -const int MAXPLANET = 10; - -struct Planet -{ - char bUsed; // true -> planet exists - Math::Point start; // initial position in degrees - Math::Point angle; // current position in degrees - float dim; // dimensions (0..1) - float speed; // speed - float dir; // direction in the sky - char name[20]; // name of the texture - Math::Point uv1, uv2; // texture mapping - char bTGA; // texture .TGA -}; - - - - -class CPlanet -{ -public: - CPlanet(CInstanceManager* iMan, CD3DEngine* engine); - ~CPlanet(); - - void Flush(); - bool EventProcess(const Event &event); - bool Create(int mode, Math::Point start, float dim, float speed, float dir, char *name, Math::Point uv1, Math::Point uv2); - bool PlanetExist(); - void LoadTexture(); - void Draw(); - void SetMode(int mode); - int RetMode(); - -protected: - bool EventFrame(const Event &event); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - - float m_time; - int m_mode; - Planet m_planet[2][MAXPLANET]; - bool m_bPlanetExist; -}; - +// * 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/. + +// planet.h + +#pragma once + + +#include "common/event.h" +#include "math/point.h" + + +class CInstanceManager; +class CD3DEngine; + + + +const int MAXPLANET = 10; + +struct Planet +{ + char bUsed; // true -> planet exists + Math::Point start; // initial position in degrees + Math::Point angle; // current position in degrees + float dim; // dimensions (0..1) + float speed; // speed + float dir; // direction in the sky + char name[20]; // name of the texture + Math::Point uv1, uv2; // texture mapping + char bTGA; // texture .TGA +}; + + + + +class CPlanet +{ +public: + CPlanet(CInstanceManager* iMan, CD3DEngine* engine); + ~CPlanet(); + + void Flush(); + bool EventProcess(const Event &event); + bool Create(int mode, Math::Point start, float dim, float speed, float dir, char *name, Math::Point uv1, Math::Point uv2); + bool PlanetExist(); + void LoadTexture(); + void Draw(); + void SetMode(int mode); + int RetMode(); + +protected: + bool EventFrame(const Event &event); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + + float m_time; + int m_mode; + Planet m_planet[2][MAXPLANET]; + bool m_bPlanetExist; +}; + diff --git a/src/old/pyro.cpp b/src/old/pyro.cpp index fc61e62..96fc776 100644 --- a/src/old/pyro.cpp +++ b/src/old/pyro.cpp @@ -1,2486 +1,2486 @@ -// * 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/. - -// pyro.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "object/robotmain.h" -#include "old/terrain.h" -#include "old/camera.h" -#include "old/particule.h" -#include "old/light.h" -#include "object/object.h" -#include "object/motion/motion.h" -#include "object/motion/motionhuman.h" -#include "ui/displaytext.h" -#include "old/sound.h" -#include "old/pyro.h" - - - - -// Object's constructor. - -CPyro::CPyro(CInstanceManager* iMan) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_PYRO, this, 100); - - m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA); - m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); - m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT); - m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT); - m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN); - m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); - m_object = 0; - - m_progress = 0.0f; - m_speed = 0.0f; - m_lightRank = -1; - m_soundChannel = -1; - LightOperFlush(); -} - -// Object's destructor. - -CPyro::~CPyro() -{ - m_iMan->DeleteInstance(CLASS_PYRO, this); -} - - -// Destroys the object. - -void CPyro::DeleteObject(bool bAll) -{ - if ( m_lightRank != -1 ) - { - m_light->DeleteLight(m_lightRank); - m_lightRank = -1; - } -} - - -// Creates pyrotechnic effect. - -bool CPyro::Create(PyroType type, CObject* pObj, float force) -{ - Math::Matrix* mat; - CObject* power; - CMotion* motion; - Math::Vector min, max, pos, speed; - Math::Point dim; - ObjectType oType; - Sound sound; - float duration, mass, h, limit; - int part, objRank, total, i, channel; - - m_object = pObj; - m_force = force; - - oType = pObj->RetType(); - objRank = pObj->RetObjectRank(0); - if ( objRank == -1 ) return false; - m_engine->GetBBox(objRank, min, max); - pos = pObj->RetPosition(0); - - DisplayError(type, pObj); // displays eventual messages - - // Copies all spheres of the object. - for ( i=0 ; i<50 ; i++ ) - { - if ( !pObj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break; - } - m_crashSphereUsed = i; - - // Calculates the size of the effect. - if ( oType == OBJECT_ANT || - oType == OBJECT_BEE || - oType == OBJECT_WORM || - oType == OBJECT_SPIDER ) - { - m_size = 40.0f; - } - else - { - m_size = Math::Distance(min, max)*2.0f; - if ( m_size < 4.0f ) m_size = 4.0f; - if ( m_size > 80.0f ) m_size = 80.0f; - } - if ( oType == OBJECT_TNT || - oType == OBJECT_BOMB ) - { - m_size *= 2.0f; - } - - m_pos = pos+(min+max)/2.0f; - m_type = type; - m_progress = 0.0f; - m_speed = 1.0f/20.0f; - m_time = 0.0f; - m_lastParticule = 0.0f; - m_lastParticuleSmoke = 0.0f; - m_lightRank = -1; - - if ( oType == OBJECT_TEEN28 || - oType == OBJECT_TEEN31 ) - { - m_pos.y = pos.y+1.0f; - } - - // Seeking the position of the battery. - power = pObj->RetPower(); - if ( power == 0 ) - { - m_bPower = false; - } - else - { - m_bPower = true; - pos = power->RetPosition(0); - pos.y += 1.0f; - mat = pObj->RetWorldMatrix(0); - m_posPower = Math::Transform(*mat, pos); - } - if ( oType == OBJECT_POWER || - oType == OBJECT_ATOMIC || - oType == OBJECT_URANIUM || - oType == OBJECT_TNT || - oType == OBJECT_BOMB ) - { - m_bPower = true; - m_posPower = m_pos; - m_posPower.y += 1.0f; - m_pos = m_posPower; - } - if ( oType == OBJECT_STATION ) - { - m_bPower = true; - mat = pObj->RetWorldMatrix(0); - m_posPower = Math::Transform(*mat, Math::Vector(-15.0f, 7.0f, 0.0f)); - m_pos = m_posPower; - } - if ( oType == OBJECT_ENERGY ) - { - m_bPower = true; - mat = pObj->RetWorldMatrix(0); - m_posPower = Math::Transform(*mat, Math::Vector(-7.0f, 6.0f, 0.0f)); - m_pos = m_posPower; - } - if ( oType == OBJECT_NUCLEAR ) - { - m_bPower = true; - m_posPower = m_pos; - } - if ( oType == OBJECT_PARA ) - { - m_bPower = true; - m_posPower = m_pos; - } - if ( oType == OBJECT_SCRAP4 || - oType == OBJECT_SCRAP5 ) // plastic material? - { - m_bPower = true; - m_posPower = m_pos; - } - - // Plays the sound of a pyrotechnic effect. - if ( type == PT_FRAGT || - type == PT_FRAGW || - type == PT_EXPLOT || - type == PT_EXPLOW ) - { - if ( m_bPower ) - { - sound = SOUND_EXPLOp; - } - else - { - sound = SOUND_EXPLO; - } - if ( oType == OBJECT_STONE || - oType == OBJECT_METAL || - oType == OBJECT_BULLET || - oType == OBJECT_BBOX || - oType == OBJECT_KEYa || - oType == OBJECT_KEYb || - oType == OBJECT_KEYc || - oType == OBJECT_KEYd ) - { - sound = SOUND_EXPLOl; - } - if ( oType == OBJECT_URANIUM || - oType == OBJECT_POWER || - oType == OBJECT_ATOMIC || - oType == OBJECT_TNT || - oType == OBJECT_BOMB ) - { - sound = SOUND_EXPLOlp; - } - m_sound->Play(sound, m_pos); - } - if ( type == PT_FRAGO || - type == PT_EXPLOO || - type == PT_SPIDER || - type == PT_SHOTM ) - { - m_sound->Play(SOUND_EXPLOi, m_pos); - } - if ( type == PT_BURNT || - type == PT_BURNO ) - { - m_soundChannel = m_sound->Play(SOUND_BURN, m_pos, 1.0f, 1.0f, true); - m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 12.0f, SOPER_CONTINUE); - m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 5.0f, SOPER_STOP); - } - if ( type == PT_BURNO ) - { - m_sound->Play(SOUND_DEADi, m_pos); - m_sound->Play(SOUND_DEADi, m_engine->RetEyePt()); - } - if ( type == PT_EGG ) - { - m_sound->Play(SOUND_EGG, m_pos); - } - if ( type == PT_WPCHECK || - type == PT_FLCREATE || - type == PT_FLDELETE ) - { - m_sound->Play(SOUND_WAYPOINT, m_pos); - } - if ( oType == OBJECT_HUMAN ) - { - if ( type == PT_DEADG ) - { - m_sound->Play(SOUND_DEADg, m_pos); - } - if ( type == PT_DEADW ) - { - m_sound->Play(SOUND_DEADw, m_pos); - } - if ( type == PT_SHOTH && m_object->RetSelect() ) - { - m_sound->Play(SOUND_AIE, m_pos); - m_sound->Play(SOUND_AIE, m_engine->RetEyePt()); - } - } - - if ( m_type == PT_FRAGT || - m_type == PT_FRAGO || - m_type == PT_FRAGW ) - { - m_engine->ShadowDelete(m_object->RetObjectRank(0)); - } - - if ( m_type == PT_DEADG ) - { - m_object->SetDead(true); - - motion = m_object->RetMotion(); - if ( motion != 0 ) - { - motion->SetAction(MHS_DEADg, 1.0f); - } - m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f); - m_camera->StartOver(OE_FADEOUTw, m_pos, 1.0f); - m_speed = 1.0f/10.0f; - return true; - } - if ( m_type == PT_DEADW ) - { - m_object->SetDead(true); - - motion = m_object->RetMotion(); - if ( motion != 0 ) - { - motion->SetAction(MHS_DEADw, 4.0f); - } - m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f); - m_camera->StartOver(OE_FADEOUTb, m_pos, 1.0f); - m_speed = 1.0f/10.0f; - return true; - } - - if ( m_type == PT_SHOTT || - m_type == PT_SHOTM ) - { - m_camera->StartEffect(CE_SHOT, m_pos, force); - m_speed = 1.0f/1.0f; - return true; - } - if ( m_type == PT_SHOTH ) - { - if ( m_object->RetSelect() ) - { - m_camera->StartOver(OE_BLOOD, m_pos, force); - } - m_speed = 1.0f/0.2f; - return true; - } - - if ( m_type == PT_SHOTW ) - { - m_speed = 1.0f/1.0f; - } - - if ( m_type == PT_BURNT ) - { - BurnStart(); - } - - if ( m_type == PT_WPCHECK ) - { - m_speed = 1.0f/8.0f; - m_object->SetEnable(false); // object more functional - } - if ( m_type == PT_FLCREATE ) - { - m_speed = 1.0f/2.0f; - } - if ( m_type == PT_FLDELETE ) - { - m_speed = 1.0f/2.0f; - m_object->SetEnable(false); // object more functional - } - if ( m_type == PT_RESET ) - { - m_speed = 1.0f/2.0f; - m_object->SetPosition(0, m_object->RetResetPosition()); - m_object->SetAngle(0, m_object->RetResetAngle()); - m_object->SetZoom(0, 0.0f); - } - if ( m_type == PT_FINDING ) - { - limit = (m_size-1.0f)/4.0f; - if ( limit > 8.0f ) limit = 8.0f; - if ( oType == OBJECT_APOLLO2 ) limit = 2.0f; - m_speed = 1.0f/limit; - } - - if ( m_type == PT_EXPLOT || - m_type == PT_EXPLOO || - m_type == PT_EXPLOW ) - { - CreateTriangle(pObj, oType, 0); - m_engine->ShadowDelete(m_object->RetObjectRank(0)); - ExploStart(); - } - - if ( m_type == PT_FALL ) - { - FallStart(); - return true; - } - - if ( m_type == PT_BURNT || - m_type == PT_BURNO ) - { - m_speed = 1.0f/15.0f; - - LightOperAdd(0.00f, 0.0f, 2.0f, 1.0f, 0.0f); // red-orange - LightOperAdd(0.30f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray - LightOperAdd(0.80f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray - LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray - CreateLight(m_pos, 40.0f); - return true; - } - - if ( m_type == PT_SPIDER ) - { - m_speed = 1.0f/15.0f; - - pos = Math::Vector(-3.0f, 2.0f, 0.0f); - mat = pObj->RetWorldMatrix(0); - m_pos = Math::Transform(*mat, pos); - - m_engine->ShadowDelete(m_object->RetObjectRank(0)); - } - - if ( m_type != PT_EGG && - m_type != PT_WIN && - m_type != PT_LOST ) - { - h = 40.0f; - if ( m_type == PT_FRAGO || - m_type == PT_EXPLOO ) - { - LightOperAdd(0.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green - LightOperAdd(0.05f, 1.0f, -1.0f, -0.5f, -1.0f); // dark green - LightOperAdd(1.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green - } - else if ( m_type == PT_FRAGT || - m_type == PT_EXPLOT ) - { - LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow - LightOperAdd(0.02f, 1.0f, 4.0f, 2.0f, 0.0f); // red-orange - LightOperAdd(0.16f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray - LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray - h = m_size*2.0f; - } - else if ( m_type == PT_SPIDER ) - { - LightOperAdd(0.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red - LightOperAdd(0.05f, 1.0f, -0.5f, -1.0f, -1.0f); // dark red - LightOperAdd(1.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red - } - else if ( m_type == PT_FRAGW || - m_type == PT_EXPLOW || - m_type == PT_SHOTW ) - { - LightOperAdd(0.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow - LightOperAdd(0.05f, 1.0f, -0.5f, -0.5f, -1.0f); // dark yellow - LightOperAdd(1.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow - } - else if ( m_type == PT_WPCHECK || - m_type == PT_FLCREATE || - m_type == PT_FLDELETE || - m_type == PT_RESET || - m_type == PT_FINDING ) - { - LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow - LightOperAdd(1.00f, 0.0f, 4.0f, 4.0f, 2.0f); // yellow - } - else - { - LightOperAdd(0.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray - LightOperAdd(0.05f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray - LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray - } - CreateLight(m_pos, h); - - if ( m_type != PT_SHOTW && - m_type != PT_WPCHECK && - m_type != PT_FLCREATE && - m_type != PT_FLDELETE && - m_type != PT_RESET && - m_type != PT_FINDING ) - { - m_camera->StartEffect(CE_EXPLO, m_pos, force); - } - } - - if ( m_type == PT_SHOTW ) return true; - - // Generates the triangles of the explosion. - if ( m_type == PT_FRAGT || - m_type == PT_FRAGO || - m_type == PT_FRAGW || - m_type == PT_SPIDER || - m_type == PT_EGG || - (m_type == PT_EXPLOT && oType == OBJECT_MOBILEtg) || - (m_type == PT_EXPLOT && oType == OBJECT_TEEN28 ) || - (m_type == PT_EXPLOT && oType == OBJECT_TEEN31 ) ) - { - for ( part=0 ; partRetParticuleDensity()); - if ( oType == OBJECT_TNT || - oType == OBJECT_BOMB ) total *= 3; - for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK1, - duration, mass, Math::Rand()+0.7f, 1.0f); - } - } - - if ( m_size > 10.0f ) // large enough (freight excluded)? - { - if ( m_bPower ) - { - pos = m_posPower; - } - else - { - pos = m_pos; - m_terrain->MoveOnFloor(pos); - pos.y += 1.0f; - } - dim.x = m_size*0.4f; - dim.y = dim.x; - m_particule->CreateParticule(pos, Math::Vector(0.0f,0.0f,0.0f), dim, PARTISPHERE0, 2.0f, 0.0f, 0.0f); - } - } - - if ( m_type == PT_FRAGO || - m_type == PT_EXPLOO ) - { - total = (int)(10.0f*m_engine->RetParticuleDensity()); - for ( i=0 ; iCreateParticule(pos, speed, dim, PARTIORGANIC1, - duration, mass); - } - total = (int)(5.0f*m_engine->RetParticuleDensity()); - for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK4, - duration, mass, duration*0.5f, dim.x*2.0f); - } - } - - if ( m_type == PT_SPIDER ) - { - for ( i=0 ; i<50 ; i++ ) - { - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*3.0f; - pos.z += (Math::Rand()-0.5f)*3.0f; - pos.y += (Math::Rand()-0.5f)*2.0f; - speed.x = (Math::Rand()-0.5f)*24.0f; - speed.z = (Math::Rand()-0.5f)*24.0f; - speed.y = 10.0f+Math::Rand()*10.0f; - dim.x = 1.0f; - dim.y = dim.x; - channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN3, 2.0f+Math::Rand()*2.0f, 10.0f); - m_particule->SetObjectFather(channel, pObj); - } - total = (int)(10.0f*m_engine->RetParticuleDensity()); - for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK3, - 2.0f+Math::Rand()*2.0f, 10.0f, 2.0f, 0.6f); - } - } - - if ( type == PT_FRAGT || - type == PT_FRAGW || - type == PT_EXPLOT || - type == PT_EXPLOW ) - { - if ( m_size > 10.0f || m_bPower ) - { - pos = m_pos; -//? m_terrain->MoveOnFloor(pos); -//? pos.y += 2.0f; - speed = Math::Vector(0.0f, 0.0f, 0.0f); - dim.x = m_size; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTICHOC, 2.0f); - } - } - - return true; -} - -// Creates an explosion with triangular form of particles. - -void CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part) -{ - D3DTriangle buffer[100]; - Math::Matrix* mat; - Math::Vector offset, pos, speed; - float percent, min, max, h, duration, mass; - int objRank, total, i; - - objRank = pObj->RetObjectRank(part); - if ( objRank == -1 ) return; - - min = 0.0f; - max = m_engine->RetLimitLOD(0); - total = m_engine->RetTotalTriangles(objRank); - percent = 0.10f; - if ( total < 50 ) percent = 0.25f; - if ( total < 20 ) percent = 0.50f; - if ( m_type == PT_EGG ) percent = 0.30f; - if ( oType == OBJECT_POWER || - oType == OBJECT_ATOMIC || - oType == OBJECT_URANIUM || - oType == OBJECT_TNT || - oType == OBJECT_BOMB ) percent = 0.75f; - if ( oType == OBJECT_MOBILEtg ) percent = 0.50f; - if ( oType == OBJECT_TEEN28 ) percent = 0.75f; - if ( oType == OBJECT_MOTHER ) max = 1000000.0f; - if ( oType == OBJECT_TEEN28 ) max = 1000000.0f; - if ( oType == OBJECT_TEEN31 ) max = 1000000.0f; - total = m_engine->GetTriangles(objRank, min, max, buffer, 100, percent); - - for ( i=0 ; i 5.0f ) - { - p2.x = p1.x+((p2.x-p1.x)*5.0f/h); - p2.y = p1.y+((p2.y-p1.y)*5.0f/h); - p2.z = p1.z+((p2.z-p1.z)*5.0f/h); - } - - h = Math::Distance(p2, p3); - if ( h > 5.0f ) - { - p3.x = p2.x+((p3.x-p2.x)*5.0f/h); - p3.y = p2.y+((p3.y-p2.y)*5.0f/h); - p3.z = p2.z+((p3.z-p2.z)*5.0f/h); - } - - h = Math::Distance(p3, p1); - if ( h > 5.0f ) - { - p1.x = p3.x+((p1.x-p3.x)*5.0f/h); - p1.y = p3.y+((p1.y-p3.y)*5.0f/h); - p1.z = p3.z+((p1.z-p3.z)*5.0f/h); - } - - buffer[i].triangle[0].x = p1.x; - buffer[i].triangle[0].y = p1.y; - buffer[i].triangle[0].z = p1.z; - buffer[i].triangle[1].x = p2.x; - buffer[i].triangle[1].y = p2.y; - buffer[i].triangle[1].z = p2.z; - buffer[i].triangle[2].x = p3.x; - buffer[i].triangle[2].y = p3.y; - buffer[i].triangle[2].z = p3.z; - - offset.x = (buffer[i].triangle[0].x+buffer[i].triangle[1].x+buffer[i].triangle[2].x)/3.0f; - offset.y = (buffer[i].triangle[0].y+buffer[i].triangle[1].y+buffer[i].triangle[2].y)/3.0f; - offset.z = (buffer[i].triangle[0].z+buffer[i].triangle[1].z+buffer[i].triangle[2].z)/3.0f; - - buffer[i].triangle[0].x -= offset.x; - buffer[i].triangle[1].x -= offset.x; - buffer[i].triangle[2].x -= offset.x; - - buffer[i].triangle[0].y -= offset.y; - buffer[i].triangle[1].y -= offset.y; - buffer[i].triangle[2].y -= offset.y; - - buffer[i].triangle[0].z -= offset.z; - buffer[i].triangle[1].z -= offset.z; - buffer[i].triangle[2].z -= offset.z; - - mat = pObj->RetWorldMatrix(part); - pos = Math::Transform(*mat, offset); - if ( m_type == PT_EGG ) - { - speed.x = (Math::Rand()-0.5f)*10.0f; - speed.z = (Math::Rand()-0.5f)*10.0f; - speed.y = Math::Rand()*15.0f; - mass = Math::Rand()*20.0f+20.0f; - } - else if ( m_type == PT_SPIDER ) - { - speed.x = (Math::Rand()-0.5f)*10.0f; - speed.z = (Math::Rand()-0.5f)*10.0f; - speed.y = Math::Rand()*20.0f; - mass = Math::Rand()*10.0f+15.0f; - } - else - { - speed.x = (Math::Rand()-0.5f)*30.0f; - speed.z = (Math::Rand()-0.5f)*30.0f; - speed.y = Math::Rand()*30.0f; - mass = Math::Rand()*10.0f+15.0f; - } - if ( oType == OBJECT_STONE ) speed *= 0.5f; - if ( oType == OBJECT_URANIUM ) speed *= 0.4f; - duration = Math::Rand()*3.0f+3.0f; - m_particule->CreateFrag(pos, speed, &buffer[i], PARTIFRAG, - duration, mass, 0.5f); - } -} - -// Displays the error or eventual information, -// linked to the destruction of an insect, a vehicle or building. - -void CPyro::DisplayError(PyroType type, CObject* pObj) -{ - ObjectType oType; - Error err; - - oType = pObj->RetType(); - - if ( type == PT_FRAGT || - type == PT_FRAGO || - type == PT_FRAGW || - type == PT_EXPLOT || - type == PT_EXPLOO || - type == PT_EXPLOW || - type == PT_BURNT || - type == PT_BURNO ) - { - err = ERR_OK; - if ( oType == OBJECT_MOTHER ) err = INFO_DELETEMOTHER; - if ( oType == OBJECT_ANT ) err = INFO_DELETEANT; - if ( oType == OBJECT_BEE ) err = INFO_DELETEBEE; - if ( oType == OBJECT_WORM ) err = INFO_DELETEWORM; - if ( oType == OBJECT_SPIDER ) err = INFO_DELETESPIDER; - - if ( oType == OBJECT_MOBILEwa || - oType == OBJECT_MOBILEta || - oType == OBJECT_MOBILEfa || - oType == OBJECT_MOBILEia || - oType == OBJECT_MOBILEwc || - oType == OBJECT_MOBILEtc || - oType == OBJECT_MOBILEfc || - oType == OBJECT_MOBILEic || - oType == OBJECT_MOBILEwi || - oType == OBJECT_MOBILEti || - oType == OBJECT_MOBILEfi || - oType == OBJECT_MOBILEii || - oType == OBJECT_MOBILEws || - oType == OBJECT_MOBILEts || - oType == OBJECT_MOBILEfs || - oType == OBJECT_MOBILEis || - oType == OBJECT_MOBILErt || - oType == OBJECT_MOBILErc || - oType == OBJECT_MOBILErr || - oType == OBJECT_MOBILErs || - oType == OBJECT_MOBILEsa || - oType == OBJECT_MOBILEwt || - oType == OBJECT_MOBILEtt || - oType == OBJECT_MOBILEft || - oType == OBJECT_MOBILEit || - oType == OBJECT_MOBILEdr ) - { - err = ERR_DELETEMOBILE; - } - - if ( oType == OBJECT_DERRICK || - oType == OBJECT_FACTORY || - oType == OBJECT_STATION || - oType == OBJECT_CONVERT || - oType == OBJECT_REPAIR || - oType == OBJECT_DESTROYER|| - oType == OBJECT_TOWER || - oType == OBJECT_RESEARCH || - oType == OBJECT_RADAR || - oType == OBJECT_INFO || - oType == OBJECT_ENERGY || - oType == OBJECT_LABO || - oType == OBJECT_NUCLEAR || - oType == OBJECT_PARA || - oType == OBJECT_SAFE || - oType == OBJECT_HUSTON || - oType == OBJECT_START || - oType == OBJECT_END ) - { - err = ERR_DELETEBUILDING; - m_displayText->DisplayError(err, pObj->RetPosition(0), 5.0f); - return; - } - - if ( err != ERR_OK ) - { - m_displayText->DisplayError(err, pObj); - } - } -} - - -// Management of an event. - -bool CPyro::EventProcess(const Event &event) -{ - ParticuleType type; - Math::Vector pos, speed, angle; - Math::Point dim; - float prog, factor, duration; - int i, r; - - if ( event.event != EVENT_FRAME ) return true; - if ( m_engine->RetPause() ) return true; - - m_time += event.rTime; - m_progress += event.rTime*m_speed; - - if ( m_soundChannel != -1 && m_object != 0 ) - { - pos = m_object->RetPosition(0); - m_sound->Position(m_soundChannel, pos); - - if ( m_lightRank != -1 ) - { - pos.y += m_lightHeight; - m_light->SetLightPos(m_lightRank, pos); - } - } - - if ( m_type == PT_SHOTT && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - if ( m_crashSphereUsed > 0 ) - { - i = rand()%m_crashSphereUsed; - pos = m_crashSpherePos[i]; - pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; - pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; - speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; - speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; - speed.y = Math::Rand()*m_crashSphereRadius[i]*1.0f; - dim.x = Math::Rand()*m_crashSphereRadius[i]*0.5f+m_crashSphereRadius[i]*0.75f*m_force; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f); - } - else - { - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*m_size*0.3f; - pos.z += (Math::Rand()-0.5f)*m_size*0.3f; - speed.x = (Math::Rand()-0.5f)*m_size*0.1f; - speed.z = (Math::Rand()-0.5f)*m_size*0.1f; - speed.y = Math::Rand()*m_size*0.2f; - dim.x = Math::Rand()*m_size/10.0f+m_size/10.0f*m_force; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f); - } - } - - if ( m_type == PT_SHOTH && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - for ( i=0 ; i<10 ; i++ ) - { - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*m_size*0.2f; - pos.z += (Math::Rand()-0.5f)*m_size*0.2f; - pos.y += (Math::Rand()-0.5f)*m_size*0.5f; - speed.x = (Math::Rand()-0.5f)*5.0f; - speed.z = (Math::Rand()-0.5f)*5.0f; - speed.y = Math::Rand()*1.0f; - dim.x = 1.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIBLOOD, Math::Rand()*3.0f+3.0f, Math::Rand()*10.0f+15.0f, 0.5f); - } - } - - if ( m_type == PT_SHOTM && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - r = (int)(10.0f*m_engine->RetParticuleDensity()); - for ( i=0 ; iCreateParticule(pos, speed, dim, PARTIBLOODM, 2.0f, 50.0f, 0.0f); - } - } - - if ( m_type == PT_SHOTW && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - if ( m_crashSphereUsed > 0 ) - { - i = rand()%m_crashSphereUsed; - pos = m_crashSpherePos[i]; - pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; - pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; - speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; - speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; - speed.y = Math::Rand()*m_crashSphereRadius[i]*1.0f; - dim.x = 1.0f*m_force; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); - } - else - { - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*m_size*0.3f; - pos.z += (Math::Rand()-0.5f)*m_size*0.3f; - speed.x = (Math::Rand()-0.5f)*m_size*0.1f; - speed.z = (Math::Rand()-0.5f)*m_size*0.1f; - speed.y = Math::Rand()*m_size*0.2f; - dim.x = 1.0f*m_force; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); - } - } - - if ( m_type == PT_SHOTW && - m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time ) - { - m_lastParticuleSmoke = m_time; - - pos = m_pos; - pos.y -= 2.0f; - pos.x += (Math::Rand()-0.5f)*4.0f; - pos.z += (Math::Rand()-0.5f)*4.0f; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 10.0f+Math::Rand()*10.0f; - dim.x = Math::Rand()*2.5f+2.0f*m_force; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f); - } - - if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) && - m_progress < 0.05f && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - speed.x = (Math::Rand()-0.5f)*m_size*1.0f; - speed.z = (Math::Rand()-0.5f)*m_size*1.0f; - speed.y = Math::Rand()*m_size*0.50f; - dim.x = Math::Rand()*m_size/5.0f+m_size/5.0f; - dim.y = dim.x; - - m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOT); - } - - if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) && - m_progress < 0.10f && - m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time ) - { - m_lastParticuleSmoke = m_time; - - dim.x = Math::Rand()*m_size/3.0f+m_size/3.0f; - dim.y = dim.x; - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*m_size*0.5f; - pos.z += (Math::Rand()-0.5f)*m_size*0.5f; - m_terrain->MoveOnFloor(pos); - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = -dim.x/2.0f/4.0f; - pos.y += dim.x/2.0f; - - r = rand()%2; - if ( r == 0 ) type = PARTISMOKE1; - if ( r == 1 ) type = PARTISMOKE2; - m_particule->CreateParticule(pos, speed, dim, type, 6.0f); - } - - if ( (m_type == PT_FRAGO || m_type == PT_EXPLOO) && - m_progress < 0.03f && - m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - speed.x = (Math::Rand()-0.5f)*m_size*2.0f; - speed.z = (Math::Rand()-0.5f)*m_size*2.0f; - speed.y = Math::Rand()*m_size*1.0f; - dim.x = Math::Rand()*m_size/2.0f+m_size/2.0f; - dim.y = dim.x; - - m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOO); - } - - if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) && - m_progress < 0.05f && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - speed.x = (Math::Rand()-0.5f)*m_size*1.0f; - speed.z = (Math::Rand()-0.5f)*m_size*1.0f; - speed.y = Math::Rand()*m_size*0.50f; - dim.x = 1.0f; - dim.y = dim.x; - - m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); - } - - if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) && - m_progress < 0.25f && - m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticuleSmoke = m_time; - - pos = m_pos; - pos.y -= 2.0f; - pos.x += (Math::Rand()-0.5f)*4.0f; - pos.z += (Math::Rand()-0.5f)*4.0f; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 4.0f+Math::Rand()*4.0f; - dim.x = Math::Rand()*2.5f+2.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f); - } - - if ( m_type == PT_WPCHECK ) - { - if ( m_progress < 0.25f ) - { - factor = 0.0f; - } - else - { - factor = powf((m_progress-0.25f)/0.75f, 2.0f)*30.0f; - } - - if ( m_progress < 0.85f && - m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - pos.y += factor; - pos.x += (Math::Rand()-0.5f)*3.0f; - pos.z += (Math::Rand()-0.5f)*3.0f; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 5.0f+Math::Rand()*5.0f; - dim.x = Math::Rand()*1.5f+1.5f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f); -//? m_particule->CreateParticule(pos, speed, dim, (ParticuleType)(PARTILENS1+rand()%4), 2.0f); - } - - angle = m_object->RetAngle(0); - angle.y = m_progress*20.0f; - angle.x = sinf(m_progress*49.0f)*0.3f; - angle.z = sinf(m_progress*47.0f)*0.2f; - m_object->SetAngle(0, angle); - - pos = m_pos; - pos.y += factor; - m_object->SetPosition(0, pos); - - if ( m_progress > 0.85f ) - { - m_object->SetZoom(0, 1.0f-(m_progress-0.85f)/0.15f); - } - } - - if ( m_type == PT_FLCREATE ) - { - if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - m_terrain->MoveOnFloor(pos); - pos.x += (Math::Rand()-0.5f)*1.0f; - pos.z += (Math::Rand()-0.5f)*1.0f; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 2.0f+Math::Rand()*2.0f; - dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f); - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f); - } - - angle = m_object->RetAngle(0); -//? angle.y = powf(m_progress, 0.2f)*20.0f; - angle.x = sinf(m_progress*49.0f)*0.3f*(1.0f-m_progress); - angle.z = sinf(m_progress*47.0f)*0.2f*(1.0f-m_progress); - m_object->SetAngle(0, angle); - - m_object->SetZoom(0, m_progress); - } - - if ( m_type == PT_FLDELETE ) - { - if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - m_terrain->MoveOnFloor(pos); - pos.x += (Math::Rand()-0.5f)*1.0f; - pos.z += (Math::Rand()-0.5f)*1.0f; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 2.0f+Math::Rand()*2.0f; - dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f); - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f); - } - - angle = m_object->RetAngle(0); - angle.y = m_progress*20.0f; - angle.x = sinf(m_progress*49.0f)*0.3f; - angle.z = sinf(m_progress*47.0f)*0.2f; - m_object->SetAngle(0, angle); - - m_object->SetZoom(0, 1.0f-m_progress); - } - - if ( m_type == PT_RESET ) - { -#if 0 - if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - speed.x = (Math::Rand()-0.5f)*6.0f; - speed.z = (Math::Rand()-0.5f)*6.0f; - speed.y = Math::Rand()*12.0f; - dim.x = (Math::Rand()*2.5f+2.5f)*(1.0f-m_progress*0.9f); - dim.y = dim.x; - pos.y += dim.y; - m_particule->CreateParticule(pos, speed, dim, - (ParticuleType)(PARTILENS1+rand()%4), - Math::Rand()*2.5f+2.5f, - Math::Rand()*5.0f+5.0f, 0.0f); - } -#else - if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_pos; - pos.x += (Math::Rand()-0.5f)*5.0f; - pos.z += (Math::Rand()-0.5f)*5.0f; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 5.0f+Math::Rand()*5.0f; - dim.x = Math::Rand()*2.0f+2.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f); - - pos = m_pos; - speed.x = (Math::Rand()-0.5f)*20.0f; - speed.z = (Math::Rand()-0.5f)*20.0f; - speed.y = Math::Rand()*10.0f; - speed *= 0.5f+m_progress*0.5f; - dim.x = 0.6f; - dim.y = dim.x; - pos.y += dim.y; - duration = Math::Rand()*1.5f+1.5f; - m_particule->CreateTrack(pos, speed, dim, PARTITRACK6, - duration, 0.0f, - duration*0.9f, 0.7f); - } -#endif - - angle = m_object->RetResetAngle(); - m_object->SetAngleY(0, angle.y-powf((1.0f-m_progress)*5.0f, 2.0f)); - m_object->SetZoom(0, m_progress); - } - - if ( m_type == PT_FINDING ) - { - if ( m_object != 0 && - m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - factor = m_size*0.3f; - if ( m_object->RetType() == OBJECT_SAFE ) factor *= 1.3f; - if ( factor > 40.0f ) factor = 40.0f; - pos = m_pos; - m_terrain->MoveOnFloor(pos); - pos.x += (Math::Rand()-0.5f)*factor; - pos.z += (Math::Rand()-0.5f)*factor; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 4.0f+Math::Rand()*4.0f; - dim.x = (Math::Rand()*3.0f+3.0f)*(1.0f-m_progress*0.9f); - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f); - } - } - - if ( (m_type == PT_BURNT || m_type == PT_BURNO) && - m_object != 0 ) - { - if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - factor = m_size/25.0f; // 1 = standard size - - pos = m_object->RetPosition(0); - pos.y -= m_object->RetCharacter()->height; - pos.x += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; - pos.z += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 0.0f; - dim.x = (Math::Rand()*2.5f+1.0f)*factor; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f); - - pos = m_object->RetPosition(0); - pos.y -= m_object->RetCharacter()->height; - pos.x += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; - pos.z += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = (Math::Rand()*5.0f*m_progress+3.0f)*factor; - dim.x = (Math::Rand()*2.0f+1.0f)*factor; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f); - - pos = m_object->RetPosition(0); - pos.y -= 2.0f; - pos.x += (Math::Rand()-0.5f)*5.0f*factor; - pos.z += (Math::Rand()-0.5f)*5.0f*factor; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = (6.0f+Math::Rand()*6.0f+m_progress*6.0f)*factor; - dim.x = (Math::Rand()*1.5f+1.0f+m_progress*3.0f)*factor; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f); - } - - if ( m_type == PT_BURNT ) - { - BurnProgress(); - } - else - { - speed.y = 0.0f; - speed.x = (Math::Rand()-0.5f)*m_progress*1.0f; - speed.z = (Math::Rand()-0.5f)*m_progress*1.0f; - if ( m_progress > 0.8f ) - { - prog = (m_progress-0.8f)/0.2f; // 0..1 - speed.y = -prog*6.0f; // sinks into the ground - m_object->SetZoom(0, 1.0f-prog*0.5f); - } - m_object->SetLinVibration(speed); - } - } - - if ( m_type == PT_WIN ) - { - if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_object->RetPosition(0); - pos.y += 1.5f; - speed.x = (Math::Rand()-0.5f)*10.0f; - speed.z = (Math::Rand()-0.5f)*10.0f; - speed.y = 8.0f+Math::Rand()*8.0f; - dim.x = Math::Rand()*0.2f+0.2f; - dim.y = dim.x; - m_particule->CreateTrack(pos, speed, dim, - (ParticuleType)(PARTITRACK7+rand()%4), - 3.0f, 20.0f, 1.0f, 0.4f); - } - } - - if ( m_type == PT_LOST ) - { - if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) - { - m_lastParticule = m_time; - - pos = m_object->RetPosition(0); - pos.y -= 2.0f; - pos.x += (Math::Rand()-0.5f)*10.0f; - pos.z += (Math::Rand()-0.5f)*10.0f; - speed.x = 0.0f; - speed.z = 0.0f; - speed.y = 1.0f+Math::Rand()*1.0f; - dim.x = Math::Rand()*1.0f+1.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 8.0f, 0.0f, 0.0f); - } - } - - if ( m_type == PT_FALL ) - { - FallProgress(event.rTime); - } - - if ( m_lightRank != -1 ) - { - LightOperFrame(event.rTime); - } - - return true; -} - -// Indicates that the object binds to the effect no longer exists, without deleting it. - -void CPyro::CutObjectLink(CObject* pObj) -{ - if ( m_object == pObj ) - { - m_object = 0; - } -} - -// Indicates whether the pyrotechnic effect is complete. - -Error CPyro::IsEnded() -{ - // Destroys the object that exploded. - //It should not be destroyed at the end of the Create, - //because it is sometimes the object itself that makes the Create: - // pyro->Create(PT_FRAGT, this); - if ( m_type == PT_FRAGT || - m_type == PT_FRAGO || - m_type == PT_FRAGW || - m_type == PT_SPIDER || - m_type == PT_EGG ) - { - DeleteObject(true, true); - } - - if ( m_type == PT_FALL ) // freight which grave? - { - return FallIsEnded(); - } - - if ( m_type == PT_WIN || - m_type == PT_LOST ) - { - return ERR_CONTINUE; - } - - // End of the pyrotechnic effect? - if ( m_progress < 1.0f ) return ERR_CONTINUE; - - if ( m_type == PT_EXPLOT || - m_type == PT_EXPLOO || - m_type == PT_EXPLOW ) // explosion? - { - ExploTerminate(); - } - - if ( m_type == PT_BURNT || - m_type == PT_BURNO ) // burning? - { - BurnTerminate(); - } - - if ( m_type == PT_WPCHECK || - m_type == PT_FLDELETE ) - { - DeleteObject(true, true); - } - - if ( m_type == PT_FLCREATE ) - { - m_object->SetAngleX(0, 0.0f); - m_object->SetAngleZ(0, 0.0f); - m_object->SetZoom(0, 1.0f); - } - - if ( m_type == PT_RESET ) - { - m_object->SetPosition(0, m_object->RetResetPosition()); - m_object->SetAngle(0, m_object->RetResetAngle()); - m_object->SetZoom(0, 1.0f); - } - - if ( m_lightRank != -1 ) - { - m_light->DeleteLight(m_lightRank); - m_lightRank = -1; - } - - return ERR_STOP; -} - -// Removes the binding to a pyrotechnic effect. - -void CPyro::DeleteObject(bool bPrimary, bool bSecondary) -{ - CObject *sub, *truck; - Math::Vector pos; - ObjectType type; - - if ( m_object == 0 ) return; - - if ( m_object->RetResetCap() == RESET_MOVE ) // resettable object? - { - m_object->SetEnable(false); // object cache and inactive - pos = m_object->RetPosition(0); - pos.y = -100.0f; - m_object->SetPosition(0, pos); - return; - } - - type = m_object->RetType(); - if ( bSecondary && - type != OBJECT_FACTORY && - type != OBJECT_NUCLEAR && - type != OBJECT_ENERGY ) - { - sub = m_object->RetPower(); - if ( sub != 0 ) - { - sub->DeleteObject(); // removes the battery - delete sub; - m_object->SetPower(0); - } - - sub = m_object->RetFret(); - if ( sub != 0 ) - { - sub->DeleteObject(); // removes the object transported - delete sub; - m_object->SetFret(0); - } - } - - if ( bPrimary ) - { - truck = m_object->RetTruck(); - if ( truck != 0 ) // object carries? - { - if ( truck->RetPower() == m_object ) - { - truck->SetPower(0); - } - if ( truck->RetFret() == m_object ) - { - truck->SetFret(0); - } - } - - sub = m_object; - sub->DeleteObject(); // removes the object (*) - delete sub; - m_object = 0; - } -} - -// (*) CObject :: DeleteObject can reset m_object through CPyro :: CutObjectLink! - - -// Empty the table of operations of animation of light. - -void CPyro::LightOperFlush() -{ - m_lightOperTotal = 0; -} - -// Adds an animation operation of the light. - -void CPyro::LightOperAdd(float progress, float intensity, - float r, float g, float b) -{ - int i; - - i = m_lightOperTotal; - - m_lightOper[i].progress = progress; - m_lightOper[i].intensity = intensity; - m_lightOper[i].color.r = r; - m_lightOper[i].color.g = g; - m_lightOper[i].color.b = b; - - m_lightOperTotal ++; -} - -// Makes evolve the associated light. - -void CPyro::LightOperFrame(float rTime) -{ - D3DCOLORVALUE color; - float progress, intensity; - int i; - - for ( i=0 ; iSetLightIntensity(m_lightRank, intensity); - m_light->SetLightColor(m_lightRank, color); - break; - } - } -} - - -// Creates light to accompany a pyrotechnic effect. - -bool CPyro::CreateLight(Math::Vector pos, float height) -{ - D3DLIGHT7 light; - - if ( !m_engine->RetLightMode() ) return true; - - m_lightHeight = height; - - ZeroMemory( &light, sizeof(light) ); - light.dltType = D3DLIGHT_SPOT; - light.dvPosition.x = pos.x; - light.dvPosition.y = pos.y+height; - light.dvPosition.z = pos.z; - light.dvDirection.x = 0.0f; - light.dvDirection.y = -1.0f; // against the bottom - light.dvDirection.z = 0.0f; - light.dvRange = D3DLIGHT_RANGE_MAX; - light.dvFalloff = 1.0f; - light.dvAttenuation0 = 1.0f; - light.dvAttenuation1 = 0.0f; - light.dvAttenuation2 = 0.0f; - light.dvTheta = 0.0f; - light.dvPhi = Math::PI/4.0f; - - m_lightRank = m_light->CreateLight(); - if ( m_lightRank == -1 ) return false; - - m_light->SetLight(m_lightRank, light); - m_light->SetLightIntensity(m_lightRank, 0.0f); - - // Only illuminates the objects on the ground. - m_light->SetLightIncluType(m_lightRank, TYPETERRAIN); - - return true; -} - - -// Starts the explosion of a vehicle. - -void CPyro::ExploStart() -{ - Math::Vector pos, angle, speed, min, max; - float weight; - int i, objRank, channel; - - m_burnType = m_object->RetType(); - - pos = m_object->RetPosition(0); - m_burnFall = m_terrain->RetFloorHeight(pos, true); - - m_object->Simplify(); - m_object->SetLock(true); // ruin not usable yet - m_object->SetExplo(true); // being destroyed - m_object->FlatParent(); - - if ( m_object->RetSelect() ) - { - m_object->SetSelect(false); // deselects the object - m_camera->SetType(CAMERA_EXPLO); - m_main->DeselectAll(); - } - m_object->DeleteDeselList(m_object); - - for ( i=0 ; iRetObjectRank(i); - if ( objRank == -1 ) continue; - m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); - - pos = m_object->RetPosition(i); - - if ( i == 0 ) // main part? - { - weight = 0.0f; - - speed.y = -1.0f; - speed.x = 0.0f; - speed.z = 0.0f; - } - else - { - m_engine->GetBBox(objRank, min, max); - weight = Math::Distance(min, max); // weight according to size! - - speed.y = 10.0f+Math::Rand()*20.0f; - speed.x = (Math::Rand()-0.5f)*20.0f; - speed.z = (Math::Rand()-0.5f)*20.0f; - } - - channel = m_particule->CreatePart(pos, speed, PARTIPART, 10.0f, 20.0f, weight, 0.5f); - if ( channel != -1 ) - { - m_object->SetMasterParticule(i, channel); - } - } - m_engine->LoadTexture("dirty04.tga", 1); - - DeleteObject(false, true); // destroys the object transported + the battery -} - -// Ends the explosion of a vehicle. - -void CPyro::ExploTerminate() -{ - DeleteObject(true, false); // removes the main object -} - - -// Starts a vehicle fire. - -void CPyro::BurnStart() -{ - Math::Vector pos, angle; - int i, objRank; - - m_burnType = m_object->RetType(); - - pos = m_object->RetPosition(0); - m_burnFall = m_terrain->RetFloorHeight(pos, true); - - m_object->Simplify(); - m_object->SetLock(true); // ruin not usable yet - - if ( m_object->RetSelect() ) - { - m_object->SetSelect(false); // deselects the object - m_camera->SetType(CAMERA_EXPLO); - m_main->DeselectAll(); - } - m_object->DeleteDeselList(m_object); - - for ( i=0 ; iRetObjectRank(i); - if ( objRank == -1 ) continue; - m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); - } - m_engine->LoadTexture("dirty04.tga", 1); - - m_burnPartTotal = 0; - - if ( m_burnType == OBJECT_DERRICK || - m_burnType == OBJECT_FACTORY || - m_burnType == OBJECT_REPAIR || - m_burnType == OBJECT_DESTROYER|| - m_burnType == OBJECT_CONVERT || - m_burnType == OBJECT_TOWER || - m_burnType == OBJECT_RESEARCH || - m_burnType == OBJECT_ENERGY || - m_burnType == OBJECT_LABO ) - { - pos.x = 0.0f; - pos.y = -(4.0f+Math::Rand()*4.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_STATION || - m_burnType == OBJECT_RADAR || - m_burnType == OBJECT_INFO ) - { - pos.x = 0.0f; - pos.y = -(1.0f+Math::Rand()*1.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.2f; - } - else if ( m_burnType == OBJECT_NUCLEAR ) - { - pos.x = 0.0f; - pos.y = -(10.0f+Math::Rand()*10.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_PARA ) - { - pos.x = 0.0f; - pos.y = -(10.0f+Math::Rand()*10.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_SAFE ) - { - pos.x = 0.0f; - pos.y = -(10.0f+Math::Rand()*10.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_HUSTON ) - { - pos.x = 0.0f; - pos.y = -(10.0f+Math::Rand()*10.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_MOBILEwa || - m_burnType == OBJECT_MOBILEwc || - m_burnType == OBJECT_MOBILEwi || - m_burnType == OBJECT_MOBILEws || - m_burnType == OBJECT_MOBILEwt ) - { - pos.x = 0.0f; - pos.y = -(0.5f+Math::Rand()*1.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.8f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.4f; - } - else if ( m_burnType == OBJECT_TEEN31 ) // basket? - { - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.8f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.2f; - } - else - { - pos.x = 0.0f; - pos.y = -(2.0f+Math::Rand()*2.0f); - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.8f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*0.8f; - } - BurnAddPart(0, pos, angle); // movement of the main part - - m_burnKeepPart[0] = -1; // nothing to keep - - if ( m_burnType == OBJECT_DERRICK ) - { - pos.x = 0.0f; - pos.y = -40.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the drill - } - - if ( m_burnType == OBJECT_REPAIR ) - { - pos.x = 0.0f; - pos.y = -12.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = -90.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the sensor - } - - if ( m_burnType == OBJECT_DESTROYER ) - { - pos.x = 0.0f; - pos.y = -12.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = -90.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the sensor - } - - if ( m_burnType == OBJECT_CONVERT ) - { - pos.x = 0.0f; - pos.y = -200.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.5f; - angle.y = (Math::Rand()-0.5f)*0.5f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the cover - BurnAddPart(2, pos, angle); - BurnAddPart(3, pos, angle); - } - - if ( m_burnType == OBJECT_TOWER ) - { - pos.x = 0.0f; - pos.y = -7.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = (Math::Rand()-0.5f)*0.4f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the cannon - } - - if ( m_burnType == OBJECT_RESEARCH ) - { - pos.x = 0.0f; - pos.y = -7.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the anemometer - } - - if ( m_burnType == OBJECT_RADAR ) - { - pos.x = 0.0f; - pos.y = -14.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = (Math::Rand()-0.5f)*0.4f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the radar - BurnAddPart(2, pos, angle); - } - - if ( m_burnType == OBJECT_INFO ) - { - pos.x = 0.0f; - pos.y = -14.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.4f; - angle.y = (Math::Rand()-0.5f)*0.4f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the information terminal - BurnAddPart(2, pos, angle); - } - - if ( m_burnType == OBJECT_LABO ) - { - pos.x = 0.0f; - pos.y = -12.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the arm - } - - if ( m_burnType == OBJECT_NUCLEAR ) - { - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = -135.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the cover - } - - if ( m_burnType == OBJECT_MOBILEfa || - m_burnType == OBJECT_MOBILEta || - m_burnType == OBJECT_MOBILEwa || - m_burnType == OBJECT_MOBILEia ) - { - pos.x = 2.0f; - pos.y = -5.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = 40.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the arm - } - - if ( m_burnType == OBJECT_MOBILEfs || - m_burnType == OBJECT_MOBILEts || - m_burnType == OBJECT_MOBILEws || - m_burnType == OBJECT_MOBILEis ) - { - pos.x = 0.0f; - pos.y = -7.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = 50.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the sensor - } - - if ( m_burnType == OBJECT_MOBILEfc || - m_burnType == OBJECT_MOBILEtc || - m_burnType == OBJECT_MOBILEwc || - m_burnType == OBJECT_MOBILEic ) - { - pos.x = -1.5f; - pos.y = -5.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = -25.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the cannon - } - - if ( m_burnType == OBJECT_MOBILEfi || - m_burnType == OBJECT_MOBILEti || - m_burnType == OBJECT_MOBILEwi || - m_burnType == OBJECT_MOBILEii ) - { - pos.x = -1.5f; - pos.y = -5.0f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*0.2f; - angle.y = (Math::Rand()-0.5f)*0.2f; - angle.z = -25.0f*Math::PI/180.0f; - BurnAddPart(1, pos, angle); // down the insect-cannon - } - - if ( m_burnType == OBJECT_MOBILErt || - m_burnType == OBJECT_MOBILErc ) - { - pos.x = 0.0f; - pos.y = -10.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the holder - - pos.x = 0.0f; - pos.y = -10.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(2, pos, angle); // down the pestle/cannon - } - - if ( m_burnType == OBJECT_MOBILErr ) - { - pos.x = 0.0f; - pos.y = -10.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the holder - - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = -Math::PI/2.0f; - BurnAddPart(4, pos, angle); - - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = Math::PI/2.5f; - BurnAddPart(2, pos, angle); - } - - if ( m_burnType == OBJECT_MOBILErs ) - { - pos.x = 0.0f; - pos.y = -10.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the holder - - pos.x = 0.0f; - pos.y = -5.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(2, pos, angle); - - pos.x = 0.0f; - pos.y = -5.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(3, pos, angle); - } - - if ( m_burnType == OBJECT_MOBILEsa ) - { - pos.x = 0.0f; - pos.y = -10.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = 0.0f; - BurnAddPart(1, pos, angle); // down the holder - } - - if ( m_burnType == OBJECT_MOBILEwa || - m_burnType == OBJECT_MOBILEwc || - m_burnType == OBJECT_MOBILEwi || - m_burnType == OBJECT_MOBILEws || - m_burnType == OBJECT_MOBILEwt ) // wheels? - { - for ( i=0 ; i<4 ; i++ ) - { - pos.x = 0.0f; - pos.y = Math::Rand()*0.5f; - pos.z = 0.0f; - angle.x = (Math::Rand()-0.5f)*Math::PI/2.0f; - angle.y = (Math::Rand()-0.5f)*Math::PI/2.0f; - angle.z = 0.0f; - BurnAddPart(6+i, pos, angle); // wheel - - m_burnKeepPart[i] = 6+i; // we keep the wheels - } - m_burnKeepPart[i] = -1; - } - - if ( m_burnType == OBJECT_MOBILEta || - m_burnType == OBJECT_MOBILEtc || - m_burnType == OBJECT_MOBILEti || - m_burnType == OBJECT_MOBILEts || - m_burnType == OBJECT_MOBILErt || - m_burnType == OBJECT_MOBILErc || - m_burnType == OBJECT_MOBILErr || - m_burnType == OBJECT_MOBILErs || - m_burnType == OBJECT_MOBILEsa || - m_burnType == OBJECT_MOBILEdr ) // caterpillars? - { - pos.x = 0.0f; - pos.y = -4.0f; - pos.z = 2.0f; - angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f; - angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f; - angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f; - BurnAddPart(6, pos, angle); // down the right caterpillar - - pos.x = 0.0f; - pos.y = -4.0f; - pos.z = -2.0f; - angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f; - angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f; - angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f; - BurnAddPart(7, pos, angle); // down the left caterpillar - } - - if ( m_burnType == OBJECT_MOBILEfa || - m_burnType == OBJECT_MOBILEfc || - m_burnType == OBJECT_MOBILEfi || - m_burnType == OBJECT_MOBILEfs || - m_burnType == OBJECT_MOBILEft ) // flying? - { - for ( i=0 ; i<3 ; i++ ) - { - pos.x = 0.0f; - pos.y = -3.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = 0.0f; - angle.z = (Math::Rand()-0.5f)*Math::PI/2.0f; - BurnAddPart(6+i, pos, angle); // foot - } - m_burnKeepPart[i] = -1; - } - - if ( m_burnType == OBJECT_MOBILEia || - m_burnType == OBJECT_MOBILEic || - m_burnType == OBJECT_MOBILEii || - m_burnType == OBJECT_MOBILEis ) // legs? - { - for ( i=0 ; i<6; i++ ) - { - pos.x = 0.0f; - pos.y = -3.0f; - pos.z = 0.0f; - angle.x = 0.0f; - angle.y = (Math::Rand()-0.5f)*Math::PI/4.0f; - angle.z = (Math::Rand()-0.5f)*Math::PI/4.0f; - BurnAddPart(6+i, pos, angle); // leg - } - } -} - -// Adds a part move. - -void CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle) -{ - int i; - - i = m_burnPartTotal; - m_burnPart[i].part = part; - m_burnPart[i].initialPos = m_object->RetPosition(part); - m_burnPart[i].finalPos = m_burnPart[i].initialPos+pos; - m_burnPart[i].initialAngle = m_object->RetAngle(part); - m_burnPart[i].finalAngle = m_burnPart[i].initialAngle+angle; - - m_burnPartTotal ++; -} - -// Advances of a vehicle fire. - -void CPyro::BurnProgress() -{ - CObject* sub; - Math::Vector pos; - float h; - int i; - - if ( m_burnType == OBJECT_TEEN31 ) // basket? - { - m_object->SetZoomY(0, 1.0f-m_progress*0.5f); // slight flattening - } - - for ( i=0 ; i 0.0f ) - { - h = powf(m_progress, 2.0f)*1000.0f; - if ( h > m_burnFall ) h = m_burnFall; - pos.y -= h; - } - m_object->SetPosition(m_burnPart[i].part, pos); - - pos = m_burnPart[i].initialAngle + m_progress*(m_burnPart[i].finalAngle-m_burnPart[i].initialAngle); - m_object->SetAngle(m_burnPart[i].part, pos); - } - - sub = m_object->RetPower(); - if ( sub != 0 ) // is there a battery? - { - sub->SetZoomY(0, 1.0f-m_progress); // complete flattening - } -} - -// Indicates whether a part should be retained. - -bool CPyro::BurnIsKeepPart(int part) -{ - int i; - - i = 0; - while ( m_burnKeepPart[i] != -1 ) - { - if ( part == m_burnKeepPart[i++] ) return true; // must keep - } - return false; // must destroy -} - -// Ends the fire of an insect or a vehicle. - -void CPyro::BurnTerminate() -{ - int i, objRank; - - if ( m_type == PT_BURNO ) // organic object is burning? - { - DeleteObject(true, true); // removes the insect - return; - } - - for ( i=1 ; iRetObjectRank(i); - if ( objRank == -1 ) continue; - if ( BurnIsKeepPart(i) ) continue; - - m_object->DeletePart(i); - } - - DeleteObject(false, true); // destroys the object transported + the battery - - if ( m_burnType == OBJECT_DERRICK || - m_burnType == OBJECT_STATION || - m_burnType == OBJECT_FACTORY || - m_burnType == OBJECT_REPAIR || - m_burnType == OBJECT_DESTROYER|| - m_burnType == OBJECT_CONVERT || - m_burnType == OBJECT_TOWER || - m_burnType == OBJECT_RESEARCH || - m_burnType == OBJECT_RADAR || - m_burnType == OBJECT_INFO || - m_burnType == OBJECT_ENERGY || - m_burnType == OBJECT_LABO || - m_burnType == OBJECT_NUCLEAR || - m_burnType == OBJECT_PARA || - m_burnType == OBJECT_SAFE || - m_burnType == OBJECT_HUSTON || - m_burnType == OBJECT_START || - m_burnType == OBJECT_END ) - { - m_object->SetType(OBJECT_RUINfactory); // others become a ruin - m_object->SetLock(false); - } - else - { - m_object->SetType(OBJECT_RUINmobilew1); // others become a ruin - m_object->SetLock(false); - } - - m_object->SetBurn(false); // ruin usable (c-e-d. recoverable) -} - - -// Start of an object freight falling. - -void CPyro::FallStart() -{ - Math::Vector pos; - - m_object->SetBurn(true); // usable - - pos = m_object->RetPosition(0); - m_fallFloor = m_terrain->RetFloorLevel(pos); - m_fallSpeed = 0.0f; - m_fallBulletTime = 0.0f; - m_bFallEnding = false; -} - -// Seeking an object explode by the falling ball of bees. - -CObject* CPyro::FallSearchBeeExplo() -{ - CObject* pObj; - Math::Vector iPos, oPos; - ObjectType oType; - float iRadius, oRadius, distance, shieldRadius; - int i, j; - - m_object->GetCrashSphere(0, iPos, iRadius); - - for ( i=0 ; i<1000000 ; i++ ) - { - pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); - if ( pObj == 0 ) break; - - oType = pObj->RetType(); - if ( oType != OBJECT_HUMAN && - oType != OBJECT_MOBILEfa && - oType != OBJECT_MOBILEta && - oType != OBJECT_MOBILEwa && - oType != OBJECT_MOBILEia && - oType != OBJECT_MOBILEfc && - oType != OBJECT_MOBILEtc && - oType != OBJECT_MOBILEwc && - oType != OBJECT_MOBILEic && - oType != OBJECT_MOBILEfi && - oType != OBJECT_MOBILEti && - oType != OBJECT_MOBILEwi && - oType != OBJECT_MOBILEii && - oType != OBJECT_MOBILEfs && - oType != OBJECT_MOBILEts && - oType != OBJECT_MOBILEws && - oType != OBJECT_MOBILEis && - oType != OBJECT_MOBILErt && - oType != OBJECT_MOBILErc && - oType != OBJECT_MOBILErr && - oType != OBJECT_MOBILErs && - oType != OBJECT_MOBILEsa && - oType != OBJECT_MOBILEtg && - oType != OBJECT_MOBILEft && - oType != OBJECT_MOBILEtt && - oType != OBJECT_MOBILEwt && - oType != OBJECT_MOBILEit && - oType != OBJECT_MOBILEdr && - oType != OBJECT_BASE && - oType != OBJECT_DERRICK && - oType != OBJECT_STATION && - oType != OBJECT_FACTORY && - oType != OBJECT_REPAIR && - oType != OBJECT_DESTROYER&& - oType != OBJECT_CONVERT && - oType != OBJECT_TOWER && - oType != OBJECT_RESEARCH && - oType != OBJECT_RADAR && - oType != OBJECT_INFO && - oType != OBJECT_ENERGY && - oType != OBJECT_LABO && - oType != OBJECT_NUCLEAR && - oType != OBJECT_PARA && - oType != OBJECT_SAFE && - oType != OBJECT_HUSTON && - oType != OBJECT_METAL && - oType != OBJECT_POWER && - oType != OBJECT_ATOMIC ) continue; - - if ( pObj->RetTruck() != 0 ) continue; // object transported? - - oPos = pObj->RetPosition(0); - - shieldRadius = pObj->RetShieldRadius(); - if ( shieldRadius > 0.0f ) - { - distance = Math::Distance(oPos, iPos); - if ( distance <= shieldRadius ) return pObj; - } - - if ( oType == OBJECT_BASE ) - { - distance = Math::Distance(oPos, iPos); - if ( distance < 25.0f ) return pObj; - } - - // Test the center of the object, which is necessary for objects - // that have no sphere in the center (station). - distance = Math::Distance(oPos, iPos)-4.0f; - if ( distance < 5.0f ) return pObj; - - // Test with all spheres of the object. - j = 0; - while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) - { - distance = Math::Distance(oPos, iPos); - if ( distance <= iRadius+oRadius ) - { - return pObj; - } - } - } - return 0; -} - -// Fall of an object's freight. - -void CPyro::FallProgress(float rTime) -{ - CObject* pObj; - Math::Vector pos; - bool bFloor = false; - - if ( m_object == 0 ) return; - - m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt - pos = m_object->RetPosition(0); - pos.y -= m_fallSpeed*rTime; // dd -= v2*dt - - if ( pos.y <= m_fallFloor ) // below the ground level? - { - pos.y = m_fallFloor; - bFloor = true; - } - m_object->SetPosition(0, pos); - - if ( m_object->RetType() == OBJECT_BULLET ) - { - m_fallBulletTime += rTime; - - if ( m_fallBulletTime > 0.2f || bFloor ) - { - m_fallBulletTime = 0.0f; - - pObj = FallSearchBeeExplo(); - if ( pObj == 0 ) - { - if ( bFloor ) // reaches the ground? - { - m_object->ExploObject(EXPLO_BOUM, 0.0f); // start explosion - } - } - else - { - if ( pObj->RetShieldRadius() > 0.0f ) // protected by shield? - { - m_particule->CreateParticule(pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f); - m_sound->Play(SOUND_GUNDEL); - - DeleteObject(true, true); // removes the ball - } - else - { - if ( pObj->ExploObject(EXPLO_BOUM, 1.0f) ) // start explosion - { - DeleteObject(true, true); // removes the ball - } - else - { - m_object->ExploObject(EXPLO_BOUM, 0.0f); // start explosion - } - } - } - - if ( bFloor || pObj != 0 ) - { - m_bFallEnding = true; - } - } - } -} - -// Indicates whether the fall is over. - -Error CPyro::FallIsEnded() -{ - Math::Vector pos; - - if ( m_bFallEnding || m_object == 0 ) return ERR_STOP; - - pos = m_object->RetPosition(0); - if ( pos.y > m_fallFloor ) return ERR_CONTINUE; - - m_sound->Play(SOUND_BOUM, pos); - m_object->SetBurn(false); // usable again - - return ERR_STOP; -} - +// * 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/. + +// pyro.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "object/robotmain.h" +#include "old/terrain.h" +#include "old/camera.h" +#include "old/particule.h" +#include "old/light.h" +#include "object/object.h" +#include "object/motion/motion.h" +#include "object/motion/motionhuman.h" +#include "ui/displaytext.h" +#include "old/sound.h" +#include "old/pyro.h" + + + + +// Object's constructor. + +CPyro::CPyro(CInstanceManager* iMan) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_PYRO, this, 100); + + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA); + m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); + m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT); + m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT); + m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN); + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + m_object = 0; + + m_progress = 0.0f; + m_speed = 0.0f; + m_lightRank = -1; + m_soundChannel = -1; + LightOperFlush(); +} + +// Object's destructor. + +CPyro::~CPyro() +{ + m_iMan->DeleteInstance(CLASS_PYRO, this); +} + + +// Destroys the object. + +void CPyro::DeleteObject(bool bAll) +{ + if ( m_lightRank != -1 ) + { + m_light->DeleteLight(m_lightRank); + m_lightRank = -1; + } +} + + +// Creates pyrotechnic effect. + +bool CPyro::Create(PyroType type, CObject* pObj, float force) +{ + Math::Matrix* mat; + CObject* power; + CMotion* motion; + Math::Vector min, max, pos, speed; + Math::Point dim; + ObjectType oType; + Sound sound; + float duration, mass, h, limit; + int part, objRank, total, i, channel; + + m_object = pObj; + m_force = force; + + oType = pObj->RetType(); + objRank = pObj->RetObjectRank(0); + if ( objRank == -1 ) return false; + m_engine->GetBBox(objRank, min, max); + pos = pObj->RetPosition(0); + + DisplayError(type, pObj); // displays eventual messages + + // Copies all spheres of the object. + for ( i=0 ; i<50 ; i++ ) + { + if ( !pObj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break; + } + m_crashSphereUsed = i; + + // Calculates the size of the effect. + if ( oType == OBJECT_ANT || + oType == OBJECT_BEE || + oType == OBJECT_WORM || + oType == OBJECT_SPIDER ) + { + m_size = 40.0f; + } + else + { + m_size = Math::Distance(min, max)*2.0f; + if ( m_size < 4.0f ) m_size = 4.0f; + if ( m_size > 80.0f ) m_size = 80.0f; + } + if ( oType == OBJECT_TNT || + oType == OBJECT_BOMB ) + { + m_size *= 2.0f; + } + + m_pos = pos+(min+max)/2.0f; + m_type = type; + m_progress = 0.0f; + m_speed = 1.0f/20.0f; + m_time = 0.0f; + m_lastParticule = 0.0f; + m_lastParticuleSmoke = 0.0f; + m_lightRank = -1; + + if ( oType == OBJECT_TEEN28 || + oType == OBJECT_TEEN31 ) + { + m_pos.y = pos.y+1.0f; + } + + // Seeking the position of the battery. + power = pObj->RetPower(); + if ( power == 0 ) + { + m_bPower = false; + } + else + { + m_bPower = true; + pos = power->RetPosition(0); + pos.y += 1.0f; + mat = pObj->RetWorldMatrix(0); + m_posPower = Math::Transform(*mat, pos); + } + if ( oType == OBJECT_POWER || + oType == OBJECT_ATOMIC || + oType == OBJECT_URANIUM || + oType == OBJECT_TNT || + oType == OBJECT_BOMB ) + { + m_bPower = true; + m_posPower = m_pos; + m_posPower.y += 1.0f; + m_pos = m_posPower; + } + if ( oType == OBJECT_STATION ) + { + m_bPower = true; + mat = pObj->RetWorldMatrix(0); + m_posPower = Math::Transform(*mat, Math::Vector(-15.0f, 7.0f, 0.0f)); + m_pos = m_posPower; + } + if ( oType == OBJECT_ENERGY ) + { + m_bPower = true; + mat = pObj->RetWorldMatrix(0); + m_posPower = Math::Transform(*mat, Math::Vector(-7.0f, 6.0f, 0.0f)); + m_pos = m_posPower; + } + if ( oType == OBJECT_NUCLEAR ) + { + m_bPower = true; + m_posPower = m_pos; + } + if ( oType == OBJECT_PARA ) + { + m_bPower = true; + m_posPower = m_pos; + } + if ( oType == OBJECT_SCRAP4 || + oType == OBJECT_SCRAP5 ) // plastic material? + { + m_bPower = true; + m_posPower = m_pos; + } + + // Plays the sound of a pyrotechnic effect. + if ( type == PT_FRAGT || + type == PT_FRAGW || + type == PT_EXPLOT || + type == PT_EXPLOW ) + { + if ( m_bPower ) + { + sound = SOUND_EXPLOp; + } + else + { + sound = SOUND_EXPLO; + } + if ( oType == OBJECT_STONE || + oType == OBJECT_METAL || + oType == OBJECT_BULLET || + oType == OBJECT_BBOX || + oType == OBJECT_KEYa || + oType == OBJECT_KEYb || + oType == OBJECT_KEYc || + oType == OBJECT_KEYd ) + { + sound = SOUND_EXPLOl; + } + if ( oType == OBJECT_URANIUM || + oType == OBJECT_POWER || + oType == OBJECT_ATOMIC || + oType == OBJECT_TNT || + oType == OBJECT_BOMB ) + { + sound = SOUND_EXPLOlp; + } + m_sound->Play(sound, m_pos); + } + if ( type == PT_FRAGO || + type == PT_EXPLOO || + type == PT_SPIDER || + type == PT_SHOTM ) + { + m_sound->Play(SOUND_EXPLOi, m_pos); + } + if ( type == PT_BURNT || + type == PT_BURNO ) + { + m_soundChannel = m_sound->Play(SOUND_BURN, m_pos, 1.0f, 1.0f, true); + m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 12.0f, SOPER_CONTINUE); + m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 5.0f, SOPER_STOP); + } + if ( type == PT_BURNO ) + { + m_sound->Play(SOUND_DEADi, m_pos); + m_sound->Play(SOUND_DEADi, m_engine->RetEyePt()); + } + if ( type == PT_EGG ) + { + m_sound->Play(SOUND_EGG, m_pos); + } + if ( type == PT_WPCHECK || + type == PT_FLCREATE || + type == PT_FLDELETE ) + { + m_sound->Play(SOUND_WAYPOINT, m_pos); + } + if ( oType == OBJECT_HUMAN ) + { + if ( type == PT_DEADG ) + { + m_sound->Play(SOUND_DEADg, m_pos); + } + if ( type == PT_DEADW ) + { + m_sound->Play(SOUND_DEADw, m_pos); + } + if ( type == PT_SHOTH && m_object->RetSelect() ) + { + m_sound->Play(SOUND_AIE, m_pos); + m_sound->Play(SOUND_AIE, m_engine->RetEyePt()); + } + } + + if ( m_type == PT_FRAGT || + m_type == PT_FRAGO || + m_type == PT_FRAGW ) + { + m_engine->ShadowDelete(m_object->RetObjectRank(0)); + } + + if ( m_type == PT_DEADG ) + { + m_object->SetDead(true); + + motion = m_object->RetMotion(); + if ( motion != 0 ) + { + motion->SetAction(MHS_DEADg, 1.0f); + } + m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 1.5f); + m_camera->StartOver(OE_FADEOUTw, m_pos, 1.0f); + m_speed = 1.0f/10.0f; + return true; + } + if ( m_type == PT_DEADW ) + { + m_object->SetDead(true); + + motion = m_object->RetMotion(); + if ( motion != 0 ) + { + motion->SetAction(MHS_DEADw, 4.0f); + } + m_camera->StartCentering(m_object, Math::PI*0.5f, 99.9f, 0.0f, 3.0f); + m_camera->StartOver(OE_FADEOUTb, m_pos, 1.0f); + m_speed = 1.0f/10.0f; + return true; + } + + if ( m_type == PT_SHOTT || + m_type == PT_SHOTM ) + { + m_camera->StartEffect(CE_SHOT, m_pos, force); + m_speed = 1.0f/1.0f; + return true; + } + if ( m_type == PT_SHOTH ) + { + if ( m_object->RetSelect() ) + { + m_camera->StartOver(OE_BLOOD, m_pos, force); + } + m_speed = 1.0f/0.2f; + return true; + } + + if ( m_type == PT_SHOTW ) + { + m_speed = 1.0f/1.0f; + } + + if ( m_type == PT_BURNT ) + { + BurnStart(); + } + + if ( m_type == PT_WPCHECK ) + { + m_speed = 1.0f/8.0f; + m_object->SetEnable(false); // object more functional + } + if ( m_type == PT_FLCREATE ) + { + m_speed = 1.0f/2.0f; + } + if ( m_type == PT_FLDELETE ) + { + m_speed = 1.0f/2.0f; + m_object->SetEnable(false); // object more functional + } + if ( m_type == PT_RESET ) + { + m_speed = 1.0f/2.0f; + m_object->SetPosition(0, m_object->RetResetPosition()); + m_object->SetAngle(0, m_object->RetResetAngle()); + m_object->SetZoom(0, 0.0f); + } + if ( m_type == PT_FINDING ) + { + limit = (m_size-1.0f)/4.0f; + if ( limit > 8.0f ) limit = 8.0f; + if ( oType == OBJECT_APOLLO2 ) limit = 2.0f; + m_speed = 1.0f/limit; + } + + if ( m_type == PT_EXPLOT || + m_type == PT_EXPLOO || + m_type == PT_EXPLOW ) + { + CreateTriangle(pObj, oType, 0); + m_engine->ShadowDelete(m_object->RetObjectRank(0)); + ExploStart(); + } + + if ( m_type == PT_FALL ) + { + FallStart(); + return true; + } + + if ( m_type == PT_BURNT || + m_type == PT_BURNO ) + { + m_speed = 1.0f/15.0f; + + LightOperAdd(0.00f, 0.0f, 2.0f, 1.0f, 0.0f); // red-orange + LightOperAdd(0.30f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray + LightOperAdd(0.80f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray + LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray + CreateLight(m_pos, 40.0f); + return true; + } + + if ( m_type == PT_SPIDER ) + { + m_speed = 1.0f/15.0f; + + pos = Math::Vector(-3.0f, 2.0f, 0.0f); + mat = pObj->RetWorldMatrix(0); + m_pos = Math::Transform(*mat, pos); + + m_engine->ShadowDelete(m_object->RetObjectRank(0)); + } + + if ( m_type != PT_EGG && + m_type != PT_WIN && + m_type != PT_LOST ) + { + h = 40.0f; + if ( m_type == PT_FRAGO || + m_type == PT_EXPLOO ) + { + LightOperAdd(0.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green + LightOperAdd(0.05f, 1.0f, -1.0f, -0.5f, -1.0f); // dark green + LightOperAdd(1.00f, 0.0f, -1.0f, -0.5f, -1.0f); // dark green + } + else if ( m_type == PT_FRAGT || + m_type == PT_EXPLOT ) + { + LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow + LightOperAdd(0.02f, 1.0f, 4.0f, 2.0f, 0.0f); // red-orange + LightOperAdd(0.16f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray + LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray + h = m_size*2.0f; + } + else if ( m_type == PT_SPIDER ) + { + LightOperAdd(0.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red + LightOperAdd(0.05f, 1.0f, -0.5f, -1.0f, -1.0f); // dark red + LightOperAdd(1.00f, 0.0f, -0.5f, -1.0f, -1.0f); // dark red + } + else if ( m_type == PT_FRAGW || + m_type == PT_EXPLOW || + m_type == PT_SHOTW ) + { + LightOperAdd(0.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow + LightOperAdd(0.05f, 1.0f, -0.5f, -0.5f, -1.0f); // dark yellow + LightOperAdd(1.00f, 0.0f, -0.5f, -0.5f, -1.0f); // dark yellow + } + else if ( m_type == PT_WPCHECK || + m_type == PT_FLCREATE || + m_type == PT_FLDELETE || + m_type == PT_RESET || + m_type == PT_FINDING ) + { + LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // yellow + LightOperAdd(1.00f, 0.0f, 4.0f, 4.0f, 2.0f); // yellow + } + else + { + LightOperAdd(0.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray + LightOperAdd(0.05f, 1.0f, -0.8f, -0.8f, -0.8f); // dark gray + LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // dark gray + } + CreateLight(m_pos, h); + + if ( m_type != PT_SHOTW && + m_type != PT_WPCHECK && + m_type != PT_FLCREATE && + m_type != PT_FLDELETE && + m_type != PT_RESET && + m_type != PT_FINDING ) + { + m_camera->StartEffect(CE_EXPLO, m_pos, force); + } + } + + if ( m_type == PT_SHOTW ) return true; + + // Generates the triangles of the explosion. + if ( m_type == PT_FRAGT || + m_type == PT_FRAGO || + m_type == PT_FRAGW || + m_type == PT_SPIDER || + m_type == PT_EGG || + (m_type == PT_EXPLOT && oType == OBJECT_MOBILEtg) || + (m_type == PT_EXPLOT && oType == OBJECT_TEEN28 ) || + (m_type == PT_EXPLOT && oType == OBJECT_TEEN31 ) ) + { + for ( part=0 ; partRetParticuleDensity()); + if ( oType == OBJECT_TNT || + oType == OBJECT_BOMB ) total *= 3; + for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK1, + duration, mass, Math::Rand()+0.7f, 1.0f); + } + } + + if ( m_size > 10.0f ) // large enough (freight excluded)? + { + if ( m_bPower ) + { + pos = m_posPower; + } + else + { + pos = m_pos; + m_terrain->MoveOnFloor(pos); + pos.y += 1.0f; + } + dim.x = m_size*0.4f; + dim.y = dim.x; + m_particule->CreateParticule(pos, Math::Vector(0.0f,0.0f,0.0f), dim, PARTISPHERE0, 2.0f, 0.0f, 0.0f); + } + } + + if ( m_type == PT_FRAGO || + m_type == PT_EXPLOO ) + { + total = (int)(10.0f*m_engine->RetParticuleDensity()); + for ( i=0 ; iCreateParticule(pos, speed, dim, PARTIORGANIC1, + duration, mass); + } + total = (int)(5.0f*m_engine->RetParticuleDensity()); + for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK4, + duration, mass, duration*0.5f, dim.x*2.0f); + } + } + + if ( m_type == PT_SPIDER ) + { + for ( i=0 ; i<50 ; i++ ) + { + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*3.0f; + pos.z += (Math::Rand()-0.5f)*3.0f; + pos.y += (Math::Rand()-0.5f)*2.0f; + speed.x = (Math::Rand()-0.5f)*24.0f; + speed.z = (Math::Rand()-0.5f)*24.0f; + speed.y = 10.0f+Math::Rand()*10.0f; + dim.x = 1.0f; + dim.y = dim.x; + channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN3, 2.0f+Math::Rand()*2.0f, 10.0f); + m_particule->SetObjectFather(channel, pObj); + } + total = (int)(10.0f*m_engine->RetParticuleDensity()); + for ( i=0 ; iCreateTrack(pos, speed, dim, PARTITRACK3, + 2.0f+Math::Rand()*2.0f, 10.0f, 2.0f, 0.6f); + } + } + + if ( type == PT_FRAGT || + type == PT_FRAGW || + type == PT_EXPLOT || + type == PT_EXPLOW ) + { + if ( m_size > 10.0f || m_bPower ) + { + pos = m_pos; +//? m_terrain->MoveOnFloor(pos); +//? pos.y += 2.0f; + speed = Math::Vector(0.0f, 0.0f, 0.0f); + dim.x = m_size; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTICHOC, 2.0f); + } + } + + return true; +} + +// Creates an explosion with triangular form of particles. + +void CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part) +{ + D3DTriangle buffer[100]; + Math::Matrix* mat; + Math::Vector offset, pos, speed; + float percent, min, max, h, duration, mass; + int objRank, total, i; + + objRank = pObj->RetObjectRank(part); + if ( objRank == -1 ) return; + + min = 0.0f; + max = m_engine->RetLimitLOD(0); + total = m_engine->RetTotalTriangles(objRank); + percent = 0.10f; + if ( total < 50 ) percent = 0.25f; + if ( total < 20 ) percent = 0.50f; + if ( m_type == PT_EGG ) percent = 0.30f; + if ( oType == OBJECT_POWER || + oType == OBJECT_ATOMIC || + oType == OBJECT_URANIUM || + oType == OBJECT_TNT || + oType == OBJECT_BOMB ) percent = 0.75f; + if ( oType == OBJECT_MOBILEtg ) percent = 0.50f; + if ( oType == OBJECT_TEEN28 ) percent = 0.75f; + if ( oType == OBJECT_MOTHER ) max = 1000000.0f; + if ( oType == OBJECT_TEEN28 ) max = 1000000.0f; + if ( oType == OBJECT_TEEN31 ) max = 1000000.0f; + total = m_engine->GetTriangles(objRank, min, max, buffer, 100, percent); + + for ( i=0 ; i 5.0f ) + { + p2.x = p1.x+((p2.x-p1.x)*5.0f/h); + p2.y = p1.y+((p2.y-p1.y)*5.0f/h); + p2.z = p1.z+((p2.z-p1.z)*5.0f/h); + } + + h = Math::Distance(p2, p3); + if ( h > 5.0f ) + { + p3.x = p2.x+((p3.x-p2.x)*5.0f/h); + p3.y = p2.y+((p3.y-p2.y)*5.0f/h); + p3.z = p2.z+((p3.z-p2.z)*5.0f/h); + } + + h = Math::Distance(p3, p1); + if ( h > 5.0f ) + { + p1.x = p3.x+((p1.x-p3.x)*5.0f/h); + p1.y = p3.y+((p1.y-p3.y)*5.0f/h); + p1.z = p3.z+((p1.z-p3.z)*5.0f/h); + } + + buffer[i].triangle[0].x = p1.x; + buffer[i].triangle[0].y = p1.y; + buffer[i].triangle[0].z = p1.z; + buffer[i].triangle[1].x = p2.x; + buffer[i].triangle[1].y = p2.y; + buffer[i].triangle[1].z = p2.z; + buffer[i].triangle[2].x = p3.x; + buffer[i].triangle[2].y = p3.y; + buffer[i].triangle[2].z = p3.z; + + offset.x = (buffer[i].triangle[0].x+buffer[i].triangle[1].x+buffer[i].triangle[2].x)/3.0f; + offset.y = (buffer[i].triangle[0].y+buffer[i].triangle[1].y+buffer[i].triangle[2].y)/3.0f; + offset.z = (buffer[i].triangle[0].z+buffer[i].triangle[1].z+buffer[i].triangle[2].z)/3.0f; + + buffer[i].triangle[0].x -= offset.x; + buffer[i].triangle[1].x -= offset.x; + buffer[i].triangle[2].x -= offset.x; + + buffer[i].triangle[0].y -= offset.y; + buffer[i].triangle[1].y -= offset.y; + buffer[i].triangle[2].y -= offset.y; + + buffer[i].triangle[0].z -= offset.z; + buffer[i].triangle[1].z -= offset.z; + buffer[i].triangle[2].z -= offset.z; + + mat = pObj->RetWorldMatrix(part); + pos = Math::Transform(*mat, offset); + if ( m_type == PT_EGG ) + { + speed.x = (Math::Rand()-0.5f)*10.0f; + speed.z = (Math::Rand()-0.5f)*10.0f; + speed.y = Math::Rand()*15.0f; + mass = Math::Rand()*20.0f+20.0f; + } + else if ( m_type == PT_SPIDER ) + { + speed.x = (Math::Rand()-0.5f)*10.0f; + speed.z = (Math::Rand()-0.5f)*10.0f; + speed.y = Math::Rand()*20.0f; + mass = Math::Rand()*10.0f+15.0f; + } + else + { + speed.x = (Math::Rand()-0.5f)*30.0f; + speed.z = (Math::Rand()-0.5f)*30.0f; + speed.y = Math::Rand()*30.0f; + mass = Math::Rand()*10.0f+15.0f; + } + if ( oType == OBJECT_STONE ) speed *= 0.5f; + if ( oType == OBJECT_URANIUM ) speed *= 0.4f; + duration = Math::Rand()*3.0f+3.0f; + m_particule->CreateFrag(pos, speed, &buffer[i], PARTIFRAG, + duration, mass, 0.5f); + } +} + +// Displays the error or eventual information, +// linked to the destruction of an insect, a vehicle or building. + +void CPyro::DisplayError(PyroType type, CObject* pObj) +{ + ObjectType oType; + Error err; + + oType = pObj->RetType(); + + if ( type == PT_FRAGT || + type == PT_FRAGO || + type == PT_FRAGW || + type == PT_EXPLOT || + type == PT_EXPLOO || + type == PT_EXPLOW || + type == PT_BURNT || + type == PT_BURNO ) + { + err = ERR_OK; + if ( oType == OBJECT_MOTHER ) err = INFO_DELETEMOTHER; + if ( oType == OBJECT_ANT ) err = INFO_DELETEANT; + if ( oType == OBJECT_BEE ) err = INFO_DELETEBEE; + if ( oType == OBJECT_WORM ) err = INFO_DELETEWORM; + if ( oType == OBJECT_SPIDER ) err = INFO_DELETESPIDER; + + if ( oType == OBJECT_MOBILEwa || + oType == OBJECT_MOBILEta || + oType == OBJECT_MOBILEfa || + oType == OBJECT_MOBILEia || + oType == OBJECT_MOBILEwc || + oType == OBJECT_MOBILEtc || + oType == OBJECT_MOBILEfc || + oType == OBJECT_MOBILEic || + oType == OBJECT_MOBILEwi || + oType == OBJECT_MOBILEti || + oType == OBJECT_MOBILEfi || + oType == OBJECT_MOBILEii || + oType == OBJECT_MOBILEws || + oType == OBJECT_MOBILEts || + oType == OBJECT_MOBILEfs || + oType == OBJECT_MOBILEis || + oType == OBJECT_MOBILErt || + oType == OBJECT_MOBILErc || + oType == OBJECT_MOBILErr || + oType == OBJECT_MOBILErs || + oType == OBJECT_MOBILEsa || + oType == OBJECT_MOBILEwt || + oType == OBJECT_MOBILEtt || + oType == OBJECT_MOBILEft || + oType == OBJECT_MOBILEit || + oType == OBJECT_MOBILEdr ) + { + err = ERR_DELETEMOBILE; + } + + if ( oType == OBJECT_DERRICK || + oType == OBJECT_FACTORY || + oType == OBJECT_STATION || + oType == OBJECT_CONVERT || + oType == OBJECT_REPAIR || + oType == OBJECT_DESTROYER|| + oType == OBJECT_TOWER || + oType == OBJECT_RESEARCH || + oType == OBJECT_RADAR || + oType == OBJECT_INFO || + oType == OBJECT_ENERGY || + oType == OBJECT_LABO || + oType == OBJECT_NUCLEAR || + oType == OBJECT_PARA || + oType == OBJECT_SAFE || + oType == OBJECT_HUSTON || + oType == OBJECT_START || + oType == OBJECT_END ) + { + err = ERR_DELETEBUILDING; + m_displayText->DisplayError(err, pObj->RetPosition(0), 5.0f); + return; + } + + if ( err != ERR_OK ) + { + m_displayText->DisplayError(err, pObj); + } + } +} + + +// Management of an event. + +bool CPyro::EventProcess(const Event &event) +{ + ParticuleType type; + Math::Vector pos, speed, angle; + Math::Point dim; + float prog, factor, duration; + int i, r; + + if ( event.event != EVENT_FRAME ) return true; + if ( m_engine->RetPause() ) return true; + + m_time += event.rTime; + m_progress += event.rTime*m_speed; + + if ( m_soundChannel != -1 && m_object != 0 ) + { + pos = m_object->RetPosition(0); + m_sound->Position(m_soundChannel, pos); + + if ( m_lightRank != -1 ) + { + pos.y += m_lightHeight; + m_light->SetLightPos(m_lightRank, pos); + } + } + + if ( m_type == PT_SHOTT && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + if ( m_crashSphereUsed > 0 ) + { + i = rand()%m_crashSphereUsed; + pos = m_crashSpherePos[i]; + pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = Math::Rand()*m_crashSphereRadius[i]*1.0f; + dim.x = Math::Rand()*m_crashSphereRadius[i]*0.5f+m_crashSphereRadius[i]*0.75f*m_force; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f); + } + else + { + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*m_size*0.3f; + pos.z += (Math::Rand()-0.5f)*m_size*0.3f; + speed.x = (Math::Rand()-0.5f)*m_size*0.1f; + speed.z = (Math::Rand()-0.5f)*m_size*0.1f; + speed.y = Math::Rand()*m_size*0.2f; + dim.x = Math::Rand()*m_size/10.0f+m_size/10.0f*m_force; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f); + } + } + + if ( m_type == PT_SHOTH && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + for ( i=0 ; i<10 ; i++ ) + { + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*m_size*0.2f; + pos.z += (Math::Rand()-0.5f)*m_size*0.2f; + pos.y += (Math::Rand()-0.5f)*m_size*0.5f; + speed.x = (Math::Rand()-0.5f)*5.0f; + speed.z = (Math::Rand()-0.5f)*5.0f; + speed.y = Math::Rand()*1.0f; + dim.x = 1.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIBLOOD, Math::Rand()*3.0f+3.0f, Math::Rand()*10.0f+15.0f, 0.5f); + } + } + + if ( m_type == PT_SHOTM && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + r = (int)(10.0f*m_engine->RetParticuleDensity()); + for ( i=0 ; iCreateParticule(pos, speed, dim, PARTIBLOODM, 2.0f, 50.0f, 0.0f); + } + } + + if ( m_type == PT_SHOTW && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + if ( m_crashSphereUsed > 0 ) + { + i = rand()%m_crashSphereUsed; + pos = m_crashSpherePos[i]; + pos.x += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Math::Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + speed.x = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Math::Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = Math::Rand()*m_crashSphereRadius[i]*1.0f; + dim.x = 1.0f*m_force; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); + } + else + { + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*m_size*0.3f; + pos.z += (Math::Rand()-0.5f)*m_size*0.3f; + speed.x = (Math::Rand()-0.5f)*m_size*0.1f; + speed.z = (Math::Rand()-0.5f)*m_size*0.1f; + speed.y = Math::Rand()*m_size*0.2f; + dim.x = 1.0f*m_force; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); + } + } + + if ( m_type == PT_SHOTW && + m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time ) + { + m_lastParticuleSmoke = m_time; + + pos = m_pos; + pos.y -= 2.0f; + pos.x += (Math::Rand()-0.5f)*4.0f; + pos.z += (Math::Rand()-0.5f)*4.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 10.0f+Math::Rand()*10.0f; + dim.x = Math::Rand()*2.5f+2.0f*m_force; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f); + } + + if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) && + m_progress < 0.05f && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + speed.x = (Math::Rand()-0.5f)*m_size*1.0f; + speed.z = (Math::Rand()-0.5f)*m_size*1.0f; + speed.y = Math::Rand()*m_size*0.50f; + dim.x = Math::Rand()*m_size/5.0f+m_size/5.0f; + dim.y = dim.x; + + m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOT); + } + + if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) && + m_progress < 0.10f && + m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time ) + { + m_lastParticuleSmoke = m_time; + + dim.x = Math::Rand()*m_size/3.0f+m_size/3.0f; + dim.y = dim.x; + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*m_size*0.5f; + pos.z += (Math::Rand()-0.5f)*m_size*0.5f; + m_terrain->MoveOnFloor(pos); + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = -dim.x/2.0f/4.0f; + pos.y += dim.x/2.0f; + + r = rand()%2; + if ( r == 0 ) type = PARTISMOKE1; + if ( r == 1 ) type = PARTISMOKE2; + m_particule->CreateParticule(pos, speed, dim, type, 6.0f); + } + + if ( (m_type == PT_FRAGO || m_type == PT_EXPLOO) && + m_progress < 0.03f && + m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + speed.x = (Math::Rand()-0.5f)*m_size*2.0f; + speed.z = (Math::Rand()-0.5f)*m_size*2.0f; + speed.y = Math::Rand()*m_size*1.0f; + dim.x = Math::Rand()*m_size/2.0f+m_size/2.0f; + dim.y = dim.x; + + m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOO); + } + + if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) && + m_progress < 0.05f && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + speed.x = (Math::Rand()-0.5f)*m_size*1.0f; + speed.z = (Math::Rand()-0.5f)*m_size*1.0f; + speed.y = Math::Rand()*m_size*0.50f; + dim.x = 1.0f; + dim.y = dim.x; + + m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f); + } + + if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) && + m_progress < 0.25f && + m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticuleSmoke = m_time; + + pos = m_pos; + pos.y -= 2.0f; + pos.x += (Math::Rand()-0.5f)*4.0f; + pos.z += (Math::Rand()-0.5f)*4.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 4.0f+Math::Rand()*4.0f; + dim.x = Math::Rand()*2.5f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f); + } + + if ( m_type == PT_WPCHECK ) + { + if ( m_progress < 0.25f ) + { + factor = 0.0f; + } + else + { + factor = powf((m_progress-0.25f)/0.75f, 2.0f)*30.0f; + } + + if ( m_progress < 0.85f && + m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + pos.y += factor; + pos.x += (Math::Rand()-0.5f)*3.0f; + pos.z += (Math::Rand()-0.5f)*3.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 5.0f+Math::Rand()*5.0f; + dim.x = Math::Rand()*1.5f+1.5f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f); +//? m_particule->CreateParticule(pos, speed, dim, (ParticuleType)(PARTILENS1+rand()%4), 2.0f); + } + + angle = m_object->RetAngle(0); + angle.y = m_progress*20.0f; + angle.x = sinf(m_progress*49.0f)*0.3f; + angle.z = sinf(m_progress*47.0f)*0.2f; + m_object->SetAngle(0, angle); + + pos = m_pos; + pos.y += factor; + m_object->SetPosition(0, pos); + + if ( m_progress > 0.85f ) + { + m_object->SetZoom(0, 1.0f-(m_progress-0.85f)/0.15f); + } + } + + if ( m_type == PT_FLCREATE ) + { + if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + m_terrain->MoveOnFloor(pos); + pos.x += (Math::Rand()-0.5f)*1.0f; + pos.z += (Math::Rand()-0.5f)*1.0f; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 2.0f+Math::Rand()*2.0f; + dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f); + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f); + } + + angle = m_object->RetAngle(0); +//? angle.y = powf(m_progress, 0.2f)*20.0f; + angle.x = sinf(m_progress*49.0f)*0.3f*(1.0f-m_progress); + angle.z = sinf(m_progress*47.0f)*0.2f*(1.0f-m_progress); + m_object->SetAngle(0, angle); + + m_object->SetZoom(0, m_progress); + } + + if ( m_type == PT_FLDELETE ) + { + if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + m_terrain->MoveOnFloor(pos); + pos.x += (Math::Rand()-0.5f)*1.0f; + pos.z += (Math::Rand()-0.5f)*1.0f; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 2.0f+Math::Rand()*2.0f; + dim.x = (Math::Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f); + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f); + } + + angle = m_object->RetAngle(0); + angle.y = m_progress*20.0f; + angle.x = sinf(m_progress*49.0f)*0.3f; + angle.z = sinf(m_progress*47.0f)*0.2f; + m_object->SetAngle(0, angle); + + m_object->SetZoom(0, 1.0f-m_progress); + } + + if ( m_type == PT_RESET ) + { +#if 0 + if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + speed.x = (Math::Rand()-0.5f)*6.0f; + speed.z = (Math::Rand()-0.5f)*6.0f; + speed.y = Math::Rand()*12.0f; + dim.x = (Math::Rand()*2.5f+2.5f)*(1.0f-m_progress*0.9f); + dim.y = dim.x; + pos.y += dim.y; + m_particule->CreateParticule(pos, speed, dim, + (ParticuleType)(PARTILENS1+rand()%4), + Math::Rand()*2.5f+2.5f, + Math::Rand()*5.0f+5.0f, 0.0f); + } +#else + if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_pos; + pos.x += (Math::Rand()-0.5f)*5.0f; + pos.z += (Math::Rand()-0.5f)*5.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 5.0f+Math::Rand()*5.0f; + dim.x = Math::Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f); + + pos = m_pos; + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + speed.y = Math::Rand()*10.0f; + speed *= 0.5f+m_progress*0.5f; + dim.x = 0.6f; + dim.y = dim.x; + pos.y += dim.y; + duration = Math::Rand()*1.5f+1.5f; + m_particule->CreateTrack(pos, speed, dim, PARTITRACK6, + duration, 0.0f, + duration*0.9f, 0.7f); + } +#endif + + angle = m_object->RetResetAngle(); + m_object->SetAngleY(0, angle.y-powf((1.0f-m_progress)*5.0f, 2.0f)); + m_object->SetZoom(0, m_progress); + } + + if ( m_type == PT_FINDING ) + { + if ( m_object != 0 && + m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + factor = m_size*0.3f; + if ( m_object->RetType() == OBJECT_SAFE ) factor *= 1.3f; + if ( factor > 40.0f ) factor = 40.0f; + pos = m_pos; + m_terrain->MoveOnFloor(pos); + pos.x += (Math::Rand()-0.5f)*factor; + pos.z += (Math::Rand()-0.5f)*factor; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 4.0f+Math::Rand()*4.0f; + dim.x = (Math::Rand()*3.0f+3.0f)*(1.0f-m_progress*0.9f); + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f); + } + } + + if ( (m_type == PT_BURNT || m_type == PT_BURNO) && + m_object != 0 ) + { + if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + factor = m_size/25.0f; // 1 = standard size + + pos = m_object->RetPosition(0); + pos.y -= m_object->RetCharacter()->height; + pos.x += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; + pos.z += (Math::Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = (Math::Rand()*2.5f+1.0f)*factor; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f); + + pos = m_object->RetPosition(0); + pos.y -= m_object->RetCharacter()->height; + pos.x += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; + pos.z += (Math::Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = (Math::Rand()*5.0f*m_progress+3.0f)*factor; + dim.x = (Math::Rand()*2.0f+1.0f)*factor; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f); + + pos = m_object->RetPosition(0); + pos.y -= 2.0f; + pos.x += (Math::Rand()-0.5f)*5.0f*factor; + pos.z += (Math::Rand()-0.5f)*5.0f*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = (6.0f+Math::Rand()*6.0f+m_progress*6.0f)*factor; + dim.x = (Math::Rand()*1.5f+1.0f+m_progress*3.0f)*factor; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f); + } + + if ( m_type == PT_BURNT ) + { + BurnProgress(); + } + else + { + speed.y = 0.0f; + speed.x = (Math::Rand()-0.5f)*m_progress*1.0f; + speed.z = (Math::Rand()-0.5f)*m_progress*1.0f; + if ( m_progress > 0.8f ) + { + prog = (m_progress-0.8f)/0.2f; // 0..1 + speed.y = -prog*6.0f; // sinks into the ground + m_object->SetZoom(0, 1.0f-prog*0.5f); + } + m_object->SetLinVibration(speed); + } + } + + if ( m_type == PT_WIN ) + { + if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_object->RetPosition(0); + pos.y += 1.5f; + speed.x = (Math::Rand()-0.5f)*10.0f; + speed.z = (Math::Rand()-0.5f)*10.0f; + speed.y = 8.0f+Math::Rand()*8.0f; + dim.x = Math::Rand()*0.2f+0.2f; + dim.y = dim.x; + m_particule->CreateTrack(pos, speed, dim, + (ParticuleType)(PARTITRACK7+rand()%4), + 3.0f, 20.0f, 1.0f, 0.4f); + } + } + + if ( m_type == PT_LOST ) + { + if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time ) + { + m_lastParticule = m_time; + + pos = m_object->RetPosition(0); + pos.y -= 2.0f; + pos.x += (Math::Rand()-0.5f)*10.0f; + pos.z += (Math::Rand()-0.5f)*10.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 1.0f+Math::Rand()*1.0f; + dim.x = Math::Rand()*1.0f+1.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 8.0f, 0.0f, 0.0f); + } + } + + if ( m_type == PT_FALL ) + { + FallProgress(event.rTime); + } + + if ( m_lightRank != -1 ) + { + LightOperFrame(event.rTime); + } + + return true; +} + +// Indicates that the object binds to the effect no longer exists, without deleting it. + +void CPyro::CutObjectLink(CObject* pObj) +{ + if ( m_object == pObj ) + { + m_object = 0; + } +} + +// Indicates whether the pyrotechnic effect is complete. + +Error CPyro::IsEnded() +{ + // Destroys the object that exploded. + //It should not be destroyed at the end of the Create, + //because it is sometimes the object itself that makes the Create: + // pyro->Create(PT_FRAGT, this); + if ( m_type == PT_FRAGT || + m_type == PT_FRAGO || + m_type == PT_FRAGW || + m_type == PT_SPIDER || + m_type == PT_EGG ) + { + DeleteObject(true, true); + } + + if ( m_type == PT_FALL ) // freight which grave? + { + return FallIsEnded(); + } + + if ( m_type == PT_WIN || + m_type == PT_LOST ) + { + return ERR_CONTINUE; + } + + // End of the pyrotechnic effect? + if ( m_progress < 1.0f ) return ERR_CONTINUE; + + if ( m_type == PT_EXPLOT || + m_type == PT_EXPLOO || + m_type == PT_EXPLOW ) // explosion? + { + ExploTerminate(); + } + + if ( m_type == PT_BURNT || + m_type == PT_BURNO ) // burning? + { + BurnTerminate(); + } + + if ( m_type == PT_WPCHECK || + m_type == PT_FLDELETE ) + { + DeleteObject(true, true); + } + + if ( m_type == PT_FLCREATE ) + { + m_object->SetAngleX(0, 0.0f); + m_object->SetAngleZ(0, 0.0f); + m_object->SetZoom(0, 1.0f); + } + + if ( m_type == PT_RESET ) + { + m_object->SetPosition(0, m_object->RetResetPosition()); + m_object->SetAngle(0, m_object->RetResetAngle()); + m_object->SetZoom(0, 1.0f); + } + + if ( m_lightRank != -1 ) + { + m_light->DeleteLight(m_lightRank); + m_lightRank = -1; + } + + return ERR_STOP; +} + +// Removes the binding to a pyrotechnic effect. + +void CPyro::DeleteObject(bool bPrimary, bool bSecondary) +{ + CObject *sub, *truck; + Math::Vector pos; + ObjectType type; + + if ( m_object == 0 ) return; + + if ( m_object->RetResetCap() == RESET_MOVE ) // resettable object? + { + m_object->SetEnable(false); // object cache and inactive + pos = m_object->RetPosition(0); + pos.y = -100.0f; + m_object->SetPosition(0, pos); + return; + } + + type = m_object->RetType(); + if ( bSecondary && + type != OBJECT_FACTORY && + type != OBJECT_NUCLEAR && + type != OBJECT_ENERGY ) + { + sub = m_object->RetPower(); + if ( sub != 0 ) + { + sub->DeleteObject(); // removes the battery + delete sub; + m_object->SetPower(0); + } + + sub = m_object->RetFret(); + if ( sub != 0 ) + { + sub->DeleteObject(); // removes the object transported + delete sub; + m_object->SetFret(0); + } + } + + if ( bPrimary ) + { + truck = m_object->RetTruck(); + if ( truck != 0 ) // object carries? + { + if ( truck->RetPower() == m_object ) + { + truck->SetPower(0); + } + if ( truck->RetFret() == m_object ) + { + truck->SetFret(0); + } + } + + sub = m_object; + sub->DeleteObject(); // removes the object (*) + delete sub; + m_object = 0; + } +} + +// (*) CObject :: DeleteObject can reset m_object through CPyro :: CutObjectLink! + + +// Empty the table of operations of animation of light. + +void CPyro::LightOperFlush() +{ + m_lightOperTotal = 0; +} + +// Adds an animation operation of the light. + +void CPyro::LightOperAdd(float progress, float intensity, + float r, float g, float b) +{ + int i; + + i = m_lightOperTotal; + + m_lightOper[i].progress = progress; + m_lightOper[i].intensity = intensity; + m_lightOper[i].color.r = r; + m_lightOper[i].color.g = g; + m_lightOper[i].color.b = b; + + m_lightOperTotal ++; +} + +// Makes evolve the associated light. + +void CPyro::LightOperFrame(float rTime) +{ + D3DCOLORVALUE color; + float progress, intensity; + int i; + + for ( i=0 ; iSetLightIntensity(m_lightRank, intensity); + m_light->SetLightColor(m_lightRank, color); + break; + } + } +} + + +// Creates light to accompany a pyrotechnic effect. + +bool CPyro::CreateLight(Math::Vector pos, float height) +{ + D3DLIGHT7 light; + + if ( !m_engine->RetLightMode() ) return true; + + m_lightHeight = height; + + ZeroMemory( &light, sizeof(light) ); + light.dltType = D3DLIGHT_SPOT; + light.dvPosition.x = pos.x; + light.dvPosition.y = pos.y+height; + light.dvPosition.z = pos.z; + light.dvDirection.x = 0.0f; + light.dvDirection.y = -1.0f; // against the bottom + light.dvDirection.z = 0.0f; + light.dvRange = D3DLIGHT_RANGE_MAX; + light.dvFalloff = 1.0f; + light.dvAttenuation0 = 1.0f; + light.dvAttenuation1 = 0.0f; + light.dvAttenuation2 = 0.0f; + light.dvTheta = 0.0f; + light.dvPhi = Math::PI/4.0f; + + m_lightRank = m_light->CreateLight(); + if ( m_lightRank == -1 ) return false; + + m_light->SetLight(m_lightRank, light); + m_light->SetLightIntensity(m_lightRank, 0.0f); + + // Only illuminates the objects on the ground. + m_light->SetLightIncluType(m_lightRank, TYPETERRAIN); + + return true; +} + + +// Starts the explosion of a vehicle. + +void CPyro::ExploStart() +{ + Math::Vector pos, angle, speed, min, max; + float weight; + int i, objRank, channel; + + m_burnType = m_object->RetType(); + + pos = m_object->RetPosition(0); + m_burnFall = m_terrain->RetFloorHeight(pos, true); + + m_object->Simplify(); + m_object->SetLock(true); // ruin not usable yet + m_object->SetExplo(true); // being destroyed + m_object->FlatParent(); + + if ( m_object->RetSelect() ) + { + m_object->SetSelect(false); // deselects the object + m_camera->SetType(CAMERA_EXPLO); + m_main->DeselectAll(); + } + m_object->DeleteDeselList(m_object); + + for ( i=0 ; iRetObjectRank(i); + if ( objRank == -1 ) continue; + m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); + + pos = m_object->RetPosition(i); + + if ( i == 0 ) // main part? + { + weight = 0.0f; + + speed.y = -1.0f; + speed.x = 0.0f; + speed.z = 0.0f; + } + else + { + m_engine->GetBBox(objRank, min, max); + weight = Math::Distance(min, max); // weight according to size! + + speed.y = 10.0f+Math::Rand()*20.0f; + speed.x = (Math::Rand()-0.5f)*20.0f; + speed.z = (Math::Rand()-0.5f)*20.0f; + } + + channel = m_particule->CreatePart(pos, speed, PARTIPART, 10.0f, 20.0f, weight, 0.5f); + if ( channel != -1 ) + { + m_object->SetMasterParticule(i, channel); + } + } + m_engine->LoadTexture("dirty04.tga", 1); + + DeleteObject(false, true); // destroys the object transported + the battery +} + +// Ends the explosion of a vehicle. + +void CPyro::ExploTerminate() +{ + DeleteObject(true, false); // removes the main object +} + + +// Starts a vehicle fire. + +void CPyro::BurnStart() +{ + Math::Vector pos, angle; + int i, objRank; + + m_burnType = m_object->RetType(); + + pos = m_object->RetPosition(0); + m_burnFall = m_terrain->RetFloorHeight(pos, true); + + m_object->Simplify(); + m_object->SetLock(true); // ruin not usable yet + + if ( m_object->RetSelect() ) + { + m_object->SetSelect(false); // deselects the object + m_camera->SetType(CAMERA_EXPLO); + m_main->DeselectAll(); + } + m_object->DeleteDeselList(m_object); + + for ( i=0 ; iRetObjectRank(i); + if ( objRank == -1 ) continue; + m_engine->ChangeSecondTexture(objRank, "dirty04.tga"); + } + m_engine->LoadTexture("dirty04.tga", 1); + + m_burnPartTotal = 0; + + if ( m_burnType == OBJECT_DERRICK || + m_burnType == OBJECT_FACTORY || + m_burnType == OBJECT_REPAIR || + m_burnType == OBJECT_DESTROYER|| + m_burnType == OBJECT_CONVERT || + m_burnType == OBJECT_TOWER || + m_burnType == OBJECT_RESEARCH || + m_burnType == OBJECT_ENERGY || + m_burnType == OBJECT_LABO ) + { + pos.x = 0.0f; + pos.y = -(4.0f+Math::Rand()*4.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_STATION || + m_burnType == OBJECT_RADAR || + m_burnType == OBJECT_INFO ) + { + pos.x = 0.0f; + pos.y = -(1.0f+Math::Rand()*1.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.2f; + } + else if ( m_burnType == OBJECT_NUCLEAR ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Math::Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_PARA ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Math::Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_SAFE ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Math::Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_HUSTON ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Math::Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_MOBILEwa || + m_burnType == OBJECT_MOBILEwc || + m_burnType == OBJECT_MOBILEwi || + m_burnType == OBJECT_MOBILEws || + m_burnType == OBJECT_MOBILEwt ) + { + pos.x = 0.0f; + pos.y = -(0.5f+Math::Rand()*1.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_TEEN31 ) // basket? + { + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.2f; + } + else + { + pos.x = 0.0f; + pos.y = -(2.0f+Math::Rand()*2.0f); + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*0.8f; + } + BurnAddPart(0, pos, angle); // movement of the main part + + m_burnKeepPart[0] = -1; // nothing to keep + + if ( m_burnType == OBJECT_DERRICK ) + { + pos.x = 0.0f; + pos.y = -40.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the drill + } + + if ( m_burnType == OBJECT_REPAIR ) + { + pos.x = 0.0f; + pos.y = -12.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = -90.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the sensor + } + + if ( m_burnType == OBJECT_DESTROYER ) + { + pos.x = 0.0f; + pos.y = -12.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = -90.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the sensor + } + + if ( m_burnType == OBJECT_CONVERT ) + { + pos.x = 0.0f; + pos.y = -200.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.5f; + angle.y = (Math::Rand()-0.5f)*0.5f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the cover + BurnAddPart(2, pos, angle); + BurnAddPart(3, pos, angle); + } + + if ( m_burnType == OBJECT_TOWER ) + { + pos.x = 0.0f; + pos.y = -7.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = (Math::Rand()-0.5f)*0.4f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the cannon + } + + if ( m_burnType == OBJECT_RESEARCH ) + { + pos.x = 0.0f; + pos.y = -7.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the anemometer + } + + if ( m_burnType == OBJECT_RADAR ) + { + pos.x = 0.0f; + pos.y = -14.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = (Math::Rand()-0.5f)*0.4f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the radar + BurnAddPart(2, pos, angle); + } + + if ( m_burnType == OBJECT_INFO ) + { + pos.x = 0.0f; + pos.y = -14.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.4f; + angle.y = (Math::Rand()-0.5f)*0.4f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the information terminal + BurnAddPart(2, pos, angle); + } + + if ( m_burnType == OBJECT_LABO ) + { + pos.x = 0.0f; + pos.y = -12.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the arm + } + + if ( m_burnType == OBJECT_NUCLEAR ) + { + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = -135.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the cover + } + + if ( m_burnType == OBJECT_MOBILEfa || + m_burnType == OBJECT_MOBILEta || + m_burnType == OBJECT_MOBILEwa || + m_burnType == OBJECT_MOBILEia ) + { + pos.x = 2.0f; + pos.y = -5.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = 40.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the arm + } + + if ( m_burnType == OBJECT_MOBILEfs || + m_burnType == OBJECT_MOBILEts || + m_burnType == OBJECT_MOBILEws || + m_burnType == OBJECT_MOBILEis ) + { + pos.x = 0.0f; + pos.y = -7.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = 50.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the sensor + } + + if ( m_burnType == OBJECT_MOBILEfc || + m_burnType == OBJECT_MOBILEtc || + m_burnType == OBJECT_MOBILEwc || + m_burnType == OBJECT_MOBILEic ) + { + pos.x = -1.5f; + pos.y = -5.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = -25.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the cannon + } + + if ( m_burnType == OBJECT_MOBILEfi || + m_burnType == OBJECT_MOBILEti || + m_burnType == OBJECT_MOBILEwi || + m_burnType == OBJECT_MOBILEii ) + { + pos.x = -1.5f; + pos.y = -5.0f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*0.2f; + angle.y = (Math::Rand()-0.5f)*0.2f; + angle.z = -25.0f*Math::PI/180.0f; + BurnAddPart(1, pos, angle); // down the insect-cannon + } + + if ( m_burnType == OBJECT_MOBILErt || + m_burnType == OBJECT_MOBILErc ) + { + pos.x = 0.0f; + pos.y = -10.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the holder + + pos.x = 0.0f; + pos.y = -10.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(2, pos, angle); // down the pestle/cannon + } + + if ( m_burnType == OBJECT_MOBILErr ) + { + pos.x = 0.0f; + pos.y = -10.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the holder + + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = -Math::PI/2.0f; + BurnAddPart(4, pos, angle); + + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = Math::PI/2.5f; + BurnAddPart(2, pos, angle); + } + + if ( m_burnType == OBJECT_MOBILErs ) + { + pos.x = 0.0f; + pos.y = -10.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the holder + + pos.x = 0.0f; + pos.y = -5.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(2, pos, angle); + + pos.x = 0.0f; + pos.y = -5.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(3, pos, angle); + } + + if ( m_burnType == OBJECT_MOBILEsa ) + { + pos.x = 0.0f; + pos.y = -10.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = 0.0f; + BurnAddPart(1, pos, angle); // down the holder + } + + if ( m_burnType == OBJECT_MOBILEwa || + m_burnType == OBJECT_MOBILEwc || + m_burnType == OBJECT_MOBILEwi || + m_burnType == OBJECT_MOBILEws || + m_burnType == OBJECT_MOBILEwt ) // wheels? + { + for ( i=0 ; i<4 ; i++ ) + { + pos.x = 0.0f; + pos.y = Math::Rand()*0.5f; + pos.z = 0.0f; + angle.x = (Math::Rand()-0.5f)*Math::PI/2.0f; + angle.y = (Math::Rand()-0.5f)*Math::PI/2.0f; + angle.z = 0.0f; + BurnAddPart(6+i, pos, angle); // wheel + + m_burnKeepPart[i] = 6+i; // we keep the wheels + } + m_burnKeepPart[i] = -1; + } + + if ( m_burnType == OBJECT_MOBILEta || + m_burnType == OBJECT_MOBILEtc || + m_burnType == OBJECT_MOBILEti || + m_burnType == OBJECT_MOBILEts || + m_burnType == OBJECT_MOBILErt || + m_burnType == OBJECT_MOBILErc || + m_burnType == OBJECT_MOBILErr || + m_burnType == OBJECT_MOBILErs || + m_burnType == OBJECT_MOBILEsa || + m_burnType == OBJECT_MOBILEdr ) // caterpillars? + { + pos.x = 0.0f; + pos.y = -4.0f; + pos.z = 2.0f; + angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f; + angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f; + angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f; + BurnAddPart(6, pos, angle); // down the right caterpillar + + pos.x = 0.0f; + pos.y = -4.0f; + pos.z = -2.0f; + angle.x = (Math::Rand()-0.5f)*20.0f*Math::PI/180.0f; + angle.y = (Math::Rand()-0.5f)*10.0f*Math::PI/180.0f; + angle.z = (Math::Rand()-0.5f)*30.0f*Math::PI/180.0f; + BurnAddPart(7, pos, angle); // down the left caterpillar + } + + if ( m_burnType == OBJECT_MOBILEfa || + m_burnType == OBJECT_MOBILEfc || + m_burnType == OBJECT_MOBILEfi || + m_burnType == OBJECT_MOBILEfs || + m_burnType == OBJECT_MOBILEft ) // flying? + { + for ( i=0 ; i<3 ; i++ ) + { + pos.x = 0.0f; + pos.y = -3.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = 0.0f; + angle.z = (Math::Rand()-0.5f)*Math::PI/2.0f; + BurnAddPart(6+i, pos, angle); // foot + } + m_burnKeepPart[i] = -1; + } + + if ( m_burnType == OBJECT_MOBILEia || + m_burnType == OBJECT_MOBILEic || + m_burnType == OBJECT_MOBILEii || + m_burnType == OBJECT_MOBILEis ) // legs? + { + for ( i=0 ; i<6; i++ ) + { + pos.x = 0.0f; + pos.y = -3.0f; + pos.z = 0.0f; + angle.x = 0.0f; + angle.y = (Math::Rand()-0.5f)*Math::PI/4.0f; + angle.z = (Math::Rand()-0.5f)*Math::PI/4.0f; + BurnAddPart(6+i, pos, angle); // leg + } + } +} + +// Adds a part move. + +void CPyro::BurnAddPart(int part, Math::Vector pos, Math::Vector angle) +{ + int i; + + i = m_burnPartTotal; + m_burnPart[i].part = part; + m_burnPart[i].initialPos = m_object->RetPosition(part); + m_burnPart[i].finalPos = m_burnPart[i].initialPos+pos; + m_burnPart[i].initialAngle = m_object->RetAngle(part); + m_burnPart[i].finalAngle = m_burnPart[i].initialAngle+angle; + + m_burnPartTotal ++; +} + +// Advances of a vehicle fire. + +void CPyro::BurnProgress() +{ + CObject* sub; + Math::Vector pos; + float h; + int i; + + if ( m_burnType == OBJECT_TEEN31 ) // basket? + { + m_object->SetZoomY(0, 1.0f-m_progress*0.5f); // slight flattening + } + + for ( i=0 ; i 0.0f ) + { + h = powf(m_progress, 2.0f)*1000.0f; + if ( h > m_burnFall ) h = m_burnFall; + pos.y -= h; + } + m_object->SetPosition(m_burnPart[i].part, pos); + + pos = m_burnPart[i].initialAngle + m_progress*(m_burnPart[i].finalAngle-m_burnPart[i].initialAngle); + m_object->SetAngle(m_burnPart[i].part, pos); + } + + sub = m_object->RetPower(); + if ( sub != 0 ) // is there a battery? + { + sub->SetZoomY(0, 1.0f-m_progress); // complete flattening + } +} + +// Indicates whether a part should be retained. + +bool CPyro::BurnIsKeepPart(int part) +{ + int i; + + i = 0; + while ( m_burnKeepPart[i] != -1 ) + { + if ( part == m_burnKeepPart[i++] ) return true; // must keep + } + return false; // must destroy +} + +// Ends the fire of an insect or a vehicle. + +void CPyro::BurnTerminate() +{ + int i, objRank; + + if ( m_type == PT_BURNO ) // organic object is burning? + { + DeleteObject(true, true); // removes the insect + return; + } + + for ( i=1 ; iRetObjectRank(i); + if ( objRank == -1 ) continue; + if ( BurnIsKeepPart(i) ) continue; + + m_object->DeletePart(i); + } + + DeleteObject(false, true); // destroys the object transported + the battery + + if ( m_burnType == OBJECT_DERRICK || + m_burnType == OBJECT_STATION || + m_burnType == OBJECT_FACTORY || + m_burnType == OBJECT_REPAIR || + m_burnType == OBJECT_DESTROYER|| + m_burnType == OBJECT_CONVERT || + m_burnType == OBJECT_TOWER || + m_burnType == OBJECT_RESEARCH || + m_burnType == OBJECT_RADAR || + m_burnType == OBJECT_INFO || + m_burnType == OBJECT_ENERGY || + m_burnType == OBJECT_LABO || + m_burnType == OBJECT_NUCLEAR || + m_burnType == OBJECT_PARA || + m_burnType == OBJECT_SAFE || + m_burnType == OBJECT_HUSTON || + m_burnType == OBJECT_START || + m_burnType == OBJECT_END ) + { + m_object->SetType(OBJECT_RUINfactory); // others become a ruin + m_object->SetLock(false); + } + else + { + m_object->SetType(OBJECT_RUINmobilew1); // others become a ruin + m_object->SetLock(false); + } + + m_object->SetBurn(false); // ruin usable (c-e-d. recoverable) +} + + +// Start of an object freight falling. + +void CPyro::FallStart() +{ + Math::Vector pos; + + m_object->SetBurn(true); // usable + + pos = m_object->RetPosition(0); + m_fallFloor = m_terrain->RetFloorLevel(pos); + m_fallSpeed = 0.0f; + m_fallBulletTime = 0.0f; + m_bFallEnding = false; +} + +// Seeking an object explode by the falling ball of bees. + +CObject* CPyro::FallSearchBeeExplo() +{ + CObject* pObj; + Math::Vector iPos, oPos; + ObjectType oType; + float iRadius, oRadius, distance, shieldRadius; + int i, j; + + m_object->GetCrashSphere(0, iPos, iRadius); + + for ( i=0 ; i<1000000 ; i++ ) + { + pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); + if ( pObj == 0 ) break; + + oType = pObj->RetType(); + if ( oType != OBJECT_HUMAN && + oType != OBJECT_MOBILEfa && + oType != OBJECT_MOBILEta && + oType != OBJECT_MOBILEwa && + oType != OBJECT_MOBILEia && + oType != OBJECT_MOBILEfc && + oType != OBJECT_MOBILEtc && + oType != OBJECT_MOBILEwc && + oType != OBJECT_MOBILEic && + oType != OBJECT_MOBILEfi && + oType != OBJECT_MOBILEti && + oType != OBJECT_MOBILEwi && + oType != OBJECT_MOBILEii && + oType != OBJECT_MOBILEfs && + oType != OBJECT_MOBILEts && + oType != OBJECT_MOBILEws && + oType != OBJECT_MOBILEis && + oType != OBJECT_MOBILErt && + oType != OBJECT_MOBILErc && + oType != OBJECT_MOBILErr && + oType != OBJECT_MOBILErs && + oType != OBJECT_MOBILEsa && + oType != OBJECT_MOBILEtg && + oType != OBJECT_MOBILEft && + oType != OBJECT_MOBILEtt && + oType != OBJECT_MOBILEwt && + oType != OBJECT_MOBILEit && + oType != OBJECT_MOBILEdr && + oType != OBJECT_BASE && + oType != OBJECT_DERRICK && + oType != OBJECT_STATION && + oType != OBJECT_FACTORY && + oType != OBJECT_REPAIR && + oType != OBJECT_DESTROYER&& + oType != OBJECT_CONVERT && + oType != OBJECT_TOWER && + oType != OBJECT_RESEARCH && + oType != OBJECT_RADAR && + oType != OBJECT_INFO && + oType != OBJECT_ENERGY && + oType != OBJECT_LABO && + oType != OBJECT_NUCLEAR && + oType != OBJECT_PARA && + oType != OBJECT_SAFE && + oType != OBJECT_HUSTON && + oType != OBJECT_METAL && + oType != OBJECT_POWER && + oType != OBJECT_ATOMIC ) continue; + + if ( pObj->RetTruck() != 0 ) continue; // object transported? + + oPos = pObj->RetPosition(0); + + shieldRadius = pObj->RetShieldRadius(); + if ( shieldRadius > 0.0f ) + { + distance = Math::Distance(oPos, iPos); + if ( distance <= shieldRadius ) return pObj; + } + + if ( oType == OBJECT_BASE ) + { + distance = Math::Distance(oPos, iPos); + if ( distance < 25.0f ) return pObj; + } + + // Test the center of the object, which is necessary for objects + // that have no sphere in the center (station). + distance = Math::Distance(oPos, iPos)-4.0f; + if ( distance < 5.0f ) return pObj; + + // Test with all spheres of the object. + j = 0; + while ( pObj->GetCrashSphere(j++, oPos, oRadius) ) + { + distance = Math::Distance(oPos, iPos); + if ( distance <= iRadius+oRadius ) + { + return pObj; + } + } + } + return 0; +} + +// Fall of an object's freight. + +void CPyro::FallProgress(float rTime) +{ + CObject* pObj; + Math::Vector pos; + bool bFloor = false; + + if ( m_object == 0 ) return; + + m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt + pos = m_object->RetPosition(0); + pos.y -= m_fallSpeed*rTime; // dd -= v2*dt + + if ( pos.y <= m_fallFloor ) // below the ground level? + { + pos.y = m_fallFloor; + bFloor = true; + } + m_object->SetPosition(0, pos); + + if ( m_object->RetType() == OBJECT_BULLET ) + { + m_fallBulletTime += rTime; + + if ( m_fallBulletTime > 0.2f || bFloor ) + { + m_fallBulletTime = 0.0f; + + pObj = FallSearchBeeExplo(); + if ( pObj == 0 ) + { + if ( bFloor ) // reaches the ground? + { + m_object->ExploObject(EXPLO_BOUM, 0.0f); // start explosion + } + } + else + { + if ( pObj->RetShieldRadius() > 0.0f ) // protected by shield? + { + m_particule->CreateParticule(pos, Math::Vector(0.0f, 0.0f, 0.0f), Math::Point(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f); + m_sound->Play(SOUND_GUNDEL); + + DeleteObject(true, true); // removes the ball + } + else + { + if ( pObj->ExploObject(EXPLO_BOUM, 1.0f) ) // start explosion + { + DeleteObject(true, true); // removes the ball + } + else + { + m_object->ExploObject(EXPLO_BOUM, 0.0f); // start explosion + } + } + } + + if ( bFloor || pObj != 0 ) + { + m_bFallEnding = true; + } + } + } +} + +// Indicates whether the fall is over. + +Error CPyro::FallIsEnded() +{ + Math::Vector pos; + + if ( m_bFallEnding || m_object == 0 ) return ERR_STOP; + + pos = m_object->RetPosition(0); + if ( pos.y > m_fallFloor ) return ERR_CONTINUE; + + m_sound->Play(SOUND_BOUM, pos); + m_object->SetBurn(false); // usable again + + return ERR_STOP; +} + diff --git a/src/old/pyro.h b/src/old/pyro.h index 4b61356..f64d8f0 100644 --- a/src/old/pyro.h +++ b/src/old/pyro.h @@ -1,170 +1,170 @@ -// * 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/. - -// pyro.h - -#pragma once - - -#include "old/d3dengine.h" -#include "object/object.h" -#include "common/misc.h" - - -class CInstanceManager; -class CD3DEngine; -class CTerrain; -class CCamera; -class CParticule; -class CLight; -class CObject; -class CDisplayText; -class CRobotMain; -class CSound; - - - -enum PyroType -{ - PT_NULL = 0, - PT_FRAGT = 1, // fragmentation of technical object - PT_FRAGO = 2, // fragmentation of organic object - PT_FRAGW = 4, // fragmentation of object under water - PT_EXPLOT = 5, // explosion of technical object - PT_EXPLOO = 6, // explosion of organic object - PT_EXPLOW = 8, // explosion of object under water - PT_SHOTT = 9, // hit technical object - PT_SHOTH = 10, // hit human - PT_SHOTM = 11, // hit queen - PT_SHOTW = 12, // hit under water - PT_EGG = 13, // break the egg - PT_BURNT = 14, // burning of technical object - PT_BURNO = 15, // burning of organic object - PT_SPIDER = 16, // spider explosion - PT_FALL = 17, // cargo falling - PT_WPCHECK = 18, // indicator reaches - PT_FLCREATE = 19, // flag create - PT_FLDELETE = 20, // flag destroy - PT_RESET = 21, // reset position of the object - PT_WIN = 22, // fireworks - PT_LOST = 23, // black smoke - PT_DEADG = 24, // shooting death - PT_DEADW = 25, // drowning death - PT_FINDING = 26, // object discovered -}; - - -struct PyroBurnPart -{ - int part; - Math::Vector initialPos; - Math::Vector finalPos; - Math::Vector initialAngle; - Math::Vector finalAngle; -}; - -struct PyroLightOper -{ - float progress; - float intensity; - D3DCOLORVALUE color; -}; - - - -class CPyro -{ -public: - CPyro(CInstanceManager* iMan); - ~CPyro(); - - void DeleteObject(bool bAll=false); - bool Create(PyroType type, CObject* pObj, float force=1.0f); - bool EventProcess(const Event &event); - Error IsEnded(); - void CutObjectLink(CObject* pObj); - -protected: - void DisplayError(PyroType type, CObject* pObj); - bool CreateLight(Math::Vector pos, float height); - void DeleteObject(bool bPrimary, bool bSecondary); - - void CreateTriangle(CObject* pObj, ObjectType oType, int part); - - void ExploStart(); - void ExploTerminate(); - - void BurnStart(); - void BurnAddPart(int part, Math::Vector pos, Math::Vector angle); - void BurnProgress(); - bool BurnIsKeepPart(int part); - void BurnTerminate(); - - void FallStart(); - CObject* FallSearchBeeExplo(); - void FallProgress(float rTime); - Error FallIsEnded(); - - void LightOperFlush(); - void LightOperAdd(float progress, float intensity, float r, float g, float b); - void LightOperFrame(float rTime); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - CTerrain* m_terrain; - CCamera* m_camera; - CParticule* m_particule; - CLight* m_light; - CObject* m_object; - CDisplayText* m_displayText; - CRobotMain* m_main; - CSound* m_sound; - - Math::Vector m_pos; // center of the effect - Math::Vector m_posPower; // center of the battery - bool m_bPower; // battery exists? - PyroType m_type; - float m_force; - float m_size; - float m_progress; - float m_speed; - float m_time; - float m_lastParticule; - float m_lastParticuleSmoke; - int m_soundChannel; - - int m_lightRank; - int m_lightOperTotal; - PyroLightOper m_lightOper[10]; - float m_lightHeight; - - ObjectType m_burnType; - int m_burnPartTotal; - PyroBurnPart m_burnPart[10]; - int m_burnKeepPart[10]; - float m_burnFall; - - float m_fallFloor; - float m_fallSpeed; - float m_fallBulletTime; - bool m_bFallEnding; - - int m_crashSphereUsed; // number of spheres used - Math::Vector m_crashSpherePos[50]; - float m_crashSphereRadius[50]; -}; - +// * 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/. + +// pyro.h + +#pragma once + + +#include "old/d3dengine.h" +#include "object/object.h" +#include "common/misc.h" + + +class CInstanceManager; +class CD3DEngine; +class CTerrain; +class CCamera; +class CParticule; +class CLight; +class CObject; +class CDisplayText; +class CRobotMain; +class CSound; + + + +enum PyroType +{ + PT_NULL = 0, + PT_FRAGT = 1, // fragmentation of technical object + PT_FRAGO = 2, // fragmentation of organic object + PT_FRAGW = 4, // fragmentation of object under water + PT_EXPLOT = 5, // explosion of technical object + PT_EXPLOO = 6, // explosion of organic object + PT_EXPLOW = 8, // explosion of object under water + PT_SHOTT = 9, // hit technical object + PT_SHOTH = 10, // hit human + PT_SHOTM = 11, // hit queen + PT_SHOTW = 12, // hit under water + PT_EGG = 13, // break the egg + PT_BURNT = 14, // burning of technical object + PT_BURNO = 15, // burning of organic object + PT_SPIDER = 16, // spider explosion + PT_FALL = 17, // cargo falling + PT_WPCHECK = 18, // indicator reaches + PT_FLCREATE = 19, // flag create + PT_FLDELETE = 20, // flag destroy + PT_RESET = 21, // reset position of the object + PT_WIN = 22, // fireworks + PT_LOST = 23, // black smoke + PT_DEADG = 24, // shooting death + PT_DEADW = 25, // drowning death + PT_FINDING = 26, // object discovered +}; + + +struct PyroBurnPart +{ + int part; + Math::Vector initialPos; + Math::Vector finalPos; + Math::Vector initialAngle; + Math::Vector finalAngle; +}; + +struct PyroLightOper +{ + float progress; + float intensity; + D3DCOLORVALUE color; +}; + + + +class CPyro +{ +public: + CPyro(CInstanceManager* iMan); + ~CPyro(); + + void DeleteObject(bool bAll=false); + bool Create(PyroType type, CObject* pObj, float force=1.0f); + bool EventProcess(const Event &event); + Error IsEnded(); + void CutObjectLink(CObject* pObj); + +protected: + void DisplayError(PyroType type, CObject* pObj); + bool CreateLight(Math::Vector pos, float height); + void DeleteObject(bool bPrimary, bool bSecondary); + + void CreateTriangle(CObject* pObj, ObjectType oType, int part); + + void ExploStart(); + void ExploTerminate(); + + void BurnStart(); + void BurnAddPart(int part, Math::Vector pos, Math::Vector angle); + void BurnProgress(); + bool BurnIsKeepPart(int part); + void BurnTerminate(); + + void FallStart(); + CObject* FallSearchBeeExplo(); + void FallProgress(float rTime); + Error FallIsEnded(); + + void LightOperFlush(); + void LightOperAdd(float progress, float intensity, float r, float g, float b); + void LightOperFrame(float rTime); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + CTerrain* m_terrain; + CCamera* m_camera; + CParticule* m_particule; + CLight* m_light; + CObject* m_object; + CDisplayText* m_displayText; + CRobotMain* m_main; + CSound* m_sound; + + Math::Vector m_pos; // center of the effect + Math::Vector m_posPower; // center of the battery + bool m_bPower; // battery exists? + PyroType m_type; + float m_force; + float m_size; + float m_progress; + float m_speed; + float m_time; + float m_lastParticule; + float m_lastParticuleSmoke; + int m_soundChannel; + + int m_lightRank; + int m_lightOperTotal; + PyroLightOper m_lightOper[10]; + float m_lightHeight; + + ObjectType m_burnType; + int m_burnPartTotal; + PyroBurnPart m_burnPart[10]; + int m_burnKeepPart[10]; + float m_burnFall; + + float m_fallFloor; + float m_fallSpeed; + float m_fallBulletTime; + bool m_bFallEnding; + + int m_crashSphereUsed; // number of spheres used + Math::Vector m_crashSpherePos[50]; + float m_crashSphereRadius[50]; +}; + diff --git a/src/old/resource.h b/src/old/resource.h index 0f3be0a..959592d 100644 --- a/src/old/resource.h +++ b/src/old/resource.h @@ -1,55 +1,55 @@ -// * 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/. - -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by winmain.rc -// -#define IDI_MAIN_ICON 101 -#define IDR_MAIN_ACCEL 113 -#define IDR_MENU 141 -#define IDR_POPUP 142 -#define IDD_ABOUT 143 -#define IDD_CHANGEDEVICE 144 -#define IDC_CURSORHAND 149 -#define IDC_CURSORSCROLLL 150 -#define IDC_CURSORSCROLLR 151 -#define IDC_CURSORSCROLLU 152 -#define IDC_CURSORSCROLLD 153 -#define IDC_CURSORTARGET 154 -#define IDC_DEVICE_COMBO 1000 -#define IDC_MODE_COMBO 1001 -#define IDC_WINDOWED_CHECKBOX 1012 -#define IDC_STEREO_CHECKBOX 1013 -#define IDC_FULLSCREEN_TEXT 1014 -#define IDM_ABOUT 40001 -#define IDM_CHANGEDEVICE 40002 -#define IDM_TOGGLEFULLSCREEN 40003 -#define IDM_TOGGLESTART 40004 -#define IDM_SINGLESTEP 40005 -#define IDM_EXIT 40006 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_3D_CONTROLS 1 -#define _APS_NEXT_RESOURCE_VALUE 159 -#define _APS_NEXT_COMMAND_VALUE 40011 -#define _APS_NEXT_CONTROL_VALUE 1015 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif +// * 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/. + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by winmain.rc +// +#define IDI_MAIN_ICON 101 +#define IDR_MAIN_ACCEL 113 +#define IDR_MENU 141 +#define IDR_POPUP 142 +#define IDD_ABOUT 143 +#define IDD_CHANGEDEVICE 144 +#define IDC_CURSORHAND 149 +#define IDC_CURSORSCROLLL 150 +#define IDC_CURSORSCROLLR 151 +#define IDC_CURSORSCROLLU 152 +#define IDC_CURSORSCROLLD 153 +#define IDC_CURSORTARGET 154 +#define IDC_DEVICE_COMBO 1000 +#define IDC_MODE_COMBO 1001 +#define IDC_WINDOWED_CHECKBOX 1012 +#define IDC_STEREO_CHECKBOX 1013 +#define IDC_FULLSCREEN_TEXT 1014 +#define IDM_ABOUT 40001 +#define IDM_CHANGEDEVICE 40002 +#define IDM_TOGGLEFULLSCREEN 40003 +#define IDM_TOGGLESTART 40004 +#define IDM_SINGLESTEP 40005 +#define IDM_EXIT 40006 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_3D_CONTROLS 1 +#define _APS_NEXT_RESOURCE_VALUE 159 +#define _APS_NEXT_COMMAND_VALUE 40011 +#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/src/old/sound.cpp b/src/old/sound.cpp index 8b4089a..9aca05a 100644 --- a/src/old/sound.cpp +++ b/src/old/sound.cpp @@ -1,1659 +1,1659 @@ -// * 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/. - -// sound.cpp - - -#include -#include -#include -#include -#include - -#include "common/language.h" -#include "common/struct.h" -#include "common/iman.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/math3d.h" -#include "old/sound.h" - - -///////////////////////////////////////////////////////////////////////////// - - -const int LXIMAGE = 640; -const int LYIMAGE = 480; - - - -// Header .WAV file. - -struct WaveHeader -{ - BYTE RIFF[4]; // "RIFF" - DWORD dwSize; // size of data to follow - BYTE WAVE[4]; // "WAVE" - BYTE fmt_[4]; // "fmt " - DWORD dw16; // 16 - WORD wOne_0; // 1 - WORD wChnls; // number of Channels - DWORD dwSRate; // sample Rate - DWORD BytesPerSec; // sample Rate - WORD wBlkAlign; // 1 - WORD BitsPerSample; // sample size - BYTE DATA[4]; // "DATA" - DWORD dwDSize; // number of Samples -}; - - - - -// Displays an error DirectSound. - -void DisplayError(char *name, Sound sound, HRESULT err) -{ - char s[100]; - unsigned int i = err; - if ( err == DS_OK ) return; - sprintf(s, "SoundError in %s, sound=%d err=%d\n", name, sound, i); - OutputDebugString(s); - - if ( err == DSERR_ALLOCATED ) OutputDebugString("DSERR_ALLOCATED\n"); - if ( err == DSERR_CONTROLUNAVAIL ) OutputDebugString("DSERR_CONTROLUNAVAIL\n"); - if ( err == DSERR_INVALIDPARAM ) OutputDebugString("DSERR_INVALIDPARAM\n"); - if ( err == DSERR_INVALIDCALL ) OutputDebugString("DSERR_INVALIDCALL\n"); - if ( err == DSERR_GENERIC ) OutputDebugString("DSERR_GENERIC\n"); - if ( err == DSERR_PRIOLEVELNEEDED ) OutputDebugString("DSERR_PRIOLEVELNEEDED\n"); - if ( err == DSERR_OUTOFMEMORY ) OutputDebugString("DSERR_OUTOFMEMORY\n"); - if ( err == DSERR_BADFORMAT ) OutputDebugString("DSERR_BADFORMAT\n"); - if ( err == DSERR_UNSUPPORTED ) OutputDebugString("DSERR_UNSUPPORTED\n"); - if ( err == DSERR_NODRIVER ) OutputDebugString("DSERR_NODRIVER\n"); - if ( err == DSERR_ALREADYINITIALIZED ) OutputDebugString("DSERR_ALREADYINITIALIZED\n"); - if ( err == DSERR_NOAGGREGATION ) OutputDebugString("DSERR_NOAGGREGATION\n"); - if ( err == DSERR_BUFFERLOST ) OutputDebugString("DSERR_BUFFERLOST\n"); - if ( err == DSERR_OTHERAPPHASPRIO ) OutputDebugString("DSERR_OTHERAPPHASPRIO\n"); - if ( err == DSERR_UNINITIALIZED ) OutputDebugString("DSERR_UNINITIALIZED\n"); - if ( err == DSERR_NOINTERFACE ) OutputDebugString("DSERR_NOINTERFACE\n"); - if ( err == DSERR_ACCESSDENIED ) OutputDebugString("DSERR_ACCESSDENIED\n"); -} - -// Returns the name of the current folder. - -void GetCurrentDir(char *pName, int lg) -{ - int i; - - strncpy(pName, _pgmptr, lg-1); - pName[lg-1] = 0; - - lg = strlen(pName); - if ( lg == 0 ) return; - - for ( i=0 ; i 0 ) - { - lg --; - if ( pName[lg] == '\\' ) - { - pName[lg+1] = 0; - break; - } - } - - if ( lg > 6 && strcmp(pName+lg-6, "\\debug\\") == 0 ) - { - pName[lg-5] = 0; // ignores the folder \debug! - } - - if ( lg > 6 && strcmp(pName+lg-6, "\\release\\") == 0 ) - { - pName[lg-7] = 0; // ignores the folder \release ! - } -} - - - - -///////////////////////////////////////////////////////////////////////////// - - -// Changes the volume of midi. -// The volume is between 0 and 20! - -void InitMidiVolume(int volume) -{ - int nb, i, n; - MMRESULT result; - HMIDIOUT hmo = 0; - - static int table[21] = - { - 0x00000000, - 0x11111111, - 0x22222222, - 0x33333333, - 0x44444444, - 0x55555555, - 0x66666666, - 0x77777777, - 0x88888888, - 0x99999999, - 0xAAAAAAAA, - 0xBBBBBBBB, - 0xCCCCCCCC, - 0xDDDDDDDD, - 0xEEEEEEEE, - 0xF222F222, - 0xF555F555, - 0xF777F777, - 0xFAAAFAAA, - 0xFDDDFDDD, - 0xFFFFFFFF, - }; - - if ( volume < 0 ) volume = 0; - if ( volume > MAXVOLUME ) volume = MAXVOLUME; - - nb = midiOutGetNumDevs(); - for ( i=0 ; i MAXVOLUME ) volume = MAXVOLUME; - - // Open the mixer. This opens the mixer with a deviceID of 0. If you - // have a single sound card/mixer, then this will open it. If you have - // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and - // so on. - rc = mixerOpen(&hMixer, 0,0,0,0); - if ( rc != MMSYSERR_NOERROR ) - { - return false; // Couldn't open the mixer. - } - - // Initialize MIXERLINE structure. - ZeroMemory(&mxl,sizeof(mxl)); - mxl.cbStruct = sizeof(mxl); - - // Specify the line you want to get. You are getting the input line - // here. If you want to get the output line, you need to use - // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT. - mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC; - - rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl, - MIXER_GETLINEINFOF_COMPONENTTYPE); - if ( rc != MMSYSERR_NOERROR ) - { - return false; // Couldn't get the mixer line. - } - - // Get the control. - ZeroMemory(&mxlc, sizeof(mxlc)); - mxlc.cbStruct = sizeof(mxlc); - mxlc.dwLineID = mxl.dwLineID; -//? mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER; -//? mxlc.dwControlType = MIXERCONTROL_CONTROLF_UNIFORM; - mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; - mxlc.cControls = 1; - mxlc.cbmxctrl = sizeof(mxc); - mxlc.pamxctrl = &mxc; - ZeroMemory(&mxc, sizeof(mxc)); - mxc.cbStruct = sizeof(mxc); - rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc, - MIXER_GETLINECONTROLSF_ONEBYTYPE); -//? MIXER_GETLINECONTROLSF_ALL); - if ( rc != MMSYSERR_NOERROR ) - { - return false; // Couldn't get the control. - } - - // After successfully getting the peakmeter control, the volume range - // will be specified by mxc.Bounds.lMinimum to mxc.Bounds.lMaximum. - - MIXERCONTROLDETAILS mxcd; // Gets the control values. - MIXERCONTROLDETAILS_SIGNED volStruct; // Gets the control values. - - volStruct.lValue = volume*(mxc.Bounds.lMaximum-mxc.Bounds.lMinimum); - volStruct.lValue /= MAXVOLUME; - volStruct.lValue += mxc.Bounds.lMinimum; - - // Initialize the MIXERCONTROLDETAILS structure - ZeroMemory(&mxcd, sizeof(mxcd)); - mxcd.cbStruct = sizeof(mxcd); - mxcd.cbDetails = sizeof(volStruct); - mxcd.dwControlID = mxc.dwControlID; - mxcd.paDetails = &volStruct; - mxcd.cChannels = 1; - - // Get the current value of the peakmeter control. Typically, you - // would set a timer in your program to query the volume every 10th - // of a second or so. - rc = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd, - MIXER_SETCONTROLDETAILSF_VALUE); - if ( rc != MMSYSERR_NOERROR ) - { - return false; // Couldn't get the current volume. - } -#endif - - return true; -} - - -///////////////////////////////////////////////////////////////////////////// - - -// Constructor. - -CSound::CSound(CInstanceManager* iMan) -{ - int i; - - m_iMan = iMan; - m_iMan->AddInstance(CLASS_SOUND, this); - - m_bEnable = false; - m_bState = false; - m_bAudioTrack = true; - m_ctrl3D = true; - m_bDebugMode = false; - m_MidiDeviceID = 0; - m_MIDIMusic = 0; - m_audioVolume = 20; - m_midiVolume = 15; - m_lastMidiVolume = 0; - m_listener = 0; - m_lastTime = 0.0f; - m_playTime = 0.0f; - m_uniqueStamp = 0; - m_maxSound = MAXSOUND; - m_eye = Math::Vector(0.0f, 0.0f, 0.0f); - m_hWnd = 0; - - m_lpDS = NULL; - - ZeroMemory(m_channel, sizeof(SoundChannel)*MAXSOUND); - for ( i=0 ; iStop(); - m_channel[i].soundBuffer->Release(); - m_channel[i].soundBuffer = 0; - m_channel[i].bUsed = false; - } - } - - if ( m_listener != NULL ) - { - m_listener->Release(); - m_listener = NULL; - } - - if ( m_lpDS != NULL ) - { - m_lpDS->Release(); - m_lpDS = NULL; - } -} - - -// Specifies whether you are in debug mode. - -void CSound::SetDebugMode(bool bMode) -{ - m_bDebugMode = bMode; -} - - -// Initializes DirectSound. - -bool CSound::Create(HWND hWnd, bool b3D) -{ - LPDIRECTSOUNDBUFFER primary; - DSBUFFERDESC dsbdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx; - HRESULT hr; - - if ( !DirectSoundCreate(NULL, &m_lpDS, NULL) == DS_OK ) - { - OutputDebugString("Fatal error: DirectSoundCreate\n"); - m_bEnable = false; - return false; - } - -//? m_lpDS->SetCooperativeLevel(hWnd, DSSCL_NORMAL); - m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY); - - if ( !RetSound3DCap() ) b3D = false; - - m_ctrl3D = false; - if ( b3D ) - { - // Obtain primary buffer, asking it for 3D control. - ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) ); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; - hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL ); - if ( hr == S_OK ) - { - m_ctrl3D = true; - } - } - - if ( !m_ctrl3D ) - { - // Obtain primary buffer, without 3D control. - ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) ); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; - hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL ); - if ( hr != S_OK ) - { - return false; - } - m_ctrl3D = false; - } - - if ( m_ctrl3D ) - { - hr = primary->QueryInterface( IID_IDirectSound3DListener, - (VOID**)&m_listener ); - if ( hr != S_OK ) - { - primary->Release(); - return false; - } - } - - // Set primary buffer format to 44kHz and 16-bit output. - ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = 2; - wfx.nSamplesPerSec = 22050; -//? wfx.nSamplesPerSec = 44100; - wfx.wBitsPerSample = 16; - wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; - wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; - hr = primary->SetFormat(&wfx); - if ( hr != S_OK ) - { - DisplayError("SetFormat", SOUND_CLICK, hr); - } - - // Release the primary buffer, since it is not need anymore. - primary->Release(); - - // Search the maximum possible voices. - if ( m_ctrl3D ) - { - ZeroMemory( &dscaps, sizeof(DSCAPS) ); - dscaps.dwSize = sizeof(DSCAPS); - hr = m_lpDS->GetCaps(&dscaps); - if ( hr == DS_OK ) - { - m_maxSound = dscaps.dwMaxHwMixingAllBuffers; - if ( dscaps.dwMaxHw3DAllBuffers > 0 && - m_maxSound > (int)dscaps.dwMaxHw3DAllBuffers ) - { - m_maxSound = dscaps.dwMaxHw3DAllBuffers; - } - if ( m_maxSound > MAXSOUND ) m_maxSound = MAXSOUND; - } - } - - m_bEnable = true; - m_hWnd = hWnd; - return true; -} - - -// Indicates whether to play sounds in 3D or not. - -void CSound::SetSound3D(bool bMode) -{ - StopAll(); - - if ( m_listener != NULL ) - { - m_listener->Release(); - m_listener = NULL; - } - - if ( m_lpDS != NULL ) - { - m_lpDS->Release(); - m_lpDS = NULL; - } - - Create(m_hWnd, bMode); -} - -bool CSound::RetSound3D() -{ - return m_ctrl3D; -} - -// Indicates whether it is possible to play sounds in 3D. - -bool CSound::RetSound3DCap() -{ - DSCAPS dscaps; - HRESULT hr; - - ZeroMemory( &dscaps, sizeof(DSCAPS) ); - dscaps.dwSize = sizeof(DSCAPS); - hr = m_lpDS->GetCaps(&dscaps); - if ( hr != DS_OK ) return false; - - return ( dscaps.dwMaxHw3DAllBuffers > 0 ); -} - - - -// Returns the state of DirectSound. - -bool CSound::RetEnable() -{ - return m_bEnable; -} - - -// Switches on or off the sound. - -void CSound::SetState(bool bState) -{ - m_bState = bState; -} - -// Specifies the pathname to the CD. - -void CSound::SetCDpath(char *path) -{ - strcpy(m_CDpath, path); -} - -// Switches on or off the CD-audio music. - -void CSound::SetAudioTrack(bool bAudio) -{ - m_bAudioTrack = bAudio; -} - - -// Manages volumes of audio (. Wav) and midi (. Mid). - -void CSound::SetAudioVolume(int volume) -{ - m_audioVolume = volume; -} - -int CSound::RetAudioVolume() -{ - if ( !m_bEnable ) return 0; - return m_audioVolume; -} - -void CSound::SetMidiVolume(int volume) -{ - m_midiVolume = volume; - - if ( m_bAudioTrack ) - { - InitAudioTrackVolume(m_midiVolume); - } -} - -int CSound::RetMidiVolume() -{ - if ( !m_bEnable ) return 0; - return m_midiVolume; -} - - -// Reads a file. - -bool CSound::ReadFile(Sound sound, char *metaname, char *filename) -{ - WaveHeader wavHdr; - DWORD size; - int err; - - // Open the wave file. - err = g_metafile.Open(metaname, filename); - if ( err != 0 ) return false; - - // Read in the wave header. - g_metafile.Read(&wavHdr, sizeof(wavHdr)); - - // Figure out the size of the data region. - size = wavHdr.dwDSize; - - if ( m_files[sound] != 0 ) - { - free(m_files[sound]); - } - m_files[sound] = (char*)malloc(sizeof(WaveHeader)+size); - - memcpy(m_files[sound], &wavHdr, sizeof(WaveHeader)); - g_metafile.Read(m_files[sound]+sizeof(WaveHeader), size); - - // Close out the wave file. - g_metafile.Close(); - return true; -} - -// Hides all sound files (. Wav). - -void CSound::CacheAll() -{ - int i; - char meta[50]; - char name[50]; - - if ( !m_bEnable ) return; - - if ( m_bDebugMode ) - { - strcpy(meta, ""); - } - else - { -#if _SCHOOL - strcpy(meta, "ceebot3.dat"); -#else - strcpy(meta, "colobot3.dat"); -#endif - } - - for ( i=0 ; iGetStatus(&status); - if ( (status&DSBSTATUS_PLAYING) == 0 ) - { - m_channel[i].priority = priority; - m_channel[i].uniqueStamp = m_uniqueStamp++; - channel = i; - bAlreadyLoaded = true; - return true; - } - } -#endif - - // Seeks a channel completely free. - for ( i=0 ; iGetStatus(&status); - if ( (status&DSBSTATUS_PLAYING) == 0 ) - { - m_channel[i].soundBuffer->Release(); - m_channel[i].soundBuffer = 0; - m_channel[i].priority = priority; - m_channel[i].uniqueStamp = m_uniqueStamp++; - - channel = i; - bAlreadyLoaded = false; - return true; - } - } - - // Seeks a lower priority channel used. - for ( i=0 ; i= priority ) continue; - - m_channel[i].soundBuffer->Stop(); - m_channel[i].soundBuffer->Release(); - m_channel[i].soundBuffer = 0; - m_channel[i].priority = priority; - m_channel[i].uniqueStamp = m_uniqueStamp++; - - channel = i; - bAlreadyLoaded = false; - return true; - } - - // Seeks a channel used the same or lower priority. - for ( i=0 ; i priority ) continue; - - m_channel[i].soundBuffer->Stop(); - m_channel[i].soundBuffer->Release(); - m_channel[i].soundBuffer = 0; - m_channel[i].priority = priority; - m_channel[i].uniqueStamp = m_uniqueStamp++; - - channel = i; - bAlreadyLoaded = false; - return true; - } - - char s[100]; - sprintf(s, "Sound %d forget (priority=%d)\n", sound, priority); - OutputDebugString(s); - - return false; -} - -// Reads in data from a wave file. - -bool CSound::ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size) -{ - LPVOID pData1; - DWORD dwData1Size; - LPVOID pData2; - DWORD dwData2Size; - HRESULT hr; - - // Lock data in buffer for writing. - hr = lpDSB->Lock(0, size, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR); - if ( hr != DS_OK ) - { - return false; - } - - // Read in first chunk of data. - if ( dwData1Size > 0 ) - { - memcpy(pData1, m_files[sound]+sizeof(WaveHeader), dwData1Size); - } - - // Read in second chunk if necessary. - if ( dwData2Size > 0 ) - { - memcpy(pData2, m_files[sound]+sizeof(WaveHeader)+dwData1Size, dwData2Size); - } - - // Unlock data in buffer. - hr = lpDSB->Unlock(pData1, dwData1Size, pData2, dwData2Size); - if ( hr != DS_OK ) - { - return false; - } - - return true; -} - -// Creates a DirectSound buffer. - -bool CSound::CreateSoundBuffer(int channel, DWORD size, DWORD freq, - DWORD bitsPerSample, DWORD blkAlign, - bool bStereo) -{ - PCMWAVEFORMAT pcmwf; - DSBUFFERDESC dsbdesc; - DS3DBUFFER bufferParams; // 3D buffer properties - HRESULT hr; - - // Set up wave format structure. - memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) ); - pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; - pcmwf.wf.nChannels = bStereo ? 2 : 1; - pcmwf.wf.nSamplesPerSec = freq; - pcmwf.wf.nBlockAlign = (WORD)blkAlign; - pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; - pcmwf.wBitsPerSample = (WORD)bitsPerSample; - - // Set up DSBUFFERDESC structure. - memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. - dsbdesc.dwSize = sizeof(DSBUFFERDESC); - if ( m_ctrl3D ) - { - dsbdesc.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_MUTE3DATMAXDISTANCE| - DSBCAPS_LOCDEFER| - DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY; - } - else - { - dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY; - } - dsbdesc.dwBufferBytes = size; - dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; - - hr = m_lpDS->CreateSoundBuffer(&dsbdesc, &m_channel[channel].soundBuffer, NULL); - if ( hr != DS_OK ) return false; - - if ( m_ctrl3D ) - { - hr = m_channel[channel].soundBuffer->QueryInterface - ( - IID_IDirectSound3DBuffer, - (VOID**)&m_channel[channel].soundBuffer3D - ); - if ( hr != DS_OK ) return false; - } - - m_channel[channel].bUsed = true; - m_channel[channel].bMute = false; - return true; -} - -// Creates a DirectSound buffer from a wave file. - -bool CSound::CreateBuffer(int channel, Sound sound) -{ - WaveHeader* wavHdr; - DWORD size; - bool bStereo; - - if ( m_files[sound] == 0 ) return false; - - wavHdr = (WaveHeader*)m_files[sound]; - size = wavHdr->dwDSize; - bStereo = wavHdr->wChnls > 1 ? true : false; - - // Create the sound buffer for the wave file. - if ( !CreateSoundBuffer(channel, size, wavHdr->dwSRate, - wavHdr->BitsPerSample, wavHdr->wBlkAlign, bStereo) ) - { - return false; - } - - // Read the data for the wave file into the sound buffer. - if ( !ReadData(m_channel[channel].soundBuffer, sound, size) ) - { - return false; - } - - m_channel[channel].type = sound; - - // Close out the wave file. - return true; -} - -// Calculates the volume and pan of a sound, non-3D mode. - -void CSound::ComputeVolumePan2D(int channel, const Math::Vector &pos) -{ - float dist, a, g; - - if ( pos.x == m_eye.x && - pos.y == m_eye.y && - pos.z == m_eye.z ) - { - m_channel[channel].volume = 1.0f; // maximum volume - m_channel[channel].pan = 0.0f; // at the center - return; - } - -#if _TEEN - dist = Math::Distance(pos, m_eye); - if ( dist >= 210.0f ) // very far? - { - m_channel[channel].volume = 0.0f; // silence - m_channel[channel].pan = 0.0f; // at the center - return; - } - if ( dist <= 10.0f ) // very close? - { - m_channel[channel].volume = 1.0f; // maximum volume - m_channel[channel].pan = 0.0f; // at the center - return; - } - m_channel[channel].volume = 1.0f-((dist-10.0f)/200.0f); -#else - dist = Math::Distance(pos, m_eye); - if ( dist >= 110.0f ) // very far? - { - m_channel[channel].volume = 0.0f; // silence - m_channel[channel].pan = 0.0f; // at the center - return; - } - if ( dist <= 10.0f ) // very close? - { - m_channel[channel].volume = 1.0f; // maximum volume - m_channel[channel].pan = 0.0f; // at the center - return; - } - m_channel[channel].volume = 1.0f-((dist-10.0f)/100.0f); -#endif - - a = Math::RotateAngle(m_lookat.x-m_eye.x, m_eye.z-m_lookat.z); - g = Math::RotateAngle(pos.x-m_eye.x, m_eye.z-pos.z); - m_channel[channel].pan = sinf(Math::Direction(a, g)); -} - -// Sounds in the middle. -// Returns the associated channel or -1. - -int CSound::Play(Sound sound, float amplitude, float frequency, bool bLoop) -{ - return Play(sound, m_lookat, amplitude, frequency, bLoop); -} - -// Sounds at a given position. -// Returns the associated channel or -1. - -int CSound::Play(Sound sound, Math::Vector pos, - float amplitude, float frequency, bool bLoop) -{ - DS3DBUFFER sb; - int channel, iVolume, iPan, iFreq, uniqueStamp; - bool bAlreadyLoaded; - DWORD flag, freq; - HRESULT err; - - if ( !m_bEnable ) return -1; - if ( !m_bState || m_audioVolume == 0 ) return -1; - -//? if ( Math::Distance(pos, m_eye) > 100.0f ) return -1; - - if ( !SearchFreeBuffer(sound, channel, bAlreadyLoaded) ) return -1; - - if ( !bAlreadyLoaded ) - { - if ( !CreateBuffer(channel, sound) ) - { - if ( m_channel[channel].bUsed && - m_channel[channel].soundBuffer != 0 ) - { - m_channel[channel].soundBuffer->Release(); - m_channel[channel].soundBuffer = 0; - } - m_channel[channel].bUsed = false; - return -1; - } - } - - m_channel[channel].pos = pos; - - if ( m_ctrl3D ) - { - m_channel[channel].volume = 1.0f; - m_channel[channel].pan = 0.0f; - } - else - { - ComputeVolumePan2D(channel, pos); - } - -#if 0 - DWORD status; - m_channel[channel].soundBuffer->GetStatus(&status); - char s[100]; - sprintf(s, "Play sound=%d status=%d channel=%d flag=%d\n", sound, status, channel, bAlreadyLoaded); - OutputDebugString(s); -#endif - - m_channel[channel].oper[0].bUsed = false; - m_channel[channel].startAmplitude = amplitude; - m_channel[channel].startFrequency = frequency; - m_channel[channel].changeFrequency = 1.0f; - - if ( m_ctrl3D ) - { - sb.dwSize = sizeof(DS3DBUFFER); - err = m_channel[channel].soundBuffer3D->GetAllParameters(&sb); - DisplayError("GetAllParameters", sound, err); - - sb.vPosition = VEC_TO_D3DVEC(pos); -//? sb.dwInsideConeAngle = 90; -//? sb.dwOutsideConeAngle = 180; -//? sb.vConeOrientation = Math::Vector(0.0f, 1.0f, 0.0f); - sb.lConeOutsideVolume = DSBVOLUME_MIN; -#if _TEEN - sb.flMinDistance = 50.0f; -#else - sb.flMinDistance = 20.0f; -#endif - sb.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; - - err = m_channel[channel].soundBuffer3D->SetAllParameters(&sb, DS3D_IMMEDIATE); - DisplayError("SetAllParameters", sound, err); - } - - amplitude *= m_channel[channel].volume; - amplitude *= (float)m_audioVolume/MAXVOLUME; - iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f); - if ( iVolume > 0 ) iVolume = 0; - err = m_channel[channel].soundBuffer->SetVolume(iVolume); - DisplayError("SetVolume", sound, err); - - if ( !m_ctrl3D ) - { - iPan = (int)(m_channel[channel].pan*10000.0f); - err = m_channel[channel].soundBuffer->SetPan(iPan); - DisplayError("SetPan", sound, err); - } - - if ( !bAlreadyLoaded ) - { - err = m_channel[channel].soundBuffer->GetFrequency(&freq); - DisplayError("GetFrequency", sound, err); - m_channel[channel].initFrequency = freq; - } - iFreq = (int)(frequency*m_channel[channel].initFrequency); - err = m_channel[channel].soundBuffer->SetFrequency(iFreq); - DisplayError("SetFrequency", sound, err); - - err = m_channel[channel].soundBuffer->SetCurrentPosition(0); - DisplayError("SetCurrentPosition", sound, err); - - flag = bLoop?DSBPLAY_LOOPING:0; -//? flag |= DSBPLAY_LOCHARDWARE|DSBPLAY_TERMINATEBY_DISTANCE; -//? flag |= DSBPLAY_TERMINATEBY_DISTANCE; - err = m_channel[channel].soundBuffer->Play(0, 0, flag); - DisplayError("Play", sound, err); - if ( err == DSERR_BADFORMAT ) - { - iFreq = m_channel[channel].initFrequency; - err = m_channel[channel].soundBuffer->SetFrequency(iFreq); - DisplayError("SetFrequency (repeat)", sound, err); - - err = m_channel[channel].soundBuffer->Play(0, 0, flag); - DisplayError("Play (repeat)", sound, err); - } - - uniqueStamp = m_channel[channel].uniqueStamp; - return channel | ((uniqueStamp&0xffff)<<16); -} - -// Check a channel number. -// Adapts the channel, so it can be used as an offset in m_channel. - -bool CSound::CheckChannel(int &channel) -{ - int uniqueStamp; - - uniqueStamp = (channel>>16)&0xffff; - channel &= 0xffff; - - if ( !m_bEnable ) return false; - if ( !m_bState || m_audioVolume == 0 ) return false; - - if ( channel < 0 || channel >= m_maxSound ) return false; - if ( !m_channel[channel].bUsed ) return false; - - if ( m_channel[channel].uniqueStamp != uniqueStamp ) return false; - - return true; -} - -// Removes all envelopes. - -bool CSound::FlushEnvelope(int channel) -{ - if ( !CheckChannel(channel) ) return false; - - m_channel[channel].oper[0].bUsed = false; - return true; -} - -// Adds an operation envelope. - -bool CSound::AddEnvelope(int channel, float amplitude, float frequency, - float time, SoundNext oper) -{ - int i; - - if ( !CheckChannel(channel) ) return false; - - for ( i=0 ; iSetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED); - } - else - { - ComputeVolumePan2D(channel, pos); - - if ( !m_channel[channel].oper[0].bUsed ) - { - amplitude = m_channel[channel].startAmplitude; - amplitude *= m_channel[channel].volume; - amplitude *= (float)m_audioVolume/MAXVOLUME; - iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f); - if ( iVolume > 0 ) iVolume = 0; - err = m_channel[channel].soundBuffer->SetVolume(iVolume); - DisplayError("SetVolume", m_channel[channel].type, err); - } - - pan = m_channel[channel].pan; - iPan = (int)(pan*10000.0f); - err = m_channel[channel].soundBuffer->SetPan(iPan); - DisplayError("SetPan", m_channel[channel].type, err); - } - return true; -} - -// Changes the frequency of a sound. -// 0.5 down of an octave and 2.0 up of an octave. - -bool CSound::Frequency(int channel, float frequency) -{ - HRESULT err; - int iFreq; - - if ( !CheckChannel(channel) ) return false; - - m_channel[channel].changeFrequency = frequency; - - if ( !m_channel[channel].oper[0].bUsed ) - { - iFreq = (int)(frequency*m_channel[channel].initFrequency); - err = m_channel[channel].soundBuffer->SetFrequency(iFreq); - DisplayError("Frequency", m_channel[channel].type, err); - } - - return true; -} - -// Stops sound. - -bool CSound::Stop(int channel) -{ - if ( !CheckChannel(channel) ) return false; - - m_channel[channel].soundBuffer->Stop(); - return true; -} - -// Stops all sounds. - -bool CSound::StopAll() -{ - DWORD status; - int i; - - for ( i=0 ; iGetStatus(&status); - if ( (status&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING ) - { - m_channel[i].soundBuffer->Stop(); - } - m_channel[i].soundBuffer->Stop(); - m_channel[i].soundBuffer->Release(); - m_channel[i].soundBuffer = 0; - - m_channel[i].bUsed = false; - } - return true; -} - -// Silent all sounds. - -bool CSound::MuteAll(bool bMute) -{ - int i; - - for ( i=0 ; iSetVolume(-10000); // silence - continue; - } - - m_channel[i].oper[0].currentTime += rTime; - - progress = m_channel[i].oper[0].currentTime / m_channel[i].oper[0].totalTime; - if ( progress > 1.0f ) progress = 1.0f; - - volume = progress; - volume *= m_channel[i].oper[0].finalAmplitude-m_channel[i].startAmplitude; - volume += m_channel[i].startAmplitude; - volume *= m_channel[i].volume; - volume *= (float)m_audioVolume/MAXVOLUME; - iVolume = (int)((powf(volume, 0.2f)-1.0f)*10000.0f); - if ( iVolume > 0 ) iVolume = 0; - m_channel[i].soundBuffer->SetVolume(iVolume); - - freq = progress; - freq *= m_channel[i].oper[0].finalFrequency-m_channel[i].startFrequency; - freq += m_channel[i].startFrequency; - freq *= m_channel[i].changeFrequency; - iFreq = (int)(freq*m_channel[i].initFrequency); - err = m_channel[i].soundBuffer->SetFrequency(iFreq); - DisplayError("FrameMove::Frequency", m_channel[i].type, err); - - if ( m_channel[i].oper[0].currentTime >= - m_channel[i].oper[0].totalTime ) - { - next = m_channel[i].oper[0].nextOper; - - if ( next == SOPER_LOOP ) - { - m_channel[i].oper[0].currentTime = 0.0f; - } - else - { - OperNext(i); - - if ( next == SOPER_STOP ) - { - m_channel[i].soundBuffer->Stop(); - } - } - } - } - - m_lastTime += rTime; - if ( m_lastTime >= 0.05f && m_listener != 0 ) - { - m_lastTime = 0.0f; - m_listener->CommitDeferredSettings(); - } -} - -// Specifies the position of the listener. -// Must be called whenever the camera moves. - -void CSound::SetListener(Math::Vector eye, Math::Vector lookat) -{ - DS3DLISTENER listenerParams; - HRESULT err; - float amplitude, pan; - int i, iVolume, iPan; - - m_eye = eye; - m_lookat = lookat; - - if ( m_listener == 0 ) - { - if ( m_ctrl3D ) return; - - for ( i=0 ; i 0 ) iVolume = 0; - err = m_channel[i].soundBuffer->SetVolume(iVolume); - DisplayError("SetVolume", m_channel[i].type, err); - } - - pan = m_channel[i].pan; - iPan = (int)(pan*10000.0f); - err = m_channel[i].soundBuffer->SetPan(iPan); - DisplayError("SetPan", m_channel[i].type, err); - } - return; - } - - // Get listener parameters. - listenerParams.dwSize = sizeof(DS3DLISTENER); - m_listener->GetAllParameters(&listenerParams); - - listenerParams.vPosition = VEC_TO_D3DVEC(eye); - listenerParams.vOrientFront = VEC_TO_D3DVEC(lookat-eye); - listenerParams.vOrientTop = D3DVECTOR(0.0f, 1.0f, 0.0f); - listenerParams.flDistanceFactor = 10.0f; - listenerParams.flRolloffFactor = 1.0f; - - m_listener->SetAllParameters(&listenerParams, DS3D_DEFERRED); -} - - - - -// Uses MCI to play a MIDI file. The window procedure -// is notified when playback is complete. - -bool CSound::PlayMusic(int rank, bool bRepeat) -{ - MCI_OPEN_PARMS mciOpenParms; - MCI_PLAY_PARMS mciPlayParms; - DWORD dwReturn; - char filename[MAX_PATH]; - - m_bRepeatMusic = bRepeat; - m_playTime = 0.0f; - - if ( m_midiVolume == 0 ) return true; - - if ( m_bAudioTrack ) - { - return PlayAudioTrack(rank); - } - - if ( !m_bEnable ) return true; - InitMidiVolume(m_midiVolume); - m_lastMidiVolume = m_midiVolume; - - GetCurrentDir(filename, MAX_PATH-30); - sprintf(filename+strlen(filename), "sound\\music%.3d.blp", rank-1); - - // Open the device by specifying the device and filename. - // MCI will attempt to choose the MIDI mapper as the output port. - mciOpenParms.lpstrDeviceType = "sequencer"; - mciOpenParms.lpstrElementName = filename; - dwReturn = mciSendCommand(NULL, - MCI_OPEN, - MCI_OPEN_TYPE|MCI_OPEN_ELEMENT, - (DWORD)(LPVOID)&mciOpenParms); - if ( dwReturn != 0 ) - { - mciGetErrorString(dwReturn, filename, 128); - // Failed to open device. Don't close it; just return error. - return false; - } - - // The device opened successfully; get the device ID. - m_MidiDeviceID = mciOpenParms.wDeviceID; - - // Begin playback. - mciPlayParms.dwCallback = (DWORD)m_hWnd; - dwReturn = mciSendCommand(m_MidiDeviceID, - MCI_PLAY, - MCI_NOTIFY, - (DWORD)(LPVOID)&mciPlayParms); - if ( dwReturn != 0 ) - { - mciGetErrorString(dwReturn, filename, 128); - StopMusic(); - return false; - } - - m_MIDIMusic = rank; - return true; -} - -// Uses MCI to play a CD-audio track. The window procedure -// is notified when playback is complete. -// The rank parameter is in space [1..n] ! -// For CD mix (data/audio), it will be [2..n] ! - -bool CSound::PlayAudioTrack(int rank) -{ -#if _SOUNDTRACKS - MCI_OPEN_PARMS mciOpenParms; - MCI_PLAY_PARMS mciPlayParms; - MCI_SET_PARMS mciSetParms; - DWORD dwReturn; - char filename[MAX_PATH]; - char device[10]; - - if ( !m_bEnable ) return true; -//? if ( m_midiVolume == 0 ) return true; - InitAudioTrackVolume(m_midiVolume); - m_lastMidiVolume = m_midiVolume; - - // Open the device by specifying the device and filename. - // MCI will attempt to choose the MIDI mapper as the output port. - memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS)); -//? mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; -//? dwReturn = mciSendCommand(NULL, -//? MCI_OPEN, -//? MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, -//? (DWORD)(LPVOID)&mciOpenParms); - mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; - if ( m_CDpath[0] == 0 ) - { - dwReturn = mciSendCommand(NULL, - MCI_OPEN, - MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, - (DWORD)(LPVOID)&mciOpenParms); - } - else - { - device[0] = m_CDpath[0]; - device[1] = ':'; - device[2] = 0; - mciOpenParms.lpstrElementName = device; - dwReturn = mciSendCommand(NULL, - MCI_OPEN, - MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT, - (DWORD)(LPVOID)&mciOpenParms); - } - if ( dwReturn != 0 ) - { - mciGetErrorString(dwReturn, filename, 128); - // Failed to open device. Don't close it; just return error. - return false; - } - - // The device opened successfully; get the device ID. - m_MidiDeviceID = mciOpenParms.wDeviceID; - - // Set the time format to track/minute/second/frame (TMSF). - memset(&mciSetParms, 0, sizeof(MCI_SET_PARMS)); - mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF; - dwReturn = mciSendCommand(m_MidiDeviceID, - MCI_SET, - MCI_SET_TIME_FORMAT, - (DWORD)&mciSetParms); - if ( dwReturn != 0 ) - { - mciGetErrorString(dwReturn, filename, 128); - StopMusic(); - return false; - } - - // Begin playback. - memset(&mciPlayParms, 0, sizeof(MCI_PLAY_PARMS)); - mciPlayParms.dwCallback = (DWORD)m_hWnd; - mciPlayParms.dwFrom = MCI_MAKE_TMSF(rank+0, 0, 0, 0); - mciPlayParms.dwTo = MCI_MAKE_TMSF(rank+1, 0, 0, 0); - dwReturn = mciSendCommand(m_MidiDeviceID, - MCI_PLAY, - MCI_NOTIFY|MCI_FROM|MCI_TO, - (DWORD)(LPVOID)&mciPlayParms); - if ( dwReturn != 0 ) - { - mciGetErrorString(dwReturn, filename, 128); - StopMusic(); - return false; - } - - m_MIDIMusic = rank; -#endif - return true; -} - -// Restart the MIDI player. - -bool CSound::RestartMusic() -{ - if ( !m_bRepeatMusic ) return false; - - OutputDebugString("RestartMusic\n"); - if ( !m_bEnable ) return true; -//? if ( m_midiVolume == 0 ) return true; - if ( m_MIDIMusic == 0 ) return false; - if ( m_playTime < 5.0f ) return false; - - return PlayMusic(m_MIDIMusic, true); -} - -// Shuts down the MIDI player. - -void CSound::SuspendMusic() -{ - if ( !m_bEnable ) return; - -//? if ( m_MidiDeviceID && m_midiVolume != 0 ) - if ( m_MidiDeviceID ) - { - if ( m_bAudioTrack ) mciSendCommand(m_MidiDeviceID, MCI_STOP, 0, NULL); - mciSendCommand(m_MidiDeviceID, MCI_CLOSE, 0, NULL); - } - m_MidiDeviceID = 0; -} - -// Shuts down the MIDI player. - -void CSound::StopMusic() -{ - SuspendMusic(); - m_MIDIMusic = 0; -} - -// Returns true if the music is in progress. - -bool CSound::IsPlayingMusic() -{ - return (m_MIDIMusic != 0); -} - -// Adjusts the volume of currently music, if necessary. - -void CSound::AdaptVolumeMusic() -{ - if ( m_midiVolume != m_lastMidiVolume ) - { - if ( m_bAudioTrack ) - { - InitAudioTrackVolume(m_midiVolume); - } - else - { - InitMidiVolume(m_midiVolume); - } - m_lastMidiVolume = m_midiVolume; - RestartMusic(); - } -} - +// * 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/. + +// sound.cpp + + +#include +#include +#include +#include +#include + +#include "common/language.h" +#include "common/struct.h" +#include "common/iman.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/math3d.h" +#include "old/sound.h" + + +///////////////////////////////////////////////////////////////////////////// + + +const int LXIMAGE = 640; +const int LYIMAGE = 480; + + + +// Header .WAV file. + +struct WaveHeader +{ + BYTE RIFF[4]; // "RIFF" + DWORD dwSize; // size of data to follow + BYTE WAVE[4]; // "WAVE" + BYTE fmt_[4]; // "fmt " + DWORD dw16; // 16 + WORD wOne_0; // 1 + WORD wChnls; // number of Channels + DWORD dwSRate; // sample Rate + DWORD BytesPerSec; // sample Rate + WORD wBlkAlign; // 1 + WORD BitsPerSample; // sample size + BYTE DATA[4]; // "DATA" + DWORD dwDSize; // number of Samples +}; + + + + +// Displays an error DirectSound. + +void DisplayError(char *name, Sound sound, HRESULT err) +{ + char s[100]; + unsigned int i = err; + if ( err == DS_OK ) return; + sprintf(s, "SoundError in %s, sound=%d err=%d\n", name, sound, i); + OutputDebugString(s); + + if ( err == DSERR_ALLOCATED ) OutputDebugString("DSERR_ALLOCATED\n"); + if ( err == DSERR_CONTROLUNAVAIL ) OutputDebugString("DSERR_CONTROLUNAVAIL\n"); + if ( err == DSERR_INVALIDPARAM ) OutputDebugString("DSERR_INVALIDPARAM\n"); + if ( err == DSERR_INVALIDCALL ) OutputDebugString("DSERR_INVALIDCALL\n"); + if ( err == DSERR_GENERIC ) OutputDebugString("DSERR_GENERIC\n"); + if ( err == DSERR_PRIOLEVELNEEDED ) OutputDebugString("DSERR_PRIOLEVELNEEDED\n"); + if ( err == DSERR_OUTOFMEMORY ) OutputDebugString("DSERR_OUTOFMEMORY\n"); + if ( err == DSERR_BADFORMAT ) OutputDebugString("DSERR_BADFORMAT\n"); + if ( err == DSERR_UNSUPPORTED ) OutputDebugString("DSERR_UNSUPPORTED\n"); + if ( err == DSERR_NODRIVER ) OutputDebugString("DSERR_NODRIVER\n"); + if ( err == DSERR_ALREADYINITIALIZED ) OutputDebugString("DSERR_ALREADYINITIALIZED\n"); + if ( err == DSERR_NOAGGREGATION ) OutputDebugString("DSERR_NOAGGREGATION\n"); + if ( err == DSERR_BUFFERLOST ) OutputDebugString("DSERR_BUFFERLOST\n"); + if ( err == DSERR_OTHERAPPHASPRIO ) OutputDebugString("DSERR_OTHERAPPHASPRIO\n"); + if ( err == DSERR_UNINITIALIZED ) OutputDebugString("DSERR_UNINITIALIZED\n"); + if ( err == DSERR_NOINTERFACE ) OutputDebugString("DSERR_NOINTERFACE\n"); + if ( err == DSERR_ACCESSDENIED ) OutputDebugString("DSERR_ACCESSDENIED\n"); +} + +// Returns the name of the current folder. + +void GetCurrentDir(char *pName, int lg) +{ + int i; + + strncpy(pName, _pgmptr, lg-1); + pName[lg-1] = 0; + + lg = strlen(pName); + if ( lg == 0 ) return; + + for ( i=0 ; i 0 ) + { + lg --; + if ( pName[lg] == '\\' ) + { + pName[lg+1] = 0; + break; + } + } + + if ( lg > 6 && strcmp(pName+lg-6, "\\debug\\") == 0 ) + { + pName[lg-5] = 0; // ignores the folder \debug! + } + + if ( lg > 6 && strcmp(pName+lg-6, "\\release\\") == 0 ) + { + pName[lg-7] = 0; // ignores the folder \release ! + } +} + + + + +///////////////////////////////////////////////////////////////////////////// + + +// Changes the volume of midi. +// The volume is between 0 and 20! + +void InitMidiVolume(int volume) +{ + int nb, i, n; + MMRESULT result; + HMIDIOUT hmo = 0; + + static int table[21] = + { + 0x00000000, + 0x11111111, + 0x22222222, + 0x33333333, + 0x44444444, + 0x55555555, + 0x66666666, + 0x77777777, + 0x88888888, + 0x99999999, + 0xAAAAAAAA, + 0xBBBBBBBB, + 0xCCCCCCCC, + 0xDDDDDDDD, + 0xEEEEEEEE, + 0xF222F222, + 0xF555F555, + 0xF777F777, + 0xFAAAFAAA, + 0xFDDDFDDD, + 0xFFFFFFFF, + }; + + if ( volume < 0 ) volume = 0; + if ( volume > MAXVOLUME ) volume = MAXVOLUME; + + nb = midiOutGetNumDevs(); + for ( i=0 ; i MAXVOLUME ) volume = MAXVOLUME; + + // Open the mixer. This opens the mixer with a deviceID of 0. If you + // have a single sound card/mixer, then this will open it. If you have + // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and + // so on. + rc = mixerOpen(&hMixer, 0,0,0,0); + if ( rc != MMSYSERR_NOERROR ) + { + return false; // Couldn't open the mixer. + } + + // Initialize MIXERLINE structure. + ZeroMemory(&mxl,sizeof(mxl)); + mxl.cbStruct = sizeof(mxl); + + // Specify the line you want to get. You are getting the input line + // here. If you want to get the output line, you need to use + // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT. + mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC; + + rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl, + MIXER_GETLINEINFOF_COMPONENTTYPE); + if ( rc != MMSYSERR_NOERROR ) + { + return false; // Couldn't get the mixer line. + } + + // Get the control. + ZeroMemory(&mxlc, sizeof(mxlc)); + mxlc.cbStruct = sizeof(mxlc); + mxlc.dwLineID = mxl.dwLineID; +//? mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER; +//? mxlc.dwControlType = MIXERCONTROL_CONTROLF_UNIFORM; + mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mxlc.cControls = 1; + mxlc.cbmxctrl = sizeof(mxc); + mxlc.pamxctrl = &mxc; + ZeroMemory(&mxc, sizeof(mxc)); + mxc.cbStruct = sizeof(mxc); + rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc, + MIXER_GETLINECONTROLSF_ONEBYTYPE); +//? MIXER_GETLINECONTROLSF_ALL); + if ( rc != MMSYSERR_NOERROR ) + { + return false; // Couldn't get the control. + } + + // After successfully getting the peakmeter control, the volume range + // will be specified by mxc.Bounds.lMinimum to mxc.Bounds.lMaximum. + + MIXERCONTROLDETAILS mxcd; // Gets the control values. + MIXERCONTROLDETAILS_SIGNED volStruct; // Gets the control values. + + volStruct.lValue = volume*(mxc.Bounds.lMaximum-mxc.Bounds.lMinimum); + volStruct.lValue /= MAXVOLUME; + volStruct.lValue += mxc.Bounds.lMinimum; + + // Initialize the MIXERCONTROLDETAILS structure + ZeroMemory(&mxcd, sizeof(mxcd)); + mxcd.cbStruct = sizeof(mxcd); + mxcd.cbDetails = sizeof(volStruct); + mxcd.dwControlID = mxc.dwControlID; + mxcd.paDetails = &volStruct; + mxcd.cChannels = 1; + + // Get the current value of the peakmeter control. Typically, you + // would set a timer in your program to query the volume every 10th + // of a second or so. + rc = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd, + MIXER_SETCONTROLDETAILSF_VALUE); + if ( rc != MMSYSERR_NOERROR ) + { + return false; // Couldn't get the current volume. + } +#endif + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// + + +// Constructor. + +CSound::CSound(CInstanceManager* iMan) +{ + int i; + + m_iMan = iMan; + m_iMan->AddInstance(CLASS_SOUND, this); + + m_bEnable = false; + m_bState = false; + m_bAudioTrack = true; + m_ctrl3D = true; + m_bDebugMode = false; + m_MidiDeviceID = 0; + m_MIDIMusic = 0; + m_audioVolume = 20; + m_midiVolume = 15; + m_lastMidiVolume = 0; + m_listener = 0; + m_lastTime = 0.0f; + m_playTime = 0.0f; + m_uniqueStamp = 0; + m_maxSound = MAXSOUND; + m_eye = Math::Vector(0.0f, 0.0f, 0.0f); + m_hWnd = 0; + + m_lpDS = NULL; + + ZeroMemory(m_channel, sizeof(SoundChannel)*MAXSOUND); + for ( i=0 ; iStop(); + m_channel[i].soundBuffer->Release(); + m_channel[i].soundBuffer = 0; + m_channel[i].bUsed = false; + } + } + + if ( m_listener != NULL ) + { + m_listener->Release(); + m_listener = NULL; + } + + if ( m_lpDS != NULL ) + { + m_lpDS->Release(); + m_lpDS = NULL; + } +} + + +// Specifies whether you are in debug mode. + +void CSound::SetDebugMode(bool bMode) +{ + m_bDebugMode = bMode; +} + + +// Initializes DirectSound. + +bool CSound::Create(HWND hWnd, bool b3D) +{ + LPDIRECTSOUNDBUFFER primary; + DSBUFFERDESC dsbdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + HRESULT hr; + + if ( !DirectSoundCreate(NULL, &m_lpDS, NULL) == DS_OK ) + { + OutputDebugString("Fatal error: DirectSoundCreate\n"); + m_bEnable = false; + return false; + } + +//? m_lpDS->SetCooperativeLevel(hWnd, DSSCL_NORMAL); + m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY); + + if ( !RetSound3DCap() ) b3D = false; + + m_ctrl3D = false; + if ( b3D ) + { + // Obtain primary buffer, asking it for 3D control. + ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) ); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL ); + if ( hr == S_OK ) + { + m_ctrl3D = true; + } + } + + if ( !m_ctrl3D ) + { + // Obtain primary buffer, without 3D control. + ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) ); + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; + hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL ); + if ( hr != S_OK ) + { + return false; + } + m_ctrl3D = false; + } + + if ( m_ctrl3D ) + { + hr = primary->QueryInterface( IID_IDirectSound3DListener, + (VOID**)&m_listener ); + if ( hr != S_OK ) + { + primary->Release(); + return false; + } + } + + // Set primary buffer format to 44kHz and 16-bit output. + ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 2; + wfx.nSamplesPerSec = 22050; +//? wfx.nSamplesPerSec = 44100; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + hr = primary->SetFormat(&wfx); + if ( hr != S_OK ) + { + DisplayError("SetFormat", SOUND_CLICK, hr); + } + + // Release the primary buffer, since it is not need anymore. + primary->Release(); + + // Search the maximum possible voices. + if ( m_ctrl3D ) + { + ZeroMemory( &dscaps, sizeof(DSCAPS) ); + dscaps.dwSize = sizeof(DSCAPS); + hr = m_lpDS->GetCaps(&dscaps); + if ( hr == DS_OK ) + { + m_maxSound = dscaps.dwMaxHwMixingAllBuffers; + if ( dscaps.dwMaxHw3DAllBuffers > 0 && + m_maxSound > (int)dscaps.dwMaxHw3DAllBuffers ) + { + m_maxSound = dscaps.dwMaxHw3DAllBuffers; + } + if ( m_maxSound > MAXSOUND ) m_maxSound = MAXSOUND; + } + } + + m_bEnable = true; + m_hWnd = hWnd; + return true; +} + + +// Indicates whether to play sounds in 3D or not. + +void CSound::SetSound3D(bool bMode) +{ + StopAll(); + + if ( m_listener != NULL ) + { + m_listener->Release(); + m_listener = NULL; + } + + if ( m_lpDS != NULL ) + { + m_lpDS->Release(); + m_lpDS = NULL; + } + + Create(m_hWnd, bMode); +} + +bool CSound::RetSound3D() +{ + return m_ctrl3D; +} + +// Indicates whether it is possible to play sounds in 3D. + +bool CSound::RetSound3DCap() +{ + DSCAPS dscaps; + HRESULT hr; + + ZeroMemory( &dscaps, sizeof(DSCAPS) ); + dscaps.dwSize = sizeof(DSCAPS); + hr = m_lpDS->GetCaps(&dscaps); + if ( hr != DS_OK ) return false; + + return ( dscaps.dwMaxHw3DAllBuffers > 0 ); +} + + + +// Returns the state of DirectSound. + +bool CSound::RetEnable() +{ + return m_bEnable; +} + + +// Switches on or off the sound. + +void CSound::SetState(bool bState) +{ + m_bState = bState; +} + +// Specifies the pathname to the CD. + +void CSound::SetCDpath(char *path) +{ + strcpy(m_CDpath, path); +} + +// Switches on or off the CD-audio music. + +void CSound::SetAudioTrack(bool bAudio) +{ + m_bAudioTrack = bAudio; +} + + +// Manages volumes of audio (. Wav) and midi (. Mid). + +void CSound::SetAudioVolume(int volume) +{ + m_audioVolume = volume; +} + +int CSound::RetAudioVolume() +{ + if ( !m_bEnable ) return 0; + return m_audioVolume; +} + +void CSound::SetMidiVolume(int volume) +{ + m_midiVolume = volume; + + if ( m_bAudioTrack ) + { + InitAudioTrackVolume(m_midiVolume); + } +} + +int CSound::RetMidiVolume() +{ + if ( !m_bEnable ) return 0; + return m_midiVolume; +} + + +// Reads a file. + +bool CSound::ReadFile(Sound sound, char *metaname, char *filename) +{ + WaveHeader wavHdr; + DWORD size; + int err; + + // Open the wave file. + err = g_metafile.Open(metaname, filename); + if ( err != 0 ) return false; + + // Read in the wave header. + g_metafile.Read(&wavHdr, sizeof(wavHdr)); + + // Figure out the size of the data region. + size = wavHdr.dwDSize; + + if ( m_files[sound] != 0 ) + { + free(m_files[sound]); + } + m_files[sound] = (char*)malloc(sizeof(WaveHeader)+size); + + memcpy(m_files[sound], &wavHdr, sizeof(WaveHeader)); + g_metafile.Read(m_files[sound]+sizeof(WaveHeader), size); + + // Close out the wave file. + g_metafile.Close(); + return true; +} + +// Hides all sound files (. Wav). + +void CSound::CacheAll() +{ + int i; + char meta[50]; + char name[50]; + + if ( !m_bEnable ) return; + + if ( m_bDebugMode ) + { + strcpy(meta, ""); + } + else + { +#if _SCHOOL + strcpy(meta, "ceebot3.dat"); +#else + strcpy(meta, "colobot3.dat"); +#endif + } + + for ( i=0 ; iGetStatus(&status); + if ( (status&DSBSTATUS_PLAYING) == 0 ) + { + m_channel[i].priority = priority; + m_channel[i].uniqueStamp = m_uniqueStamp++; + channel = i; + bAlreadyLoaded = true; + return true; + } + } +#endif + + // Seeks a channel completely free. + for ( i=0 ; iGetStatus(&status); + if ( (status&DSBSTATUS_PLAYING) == 0 ) + { + m_channel[i].soundBuffer->Release(); + m_channel[i].soundBuffer = 0; + m_channel[i].priority = priority; + m_channel[i].uniqueStamp = m_uniqueStamp++; + + channel = i; + bAlreadyLoaded = false; + return true; + } + } + + // Seeks a lower priority channel used. + for ( i=0 ; i= priority ) continue; + + m_channel[i].soundBuffer->Stop(); + m_channel[i].soundBuffer->Release(); + m_channel[i].soundBuffer = 0; + m_channel[i].priority = priority; + m_channel[i].uniqueStamp = m_uniqueStamp++; + + channel = i; + bAlreadyLoaded = false; + return true; + } + + // Seeks a channel used the same or lower priority. + for ( i=0 ; i priority ) continue; + + m_channel[i].soundBuffer->Stop(); + m_channel[i].soundBuffer->Release(); + m_channel[i].soundBuffer = 0; + m_channel[i].priority = priority; + m_channel[i].uniqueStamp = m_uniqueStamp++; + + channel = i; + bAlreadyLoaded = false; + return true; + } + + char s[100]; + sprintf(s, "Sound %d forget (priority=%d)\n", sound, priority); + OutputDebugString(s); + + return false; +} + +// Reads in data from a wave file. + +bool CSound::ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size) +{ + LPVOID pData1; + DWORD dwData1Size; + LPVOID pData2; + DWORD dwData2Size; + HRESULT hr; + + // Lock data in buffer for writing. + hr = lpDSB->Lock(0, size, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR); + if ( hr != DS_OK ) + { + return false; + } + + // Read in first chunk of data. + if ( dwData1Size > 0 ) + { + memcpy(pData1, m_files[sound]+sizeof(WaveHeader), dwData1Size); + } + + // Read in second chunk if necessary. + if ( dwData2Size > 0 ) + { + memcpy(pData2, m_files[sound]+sizeof(WaveHeader)+dwData1Size, dwData2Size); + } + + // Unlock data in buffer. + hr = lpDSB->Unlock(pData1, dwData1Size, pData2, dwData2Size); + if ( hr != DS_OK ) + { + return false; + } + + return true; +} + +// Creates a DirectSound buffer. + +bool CSound::CreateSoundBuffer(int channel, DWORD size, DWORD freq, + DWORD bitsPerSample, DWORD blkAlign, + bool bStereo) +{ + PCMWAVEFORMAT pcmwf; + DSBUFFERDESC dsbdesc; + DS3DBUFFER bufferParams; // 3D buffer properties + HRESULT hr; + + // Set up wave format structure. + memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) ); + pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; + pcmwf.wf.nChannels = bStereo ? 2 : 1; + pcmwf.wf.nSamplesPerSec = freq; + pcmwf.wf.nBlockAlign = (WORD)blkAlign; + pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; + pcmwf.wBitsPerSample = (WORD)bitsPerSample; + + // Set up DSBUFFERDESC structure. + memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out. + dsbdesc.dwSize = sizeof(DSBUFFERDESC); + if ( m_ctrl3D ) + { + dsbdesc.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_MUTE3DATMAXDISTANCE| + DSBCAPS_LOCDEFER| + DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY; + } + else + { + dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY; + } + dsbdesc.dwBufferBytes = size; + dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; + + hr = m_lpDS->CreateSoundBuffer(&dsbdesc, &m_channel[channel].soundBuffer, NULL); + if ( hr != DS_OK ) return false; + + if ( m_ctrl3D ) + { + hr = m_channel[channel].soundBuffer->QueryInterface + ( + IID_IDirectSound3DBuffer, + (VOID**)&m_channel[channel].soundBuffer3D + ); + if ( hr != DS_OK ) return false; + } + + m_channel[channel].bUsed = true; + m_channel[channel].bMute = false; + return true; +} + +// Creates a DirectSound buffer from a wave file. + +bool CSound::CreateBuffer(int channel, Sound sound) +{ + WaveHeader* wavHdr; + DWORD size; + bool bStereo; + + if ( m_files[sound] == 0 ) return false; + + wavHdr = (WaveHeader*)m_files[sound]; + size = wavHdr->dwDSize; + bStereo = wavHdr->wChnls > 1 ? true : false; + + // Create the sound buffer for the wave file. + if ( !CreateSoundBuffer(channel, size, wavHdr->dwSRate, + wavHdr->BitsPerSample, wavHdr->wBlkAlign, bStereo) ) + { + return false; + } + + // Read the data for the wave file into the sound buffer. + if ( !ReadData(m_channel[channel].soundBuffer, sound, size) ) + { + return false; + } + + m_channel[channel].type = sound; + + // Close out the wave file. + return true; +} + +// Calculates the volume and pan of a sound, non-3D mode. + +void CSound::ComputeVolumePan2D(int channel, const Math::Vector &pos) +{ + float dist, a, g; + + if ( pos.x == m_eye.x && + pos.y == m_eye.y && + pos.z == m_eye.z ) + { + m_channel[channel].volume = 1.0f; // maximum volume + m_channel[channel].pan = 0.0f; // at the center + return; + } + +#if _TEEN + dist = Math::Distance(pos, m_eye); + if ( dist >= 210.0f ) // very far? + { + m_channel[channel].volume = 0.0f; // silence + m_channel[channel].pan = 0.0f; // at the center + return; + } + if ( dist <= 10.0f ) // very close? + { + m_channel[channel].volume = 1.0f; // maximum volume + m_channel[channel].pan = 0.0f; // at the center + return; + } + m_channel[channel].volume = 1.0f-((dist-10.0f)/200.0f); +#else + dist = Math::Distance(pos, m_eye); + if ( dist >= 110.0f ) // very far? + { + m_channel[channel].volume = 0.0f; // silence + m_channel[channel].pan = 0.0f; // at the center + return; + } + if ( dist <= 10.0f ) // very close? + { + m_channel[channel].volume = 1.0f; // maximum volume + m_channel[channel].pan = 0.0f; // at the center + return; + } + m_channel[channel].volume = 1.0f-((dist-10.0f)/100.0f); +#endif + + a = Math::RotateAngle(m_lookat.x-m_eye.x, m_eye.z-m_lookat.z); + g = Math::RotateAngle(pos.x-m_eye.x, m_eye.z-pos.z); + m_channel[channel].pan = sinf(Math::Direction(a, g)); +} + +// Sounds in the middle. +// Returns the associated channel or -1. + +int CSound::Play(Sound sound, float amplitude, float frequency, bool bLoop) +{ + return Play(sound, m_lookat, amplitude, frequency, bLoop); +} + +// Sounds at a given position. +// Returns the associated channel or -1. + +int CSound::Play(Sound sound, Math::Vector pos, + float amplitude, float frequency, bool bLoop) +{ + DS3DBUFFER sb; + int channel, iVolume, iPan, iFreq, uniqueStamp; + bool bAlreadyLoaded; + DWORD flag, freq; + HRESULT err; + + if ( !m_bEnable ) return -1; + if ( !m_bState || m_audioVolume == 0 ) return -1; + +//? if ( Math::Distance(pos, m_eye) > 100.0f ) return -1; + + if ( !SearchFreeBuffer(sound, channel, bAlreadyLoaded) ) return -1; + + if ( !bAlreadyLoaded ) + { + if ( !CreateBuffer(channel, sound) ) + { + if ( m_channel[channel].bUsed && + m_channel[channel].soundBuffer != 0 ) + { + m_channel[channel].soundBuffer->Release(); + m_channel[channel].soundBuffer = 0; + } + m_channel[channel].bUsed = false; + return -1; + } + } + + m_channel[channel].pos = pos; + + if ( m_ctrl3D ) + { + m_channel[channel].volume = 1.0f; + m_channel[channel].pan = 0.0f; + } + else + { + ComputeVolumePan2D(channel, pos); + } + +#if 0 + DWORD status; + m_channel[channel].soundBuffer->GetStatus(&status); + char s[100]; + sprintf(s, "Play sound=%d status=%d channel=%d flag=%d\n", sound, status, channel, bAlreadyLoaded); + OutputDebugString(s); +#endif + + m_channel[channel].oper[0].bUsed = false; + m_channel[channel].startAmplitude = amplitude; + m_channel[channel].startFrequency = frequency; + m_channel[channel].changeFrequency = 1.0f; + + if ( m_ctrl3D ) + { + sb.dwSize = sizeof(DS3DBUFFER); + err = m_channel[channel].soundBuffer3D->GetAllParameters(&sb); + DisplayError("GetAllParameters", sound, err); + + sb.vPosition = VEC_TO_D3DVEC(pos); +//? sb.dwInsideConeAngle = 90; +//? sb.dwOutsideConeAngle = 180; +//? sb.vConeOrientation = Math::Vector(0.0f, 1.0f, 0.0f); + sb.lConeOutsideVolume = DSBVOLUME_MIN; +#if _TEEN + sb.flMinDistance = 50.0f; +#else + sb.flMinDistance = 20.0f; +#endif + sb.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; + + err = m_channel[channel].soundBuffer3D->SetAllParameters(&sb, DS3D_IMMEDIATE); + DisplayError("SetAllParameters", sound, err); + } + + amplitude *= m_channel[channel].volume; + amplitude *= (float)m_audioVolume/MAXVOLUME; + iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f); + if ( iVolume > 0 ) iVolume = 0; + err = m_channel[channel].soundBuffer->SetVolume(iVolume); + DisplayError("SetVolume", sound, err); + + if ( !m_ctrl3D ) + { + iPan = (int)(m_channel[channel].pan*10000.0f); + err = m_channel[channel].soundBuffer->SetPan(iPan); + DisplayError("SetPan", sound, err); + } + + if ( !bAlreadyLoaded ) + { + err = m_channel[channel].soundBuffer->GetFrequency(&freq); + DisplayError("GetFrequency", sound, err); + m_channel[channel].initFrequency = freq; + } + iFreq = (int)(frequency*m_channel[channel].initFrequency); + err = m_channel[channel].soundBuffer->SetFrequency(iFreq); + DisplayError("SetFrequency", sound, err); + + err = m_channel[channel].soundBuffer->SetCurrentPosition(0); + DisplayError("SetCurrentPosition", sound, err); + + flag = bLoop?DSBPLAY_LOOPING:0; +//? flag |= DSBPLAY_LOCHARDWARE|DSBPLAY_TERMINATEBY_DISTANCE; +//? flag |= DSBPLAY_TERMINATEBY_DISTANCE; + err = m_channel[channel].soundBuffer->Play(0, 0, flag); + DisplayError("Play", sound, err); + if ( err == DSERR_BADFORMAT ) + { + iFreq = m_channel[channel].initFrequency; + err = m_channel[channel].soundBuffer->SetFrequency(iFreq); + DisplayError("SetFrequency (repeat)", sound, err); + + err = m_channel[channel].soundBuffer->Play(0, 0, flag); + DisplayError("Play (repeat)", sound, err); + } + + uniqueStamp = m_channel[channel].uniqueStamp; + return channel | ((uniqueStamp&0xffff)<<16); +} + +// Check a channel number. +// Adapts the channel, so it can be used as an offset in m_channel. + +bool CSound::CheckChannel(int &channel) +{ + int uniqueStamp; + + uniqueStamp = (channel>>16)&0xffff; + channel &= 0xffff; + + if ( !m_bEnable ) return false; + if ( !m_bState || m_audioVolume == 0 ) return false; + + if ( channel < 0 || channel >= m_maxSound ) return false; + if ( !m_channel[channel].bUsed ) return false; + + if ( m_channel[channel].uniqueStamp != uniqueStamp ) return false; + + return true; +} + +// Removes all envelopes. + +bool CSound::FlushEnvelope(int channel) +{ + if ( !CheckChannel(channel) ) return false; + + m_channel[channel].oper[0].bUsed = false; + return true; +} + +// Adds an operation envelope. + +bool CSound::AddEnvelope(int channel, float amplitude, float frequency, + float time, SoundNext oper) +{ + int i; + + if ( !CheckChannel(channel) ) return false; + + for ( i=0 ; iSetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED); + } + else + { + ComputeVolumePan2D(channel, pos); + + if ( !m_channel[channel].oper[0].bUsed ) + { + amplitude = m_channel[channel].startAmplitude; + amplitude *= m_channel[channel].volume; + amplitude *= (float)m_audioVolume/MAXVOLUME; + iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f); + if ( iVolume > 0 ) iVolume = 0; + err = m_channel[channel].soundBuffer->SetVolume(iVolume); + DisplayError("SetVolume", m_channel[channel].type, err); + } + + pan = m_channel[channel].pan; + iPan = (int)(pan*10000.0f); + err = m_channel[channel].soundBuffer->SetPan(iPan); + DisplayError("SetPan", m_channel[channel].type, err); + } + return true; +} + +// Changes the frequency of a sound. +// 0.5 down of an octave and 2.0 up of an octave. + +bool CSound::Frequency(int channel, float frequency) +{ + HRESULT err; + int iFreq; + + if ( !CheckChannel(channel) ) return false; + + m_channel[channel].changeFrequency = frequency; + + if ( !m_channel[channel].oper[0].bUsed ) + { + iFreq = (int)(frequency*m_channel[channel].initFrequency); + err = m_channel[channel].soundBuffer->SetFrequency(iFreq); + DisplayError("Frequency", m_channel[channel].type, err); + } + + return true; +} + +// Stops sound. + +bool CSound::Stop(int channel) +{ + if ( !CheckChannel(channel) ) return false; + + m_channel[channel].soundBuffer->Stop(); + return true; +} + +// Stops all sounds. + +bool CSound::StopAll() +{ + DWORD status; + int i; + + for ( i=0 ; iGetStatus(&status); + if ( (status&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING ) + { + m_channel[i].soundBuffer->Stop(); + } + m_channel[i].soundBuffer->Stop(); + m_channel[i].soundBuffer->Release(); + m_channel[i].soundBuffer = 0; + + m_channel[i].bUsed = false; + } + return true; +} + +// Silent all sounds. + +bool CSound::MuteAll(bool bMute) +{ + int i; + + for ( i=0 ; iSetVolume(-10000); // silence + continue; + } + + m_channel[i].oper[0].currentTime += rTime; + + progress = m_channel[i].oper[0].currentTime / m_channel[i].oper[0].totalTime; + if ( progress > 1.0f ) progress = 1.0f; + + volume = progress; + volume *= m_channel[i].oper[0].finalAmplitude-m_channel[i].startAmplitude; + volume += m_channel[i].startAmplitude; + volume *= m_channel[i].volume; + volume *= (float)m_audioVolume/MAXVOLUME; + iVolume = (int)((powf(volume, 0.2f)-1.0f)*10000.0f); + if ( iVolume > 0 ) iVolume = 0; + m_channel[i].soundBuffer->SetVolume(iVolume); + + freq = progress; + freq *= m_channel[i].oper[0].finalFrequency-m_channel[i].startFrequency; + freq += m_channel[i].startFrequency; + freq *= m_channel[i].changeFrequency; + iFreq = (int)(freq*m_channel[i].initFrequency); + err = m_channel[i].soundBuffer->SetFrequency(iFreq); + DisplayError("FrameMove::Frequency", m_channel[i].type, err); + + if ( m_channel[i].oper[0].currentTime >= + m_channel[i].oper[0].totalTime ) + { + next = m_channel[i].oper[0].nextOper; + + if ( next == SOPER_LOOP ) + { + m_channel[i].oper[0].currentTime = 0.0f; + } + else + { + OperNext(i); + + if ( next == SOPER_STOP ) + { + m_channel[i].soundBuffer->Stop(); + } + } + } + } + + m_lastTime += rTime; + if ( m_lastTime >= 0.05f && m_listener != 0 ) + { + m_lastTime = 0.0f; + m_listener->CommitDeferredSettings(); + } +} + +// Specifies the position of the listener. +// Must be called whenever the camera moves. + +void CSound::SetListener(Math::Vector eye, Math::Vector lookat) +{ + DS3DLISTENER listenerParams; + HRESULT err; + float amplitude, pan; + int i, iVolume, iPan; + + m_eye = eye; + m_lookat = lookat; + + if ( m_listener == 0 ) + { + if ( m_ctrl3D ) return; + + for ( i=0 ; i 0 ) iVolume = 0; + err = m_channel[i].soundBuffer->SetVolume(iVolume); + DisplayError("SetVolume", m_channel[i].type, err); + } + + pan = m_channel[i].pan; + iPan = (int)(pan*10000.0f); + err = m_channel[i].soundBuffer->SetPan(iPan); + DisplayError("SetPan", m_channel[i].type, err); + } + return; + } + + // Get listener parameters. + listenerParams.dwSize = sizeof(DS3DLISTENER); + m_listener->GetAllParameters(&listenerParams); + + listenerParams.vPosition = VEC_TO_D3DVEC(eye); + listenerParams.vOrientFront = VEC_TO_D3DVEC(lookat-eye); + listenerParams.vOrientTop = D3DVECTOR(0.0f, 1.0f, 0.0f); + listenerParams.flDistanceFactor = 10.0f; + listenerParams.flRolloffFactor = 1.0f; + + m_listener->SetAllParameters(&listenerParams, DS3D_DEFERRED); +} + + + + +// Uses MCI to play a MIDI file. The window procedure +// is notified when playback is complete. + +bool CSound::PlayMusic(int rank, bool bRepeat) +{ + MCI_OPEN_PARMS mciOpenParms; + MCI_PLAY_PARMS mciPlayParms; + DWORD dwReturn; + char filename[MAX_PATH]; + + m_bRepeatMusic = bRepeat; + m_playTime = 0.0f; + + if ( m_midiVolume == 0 ) return true; + + if ( m_bAudioTrack ) + { + return PlayAudioTrack(rank); + } + + if ( !m_bEnable ) return true; + InitMidiVolume(m_midiVolume); + m_lastMidiVolume = m_midiVolume; + + GetCurrentDir(filename, MAX_PATH-30); + sprintf(filename+strlen(filename), "sound\\music%.3d.blp", rank-1); + + // Open the device by specifying the device and filename. + // MCI will attempt to choose the MIDI mapper as the output port. + mciOpenParms.lpstrDeviceType = "sequencer"; + mciOpenParms.lpstrElementName = filename; + dwReturn = mciSendCommand(NULL, + MCI_OPEN, + MCI_OPEN_TYPE|MCI_OPEN_ELEMENT, + (DWORD)(LPVOID)&mciOpenParms); + if ( dwReturn != 0 ) + { + mciGetErrorString(dwReturn, filename, 128); + // Failed to open device. Don't close it; just return error. + return false; + } + + // The device opened successfully; get the device ID. + m_MidiDeviceID = mciOpenParms.wDeviceID; + + // Begin playback. + mciPlayParms.dwCallback = (DWORD)m_hWnd; + dwReturn = mciSendCommand(m_MidiDeviceID, + MCI_PLAY, + MCI_NOTIFY, + (DWORD)(LPVOID)&mciPlayParms); + if ( dwReturn != 0 ) + { + mciGetErrorString(dwReturn, filename, 128); + StopMusic(); + return false; + } + + m_MIDIMusic = rank; + return true; +} + +// Uses MCI to play a CD-audio track. The window procedure +// is notified when playback is complete. +// The rank parameter is in space [1..n] ! +// For CD mix (data/audio), it will be [2..n] ! + +bool CSound::PlayAudioTrack(int rank) +{ +#if _SOUNDTRACKS + MCI_OPEN_PARMS mciOpenParms; + MCI_PLAY_PARMS mciPlayParms; + MCI_SET_PARMS mciSetParms; + DWORD dwReturn; + char filename[MAX_PATH]; + char device[10]; + + if ( !m_bEnable ) return true; +//? if ( m_midiVolume == 0 ) return true; + InitAudioTrackVolume(m_midiVolume); + m_lastMidiVolume = m_midiVolume; + + // Open the device by specifying the device and filename. + // MCI will attempt to choose the MIDI mapper as the output port. + memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS)); +//? mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; +//? dwReturn = mciSendCommand(NULL, +//? MCI_OPEN, +//? MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, +//? (DWORD)(LPVOID)&mciOpenParms); + mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; + if ( m_CDpath[0] == 0 ) + { + dwReturn = mciSendCommand(NULL, + MCI_OPEN, + MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, + (DWORD)(LPVOID)&mciOpenParms); + } + else + { + device[0] = m_CDpath[0]; + device[1] = ':'; + device[2] = 0; + mciOpenParms.lpstrElementName = device; + dwReturn = mciSendCommand(NULL, + MCI_OPEN, + MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT, + (DWORD)(LPVOID)&mciOpenParms); + } + if ( dwReturn != 0 ) + { + mciGetErrorString(dwReturn, filename, 128); + // Failed to open device. Don't close it; just return error. + return false; + } + + // The device opened successfully; get the device ID. + m_MidiDeviceID = mciOpenParms.wDeviceID; + + // Set the time format to track/minute/second/frame (TMSF). + memset(&mciSetParms, 0, sizeof(MCI_SET_PARMS)); + mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF; + dwReturn = mciSendCommand(m_MidiDeviceID, + MCI_SET, + MCI_SET_TIME_FORMAT, + (DWORD)&mciSetParms); + if ( dwReturn != 0 ) + { + mciGetErrorString(dwReturn, filename, 128); + StopMusic(); + return false; + } + + // Begin playback. + memset(&mciPlayParms, 0, sizeof(MCI_PLAY_PARMS)); + mciPlayParms.dwCallback = (DWORD)m_hWnd; + mciPlayParms.dwFrom = MCI_MAKE_TMSF(rank+0, 0, 0, 0); + mciPlayParms.dwTo = MCI_MAKE_TMSF(rank+1, 0, 0, 0); + dwReturn = mciSendCommand(m_MidiDeviceID, + MCI_PLAY, + MCI_NOTIFY|MCI_FROM|MCI_TO, + (DWORD)(LPVOID)&mciPlayParms); + if ( dwReturn != 0 ) + { + mciGetErrorString(dwReturn, filename, 128); + StopMusic(); + return false; + } + + m_MIDIMusic = rank; +#endif + return true; +} + +// Restart the MIDI player. + +bool CSound::RestartMusic() +{ + if ( !m_bRepeatMusic ) return false; + + OutputDebugString("RestartMusic\n"); + if ( !m_bEnable ) return true; +//? if ( m_midiVolume == 0 ) return true; + if ( m_MIDIMusic == 0 ) return false; + if ( m_playTime < 5.0f ) return false; + + return PlayMusic(m_MIDIMusic, true); +} + +// Shuts down the MIDI player. + +void CSound::SuspendMusic() +{ + if ( !m_bEnable ) return; + +//? if ( m_MidiDeviceID && m_midiVolume != 0 ) + if ( m_MidiDeviceID ) + { + if ( m_bAudioTrack ) mciSendCommand(m_MidiDeviceID, MCI_STOP, 0, NULL); + mciSendCommand(m_MidiDeviceID, MCI_CLOSE, 0, NULL); + } + m_MidiDeviceID = 0; +} + +// Shuts down the MIDI player. + +void CSound::StopMusic() +{ + SuspendMusic(); + m_MIDIMusic = 0; +} + +// Returns true if the music is in progress. + +bool CSound::IsPlayingMusic() +{ + return (m_MIDIMusic != 0); +} + +// Adjusts the volume of currently music, if necessary. + +void CSound::AdaptVolumeMusic() +{ + if ( m_midiVolume != m_lastMidiVolume ) + { + if ( m_bAudioTrack ) + { + InitAudioTrackVolume(m_midiVolume); + } + else + { + InitMidiVolume(m_midiVolume); + } + m_lastMidiVolume = m_midiVolume; + RestartMusic(); + } +} + diff --git a/src/old/sound.h b/src/old/sound.h index 2dcdc2c..157eb2e 100644 --- a/src/old/sound.h +++ b/src/old/sound.h @@ -1,242 +1,242 @@ -// * 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/. - -// sound.h - -#pragma once - - -#include - - -const int MAXFILES = 200; -const int MAXSOUND = 32; -const int MAXVOLUME = 20; -const int MAXOPER = 4; - -class CInstanceManager; - - -enum Sound -{ - SOUND_CLICK = 0, - SOUND_BOUM = 1, - SOUND_EXPLO = 2, - SOUND_FLYh = 3, // human - SOUND_FLY = 4, - SOUND_STEPs = 5, // smooth - SOUND_MOTORw = 6, // wheel - SOUND_MOTORt = 7, // tank - SOUND_MOTORr = 8, // roller - SOUND_ERROR = 9, - SOUND_CONVERT = 10, - SOUND_ENERGY = 11, - SOUND_PLOUF = 12, - SOUND_BLUP = 13, - SOUND_WARNING = 14, - SOUND_DERRICK = 15, - SOUND_LABO = 16, - SOUND_STATION = 17, - SOUND_REPAIR = 18, - SOUND_RESEARCH = 19, - SOUND_INSECTs = 20, // spider - SOUND_BURN = 21, - SOUND_TZOING = 22, - SOUND_GGG = 23, - SOUND_MANIP = 24, - SOUND_FIRE = 25, // shooting with fireball - SOUND_HUMAN1 = 26, // breathing - SOUND_STEPw = 27, // water - SOUND_SWIM = 28, - SOUND_RADAR = 29, - SOUND_BUILD = 30, - SOUND_ALARM = 31, // energy alarm - SOUND_SLIDE = 32, - SOUND_EXPLOi = 33, // insect - SOUND_INSECTa = 34, // ant - SOUND_INSECTb = 35, // bee - SOUND_INSECTw = 36, // worm - SOUND_INSECTm = 37, // mother - SOUND_TREMBLE = 38, - SOUND_PSHHH = 39, - SOUND_NUCLEAR = 40, - SOUND_INFO = 41, - SOUND_OPEN = 42, - SOUND_CLOSE = 43, - SOUND_FACTORY = 44, - SOUND_EGG = 45, - SOUND_MOTORs = 46, // submarine - SOUND_MOTORi = 47, // insect (legs) - SOUND_SHIELD = 48, - SOUND_FIREi = 49, // shooting with orgaball (insect) - SOUND_GUNDEL = 50, - SOUND_PSHHH2 = 51, // shield - SOUND_MESSAGE = 52, - SOUND_BOUMm = 53, // metal - SOUND_BOUMv = 54, // plant - SOUND_BOUMs = 55, // smooth - SOUND_EXPLOl = 56, // little - SOUND_EXPLOlp = 57, // little power - SOUND_EXPLOp = 58, // power - SOUND_STEPh = 59, // hard - SOUND_STEPm = 60, // metal - SOUND_POWERON = 61, - SOUND_POWEROFF = 62, - SOUND_AIE = 63, - SOUND_WAYPOINT = 64, - SOUND_RECOVER = 65, - SOUND_DEADi = 66, - SOUND_JOSTLE = 67, - SOUND_GFLAT = 68, - SOUND_DEADg = 69, // shooting death - SOUND_DEADw = 70, // drowning - SOUND_FLYf = 71, // reactor fail - SOUND_ALARMt = 72, // temperature alarm - SOUND_FINDING = 73, // finds a cache object - SOUND_THUMP = 74, - SOUND_TOUCH = 75, - SOUND_BLITZ = 76, - SOUND_MUSHROOM = 77, - SOUND_FIREp = 78, // shooting with phazer - SOUND_EXPLOg1 = 79, // impact gun 1 - SOUND_EXPLOg2 = 80, // impact gun 2 - SOUND_MOTORd = 81, // engine friction -}; - -enum SoundNext -{ - SOPER_CONTINUE = 1, - SOPER_STOP = 2, - SOPER_LOOP = 3, -}; - -struct SoundOper -{ - char bUsed; - float finalAmplitude; - float finalFrequency; - float totalTime; - float currentTime; - SoundNext nextOper; -}; - -struct SoundChannel -{ - char bUsed; // buffer used? - char bMute; // silence? - Sound type; // SOUND_* - int priority; // so great -> important - Math::Vector pos; // position in space - unsigned short uniqueStamp; // unique marker - LPDIRECTSOUNDBUFFER soundBuffer; - LPDIRECTSOUND3DBUFFER soundBuffer3D; - float startAmplitude; - float startFrequency; - float changeFrequency; - int initFrequency; - float volume; // 2D: volume 1..0 depending on position - float pan; // 2D: pan -1..+1 depending on position - SoundOper oper[MAXOPER]; -}; - - - -class CSound -{ -public: - CSound(CInstanceManager* iMan); - ~CSound(); - - void SetDebugMode(bool bMode); - bool Create(HWND hWnd, bool b3D); - void CacheAll(); - - void SetState(bool bState); - bool RetEnable(); - - void SetCDpath(char *path); - void SetAudioTrack(bool bAudio); - - void SetSound3D(bool bMode); - bool RetSound3D(); - bool RetSound3DCap(); - - void SetAudioVolume(int volume); - int RetAudioVolume(); - void SetMidiVolume(int volume); - int RetMidiVolume(); - - void SetListener(Math::Vector eye, Math::Vector lookat); - void FrameMove(float rTime); - - int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false); - int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false); - bool FlushEnvelope(int channel); - bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper); - bool Position(int channel, Math::Vector pos); - bool Frequency(int channel, float frequency); - bool Stop(int channel); - bool StopAll(); - bool MuteAll(bool bMute); - - bool PlayMusic(int rank, bool bRepeat); - bool RestartMusic(); - void SuspendMusic(); - void StopMusic(); - bool IsPlayingMusic(); - void AdaptVolumeMusic(); - -protected: - bool CheckChannel(int &channel); - bool CreateSoundBuffer(int channel, DWORD size, DWORD freq, DWORD bitsPerSample, DWORD blkAlign, bool bStereo); - bool ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size); - bool CreateBuffer(int channel, Sound sound); - void ComputeVolumePan2D(int channel, const Math::Vector &pos); - bool ReadFile(Sound sound, char *metaname, char *filename); - int RetPriority(Sound sound); - bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded); - void OperNext(int channel); - bool PlayAudioTrack(int rank); - -protected: - CInstanceManager* m_iMan; - - HWND m_hWnd; - bool m_bEnable; - bool m_bState; - bool m_bAudioTrack; - bool m_ctrl3D; - bool m_bDebugMode; - LPDIRECTSOUND m_lpDS; - LPDIRECTSOUND3DLISTENER m_listener; - SoundChannel m_channel[MAXSOUND]; - char* m_files[MAXFILES]; - UINT m_MidiDeviceID; - int m_MIDIMusic; - bool m_bRepeatMusic; - int m_audioVolume; - int m_midiVolume; - int m_lastMidiVolume; - Math::Vector m_eye; - Math::Vector m_lookat; - float m_lastTime; - float m_playTime; - int m_uniqueStamp; - int m_maxSound; - char m_CDpath[100]; -}; - - +// * 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/. + +// sound.h + +#pragma once + + +#include + + +const int MAXFILES = 200; +const int MAXSOUND = 32; +const int MAXVOLUME = 20; +const int MAXOPER = 4; + +class CInstanceManager; + + +enum Sound +{ + SOUND_CLICK = 0, + SOUND_BOUM = 1, + SOUND_EXPLO = 2, + SOUND_FLYh = 3, // human + SOUND_FLY = 4, + SOUND_STEPs = 5, // smooth + SOUND_MOTORw = 6, // wheel + SOUND_MOTORt = 7, // tank + SOUND_MOTORr = 8, // roller + SOUND_ERROR = 9, + SOUND_CONVERT = 10, + SOUND_ENERGY = 11, + SOUND_PLOUF = 12, + SOUND_BLUP = 13, + SOUND_WARNING = 14, + SOUND_DERRICK = 15, + SOUND_LABO = 16, + SOUND_STATION = 17, + SOUND_REPAIR = 18, + SOUND_RESEARCH = 19, + SOUND_INSECTs = 20, // spider + SOUND_BURN = 21, + SOUND_TZOING = 22, + SOUND_GGG = 23, + SOUND_MANIP = 24, + SOUND_FIRE = 25, // shooting with fireball + SOUND_HUMAN1 = 26, // breathing + SOUND_STEPw = 27, // water + SOUND_SWIM = 28, + SOUND_RADAR = 29, + SOUND_BUILD = 30, + SOUND_ALARM = 31, // energy alarm + SOUND_SLIDE = 32, + SOUND_EXPLOi = 33, // insect + SOUND_INSECTa = 34, // ant + SOUND_INSECTb = 35, // bee + SOUND_INSECTw = 36, // worm + SOUND_INSECTm = 37, // mother + SOUND_TREMBLE = 38, + SOUND_PSHHH = 39, + SOUND_NUCLEAR = 40, + SOUND_INFO = 41, + SOUND_OPEN = 42, + SOUND_CLOSE = 43, + SOUND_FACTORY = 44, + SOUND_EGG = 45, + SOUND_MOTORs = 46, // submarine + SOUND_MOTORi = 47, // insect (legs) + SOUND_SHIELD = 48, + SOUND_FIREi = 49, // shooting with orgaball (insect) + SOUND_GUNDEL = 50, + SOUND_PSHHH2 = 51, // shield + SOUND_MESSAGE = 52, + SOUND_BOUMm = 53, // metal + SOUND_BOUMv = 54, // plant + SOUND_BOUMs = 55, // smooth + SOUND_EXPLOl = 56, // little + SOUND_EXPLOlp = 57, // little power + SOUND_EXPLOp = 58, // power + SOUND_STEPh = 59, // hard + SOUND_STEPm = 60, // metal + SOUND_POWERON = 61, + SOUND_POWEROFF = 62, + SOUND_AIE = 63, + SOUND_WAYPOINT = 64, + SOUND_RECOVER = 65, + SOUND_DEADi = 66, + SOUND_JOSTLE = 67, + SOUND_GFLAT = 68, + SOUND_DEADg = 69, // shooting death + SOUND_DEADw = 70, // drowning + SOUND_FLYf = 71, // reactor fail + SOUND_ALARMt = 72, // temperature alarm + SOUND_FINDING = 73, // finds a cache object + SOUND_THUMP = 74, + SOUND_TOUCH = 75, + SOUND_BLITZ = 76, + SOUND_MUSHROOM = 77, + SOUND_FIREp = 78, // shooting with phazer + SOUND_EXPLOg1 = 79, // impact gun 1 + SOUND_EXPLOg2 = 80, // impact gun 2 + SOUND_MOTORd = 81, // engine friction +}; + +enum SoundNext +{ + SOPER_CONTINUE = 1, + SOPER_STOP = 2, + SOPER_LOOP = 3, +}; + +struct SoundOper +{ + char bUsed; + float finalAmplitude; + float finalFrequency; + float totalTime; + float currentTime; + SoundNext nextOper; +}; + +struct SoundChannel +{ + char bUsed; // buffer used? + char bMute; // silence? + Sound type; // SOUND_* + int priority; // so great -> important + Math::Vector pos; // position in space + unsigned short uniqueStamp; // unique marker + LPDIRECTSOUNDBUFFER soundBuffer; + LPDIRECTSOUND3DBUFFER soundBuffer3D; + float startAmplitude; + float startFrequency; + float changeFrequency; + int initFrequency; + float volume; // 2D: volume 1..0 depending on position + float pan; // 2D: pan -1..+1 depending on position + SoundOper oper[MAXOPER]; +}; + + + +class CSound +{ +public: + CSound(CInstanceManager* iMan); + ~CSound(); + + void SetDebugMode(bool bMode); + bool Create(HWND hWnd, bool b3D); + void CacheAll(); + + void SetState(bool bState); + bool RetEnable(); + + void SetCDpath(char *path); + void SetAudioTrack(bool bAudio); + + void SetSound3D(bool bMode); + bool RetSound3D(); + bool RetSound3DCap(); + + void SetAudioVolume(int volume); + int RetAudioVolume(); + void SetMidiVolume(int volume); + int RetMidiVolume(); + + void SetListener(Math::Vector eye, Math::Vector lookat); + void FrameMove(float rTime); + + int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false); + int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop=false); + bool FlushEnvelope(int channel); + bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper); + bool Position(int channel, Math::Vector pos); + bool Frequency(int channel, float frequency); + bool Stop(int channel); + bool StopAll(); + bool MuteAll(bool bMute); + + bool PlayMusic(int rank, bool bRepeat); + bool RestartMusic(); + void SuspendMusic(); + void StopMusic(); + bool IsPlayingMusic(); + void AdaptVolumeMusic(); + +protected: + bool CheckChannel(int &channel); + bool CreateSoundBuffer(int channel, DWORD size, DWORD freq, DWORD bitsPerSample, DWORD blkAlign, bool bStereo); + bool ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size); + bool CreateBuffer(int channel, Sound sound); + void ComputeVolumePan2D(int channel, const Math::Vector &pos); + bool ReadFile(Sound sound, char *metaname, char *filename); + int RetPriority(Sound sound); + bool SearchFreeBuffer(Sound sound, int &channel, bool &bAlreadyLoaded); + void OperNext(int channel); + bool PlayAudioTrack(int rank); + +protected: + CInstanceManager* m_iMan; + + HWND m_hWnd; + bool m_bEnable; + bool m_bState; + bool m_bAudioTrack; + bool m_ctrl3D; + bool m_bDebugMode; + LPDIRECTSOUND m_lpDS; + LPDIRECTSOUND3DLISTENER m_listener; + SoundChannel m_channel[MAXSOUND]; + char* m_files[MAXFILES]; + UINT m_MidiDeviceID; + int m_MIDIMusic; + bool m_bRepeatMusic; + int m_audioVolume; + int m_midiVolume; + int m_lastMidiVolume; + Math::Vector m_eye; + Math::Vector m_lookat; + float m_lastTime; + float m_playTime; + int m_uniqueStamp; + int m_maxSound; + char m_CDpath[100]; +}; + + diff --git a/src/old/terrain.cpp b/src/old/terrain.cpp index b558e71..2f2250c 100644 --- a/src/old/terrain.cpp +++ b/src/old/terrain.cpp @@ -1,2270 +1,2270 @@ -// * 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/. - -// terrain.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/const.h" -#include "math/geometry.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "common/language.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/modfile.h" -#include "old/water.h" -#include "old/terrain.h" - - -const int BMPHEAD = 1078; - - - -// Constructor of the terrain. - -CTerrain::CTerrain(CInstanceManager* iMan) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_TERRAIN, this); - - m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); - m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); - - m_mosaic = 20; - m_brick = 1<<4; - m_size = 10.0f; - m_vision = 200.0f; - m_relief = 0; - m_texture = 0; - m_objRank = 0; - m_scaleMapping = 0.01f; - m_scaleRelief = 1.0f; - m_subdivMapping = 1; - m_depth = 2; - m_texBaseName[0]= 0; - m_texBaseExt[0] = 0; - m_bMultiText = true; - m_bLevelText = false; - m_resources = 0; - m_levelMatTotal = 0; - m_levelMatMax = 0; - m_levelDot = 0; - m_wind = Math::Vector(0.0f, 0.0f, 0.0f); - m_defHardness = 0.5f; - - FlushBuildingLevel(); - FlushFlyingLimit(); -} - -// Destructor of the terrain. - -CTerrain::~CTerrain() -{ - free(m_relief); - free(m_texture); - free(m_objRank); - free(m_resources); -} - - -// Generates a new flat terrain. -// The terrain is composed of mosaics, themselves composed of bricks. -// Each brick is composed of two triangles. -// mosaic: number of mosaics along the axes X and Z -// brick: number of bricks (power of 2) -// size: size of a brick along the axes X and Z -// vision: vision before a change of resolution -// scaleMapping: scale textures for mapping -// -// ^ z -// | <---> brick*size -// +---+---+---+---+ -// | | | |_|_| mosaic = 4 -// | | | | | | brick = 2 (brickP2=1) -// +---+---+---+---+ -// |\ \| | | | -// |\ \| | | | -// +---+---o---+---+---> x -// | | | | | -// | | | | | -// +---+---+---+---+ -// | | | | | The land is viewed from above here. -// | | | | | -// +---+---+---+---+ -// <---------------> mosaic*brick*size - -bool CTerrain::Generate(int mosaic, int brickP2, float size, float vision, - int depth, float hardness) -{ - int dim; - - m_mosaic = mosaic; - m_brick = 1<SetTerrainVision(vision); - - m_bMultiText = true; - m_bLevelText = false; - m_scaleMapping = 1.0f/(m_brick*m_size); - m_subdivMapping = 1; - - dim = (m_mosaic*m_brick+1)*(m_mosaic*m_brick+1); - m_relief = (float*)malloc(sizeof(float)*dim); - ZeroMemory(m_relief, sizeof(float)*dim); - - dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping; - m_texture = (int*)malloc(sizeof(int)*dim); - ZeroMemory(m_texture, sizeof(int)*dim); - - dim = m_mosaic*m_mosaic; - m_objRank = (int*)malloc(sizeof(int)*dim); - ZeroMemory(m_objRank, sizeof(int)*dim); - - return true; -} - - -int CTerrain::RetMosaic() -{ - return m_mosaic; -} - -int CTerrain::RetBrick() -{ - return m_brick; -} - -float CTerrain::RetSize() -{ - return m_size; -} - -float CTerrain::RetScaleRelief() -{ - return m_scaleRelief; -} - - -// Initializes the names of textures to use for the land. - -bool CTerrain::InitTextures(char* baseName, int* table, int dx, int dy) -{ - int x, y; - char* p; - - m_bLevelText = false; - - strcpy(m_texBaseName, baseName); - p = strchr(m_texBaseName, '.'); // p <- ^beginning of the extension - if ( p == 0 ) - { - strcpy(m_texBaseExt, ".tga"); - } - else - { - strcpy(m_texBaseExt, p); // m_texBaseExt <- ".tga" or ".bmp" - *p = 0; // m_texBaseName <- name without extension - } - - for ( y=0 ; y= MAXMATTERRAIN-1 ) return false; - - LevelOpenTable(); - - if ( id == 0 ) - { - id = m_levelID++; // puts an ID internal standard - } - - strcpy(m_levelMat[i].texName, baseName); - m_levelMat[i].id = id; - m_levelMat[i].u = u; - m_levelMat[i].v = v; - m_levelMat[i].mat[0] = up; - m_levelMat[i].mat[1] = right; - m_levelMat[i].mat[2] = down; - m_levelMat[i].mat[3] = left; - m_levelMat[i].hardness = hardness; - - if ( m_levelMatMax < up+1 ) m_levelMatMax = up+1; - if ( m_levelMatMax < right+1 ) m_levelMatMax = right+1; - if ( m_levelMatMax < down+1 ) m_levelMatMax = down+1; - if ( m_levelMatMax < left+1 ) m_levelMatMax = left+1; - - m_bLevelText = true; - m_subdivMapping = 4; - - m_levelMatTotal ++; - return true; -} - - -// Load relief from a BMP file. -// The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. -// The image must be 8 bits/pixel, 256 colors with a standard pallet. - -// Converts coordinated image (x;y) -> world (x;-;z) : -// Wx = 5*Ix-400 -// Wz = -(5*Iy-400) - -// Converts coordinated world (x;-;z) -> image (x;y) : -// Ix = (400+Wx)/5 -// Iy = (400-Wz)/5 - -bool CTerrain::ResFromBMP(const char* filename) -{ - FILE* file; - int size, sizem; - - file = fopen(filename, "rb"); - if ( file == NULL ) return false; - - size = (m_mosaic*m_brick)+1; - sizem = ((size+4-1)/4)*4; // upper size multiple of 4 - - if ( m_resources != 0 ) - { - free(m_resources); - } - - m_resources = (unsigned char*)malloc(BMPHEAD+sizem*size); - fread(m_resources, BMPHEAD+sizem*size, 1, file); - - if ( m_resources[18] != (size&0xff) || m_resources[19] != (size>>8) || - m_resources[22] != (size&0xff) || m_resources[23] != (size>>8) ) - { - free(m_resources); - m_resources = 0; - fclose(file); - return false; - } - - fclose(file); - return true; -} - -// Returns the resource type available underground. - -TerrainRes CTerrain::RetResource(const Math::Vector &p) -{ - int x, y, size, sizem, ress; - - if ( m_resources == 0 ) return TR_NULL; - - x = (int)((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size); - y = (int)((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return TR_NULL; - - size = (m_mosaic*m_brick)+1; - sizem = ((size+4-1)/4)*4; // upper size multiple of 4 - - ress = m_resources[BMPHEAD+x+sizem*y]; - if ( ress == 5 ) return TR_STONE; // red? - if ( ress == 35 ) return TR_URANIUM; // yellow? - if ( ress == 30 ) return TR_POWER; // green? - if ( ress == 24 ) return TR_KEYa; // ~green? - if ( ress == 25 ) return TR_KEYb; // ~green? - if ( ress == 26 ) return TR_KEYc; // ~green? - if ( ress == 27 ) return TR_KEYd; // ~green? - - return TR_NULL; -} - - -// Initializes a completely flat terrain. - -void CTerrain::FlushRelief() -{ - free(m_relief); - m_relief = 0; -} - -// Load relief from a BMP file. -// The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. -// The image must be 8 bits/pixel, 256 gray scale: -// white = ground (y=0) -// black = mountain (y=255*scaleRelief) - -// Converts coordinated image(x;y) -> world (x;-;z) : -// Wx = 5*Ix-400 -// Wz = -(5*Iy-400) - -// Converts coordinated world (x;-;z) -> image (x;y) : -// Ix = (400+Wx)/5 -// Iy = (400-Wz)/5 - -bool CTerrain::ReliefFromBMP(const char* filename, float scaleRelief, - bool adjustBorder) -{ - FILE* file; - unsigned char* buffer; - int size, sizem, x, y; - float level, limit, dist, border; - - m_scaleRelief = scaleRelief; - - file = fopen(filename, "rb"); - if ( file == NULL ) return false; - - size = (m_mosaic*m_brick)+1; - sizem = ((size+4-1)/4)*4; // upper size multiple of 4 - - buffer = (unsigned char*)malloc(BMPHEAD+sizem*size); - fread(buffer, BMPHEAD+sizem*size, 1, file); - - if ( buffer[18] != (size&0xff) || buffer[19] != (size>>8) || - buffer[22] != (size&0xff) || buffer[23] != (size>>8) ) - { - free(buffer); - fclose(file); - return false; - } - - limit = 0.9f; - for ( y=0 ; y limit && adjustBorder ) - { - dist = (dist-limit)/(1.0f-limit); // 0..1 - if ( dist > 1.0f ) dist = 1.0f; - border = 300.0f+Math::Rand()*20.0f; - level = level+dist*(border-level); - } - - m_relief[x+y*size] = level; - } - } - - free(buffer); - fclose(file); - return true; -} - -// Adds a point of elevation in the buffer of relief. - -bool CTerrain::ReliefAddDot(Math::Vector pos, float scaleRelief) -{ - float dim; - int size, x, y; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - size = (m_mosaic*m_brick)+1; - - pos.x = (pos.x+dim)/m_size; - pos.z = (pos.z+dim)/m_size; - - x = (int)pos.x; - y = (int)pos.z; - - if ( x < 0 || x >= size || - y < 0 || y >= size ) return false; - - if ( m_relief[x+y*size] < pos.y*scaleRelief ) - { - m_relief[x+y*size] = pos.y*scaleRelief; - } - return true; -} - -// Load relief from a DXF file. - -bool CTerrain::ReliefFromDXF(const char* filename, float scaleRelief) -{ - FILE* file = NULL; - char line[100]; - int command, rankSommet, nbSommet, nbFace, size; - Math::Vector* table; - bool bWaitNbSommet; - bool bWaitNbFace; - bool bWaitSommetX; - bool bWaitSommetY; - bool bWaitSommetZ; - bool bWaitFaceX; - bool bWaitFaceY; - bool bWaitFaceZ; - float x,y,z; - int p1,p2,p3; - - ZeroMemory(m_relief, sizeof(float)*(m_mosaic*m_brick+1)*(m_mosaic*m_brick+1)); - - file = fopen(filename, "r"); - if ( file == NULL ) return false; - - size = (m_mosaic*m_brick)+1; - table = (Math::Vector*)malloc(sizeof(Math::Vector)*size*size); - - rankSommet = 0; - bWaitNbSommet = false; - bWaitNbFace = false; - bWaitSommetX = false; - bWaitSommetY = false; - bWaitSommetZ = false; - bWaitFaceX = false; - bWaitFaceY = false; - bWaitFaceZ = false; - - while ( fgets(line, 100, file) != NULL ) - { - sscanf(line, "%d", &command); - if ( fgets(line, 100, file) == NULL ) break; - - if ( command == 66 ) - { - bWaitNbSommet = true; - } - - if ( command == 71 && bWaitNbSommet ) - { - bWaitNbSommet = false; - sscanf(line, "%d", &nbSommet); - if ( nbSommet > size*size ) nbSommet = size*size; - rankSommet = 0; - bWaitNbFace = true; - } - - if ( command == 72 && bWaitNbFace ) - { - bWaitNbFace = false; - sscanf(line, "%d", &nbFace); - bWaitSommetX = true; - } - - if ( command == 10 && bWaitSommetX ) - { - bWaitSommetX = false; - sscanf(line, "%f", &x); - bWaitSommetY = true; - } - - if ( command == 20 && bWaitSommetY ) - { - bWaitSommetY = false; - sscanf(line, "%f", &y); - bWaitSommetZ = true; - } - - if ( command == 30 && bWaitSommetZ ) - { - bWaitSommetZ = false; - sscanf(line, "%f", &z); - - nbSommet --; - if ( nbSommet >= 0 ) - { - Math::Vector p(x,z,y); // permutation of Y and Z! - table[rankSommet++] = p; - bWaitSommetX = true; - } - else - { - bWaitFaceX = true; - } - } - - if ( command == 71 && bWaitFaceX ) - { - bWaitFaceX = false; - sscanf(line, "%d", &p1); - if ( p1 < 0 ) p1 = -p1; - bWaitFaceY = true; - } - - if ( command == 72 && bWaitFaceY ) - { - bWaitFaceY = false; - sscanf(line, "%d", &p2); - if ( p2 < 0 ) p2 = -p2; - bWaitFaceZ = true; - } - - if ( command == 73 && bWaitFaceZ ) - { - bWaitFaceZ = false; - sscanf(line, "%d", &p3); - if ( p3 < 0 ) p3 = -p3; - - nbFace --; - if ( nbFace >= 0 ) - { - ReliefAddDot(table[p3-1], scaleRelief); - ReliefAddDot(table[p2-1], scaleRelief); - ReliefAddDot(table[p1-1], scaleRelief); - bWaitFaceX = true; - } - } - - } - - free(table); - fclose(file); - return true; -} - - -// Adjusts a position so that it does not exceed the boundaries. - -void CTerrain::LimitPos(Math::Vector &pos) -{ - float dim; - -#if _TEEN - dim = (m_mosaic*m_brick*m_size)/2.0f*0.98f; -#else - dim = (m_mosaic*m_brick*m_size)/2.0f*0.92f; -#endif - - if ( pos.x < -dim ) pos.x = -dim; - if ( pos.x > dim ) pos.x = dim; - if ( pos.z < -dim ) pos.z = -dim; - if ( pos.z > dim ) pos.z = dim; -} - - -// Adjust the edges of each mosaic to be compatible with all lower resolutions. - -void CTerrain::AdjustRelief() -{ - int x, y, xx, yy, ii, b; - float level1, level2; - - if ( m_depth == 1 ) return; - - ii = m_mosaic*m_brick+1; - b = 1<<(m_depth-1); - - for ( y=0 ; y= 0 && x <= m_mosaic*m_brick && - y >= 0 && y <= m_mosaic*m_brick ) - { - p.y = m_relief[x+y*(m_mosaic*m_brick+1)]; - } - else - { - p.y = 0.0f; - } - - return p; -} - -// Calculates a vertex of the terrain. -// Calculates a normal soft, taking into account the six adjacent triangles: -// -// ^ y -// | -// b---c---+ -// |\ |\ | -// | \| \| -// a---o---d -// |\ |\ | -// | \| \| -// +---f---e--> x - -D3DVERTEX2 CTerrain::RetVertex(int x, int y, int step) -{ - D3DVERTEX2 v; - Math::Vector o, oo, a,b,c,d,e,f, n, s; - int brick; - - o = RetVector(x, y); - v.x = o.x; - v.y = o.y; - v.z = o.z; - - a = RetVector(x-step, y ); - b = RetVector(x-step, y+step); - c = RetVector(x, y+step); - d = RetVector(x+step, y ); - e = RetVector(x+step, y-step); - f = RetVector(x, y-step); - - s = Math::Vector(0.0f, 0.0f, 0.0f); - - if ( x-step >= 0 && y+step <= m_mosaic*m_brick+1 ) - { - s += Math::NormalToPlane(b,a,o); - s += Math::NormalToPlane(c,b,o); - } - - if ( x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1 ) - { - s += Math::NormalToPlane(d,c,o); - } - - if ( x+step <= m_mosaic*m_brick+1 && y-step >= 0 ) - { - s += Math::NormalToPlane(e,d,o); - s += Math::NormalToPlane(f,e,o); - } - - if ( x-step >= 0 && y-step >= 0 ) - { - s += Math::NormalToPlane(a,f,o); - } - - s = Normalize(s); - v.nx = s.x; - v.ny = s.y; - v.nz = s.z; - - if ( m_bMultiText ) - { - brick = m_brick/m_subdivMapping; - oo = RetVector((x/brick)*brick, (y/brick)*brick); - o = RetVector(x, y); - v.tu = (o.x-oo.x)*m_scaleMapping*m_subdivMapping; - v.tv = 1.0f - (o.z-oo.z)*m_scaleMapping*m_subdivMapping; - } - else - { - v.tu = o.x*m_scaleMapping; - v.tv = o.z*m_scaleMapping; - } - - return v; -} - -// Creates all objects of a mosaic. -// The origin of mosaic is his center. -// -// ^ z -// | -// | 2---4---6-- -// | |\ |\ |\ -// | | \| \| -// | 1---3---5--- ... -// | -// +-------------------> x - -bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, - const D3DMATERIAL7 &mat, - float min, float max) -{ - Math::Matrix transform; - D3DVERTEX2 o, p1, p2; - D3DObjLevel6* buffer; - Math::Point uv; - int brick, total, size, mx, my, x, y, xx, yy, i; - char texName1[20]; - char texName2[20]; - float pixel, dp; - - if ( step == 1 && m_engine->RetGroundSpot() ) - { - i = (ox/5) + (oy/5)*(m_mosaic/5); - sprintf(texName2, "shadow%.2d.tga", i); - } - else - { - texName2[0] = 0; - } - - brick = m_brick/m_subdivMapping; - - o = RetVertex(ox*m_brick+m_brick/2, oy*m_brick+m_brick/2, step); - total = ((brick/step)+1)*2; - size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1); - - pixel = 1.0f/256.0f; // 1 pixel cover (*) -//? dp = 0.5f/512.0f; - dp = 1.0f/512.0f; - - for ( my=0 ; mytotalPossible = total; - buffer->totalUsed = total; - buffer->type = D3DTYPE6S; - buffer->material = mat; - if ( m_bMultiText ) - { -//? buffer->state = D3DSTATENORMAL; - buffer->state = D3DSTATEWRAP; - } - else - { - buffer->state = D3DSTATEWRAP; - } - buffer->state |= D3DSTATESECOND; - if ( step == 1 ) - { - buffer->state |= D3DSTATEDUALb; - } - i = 0; - for ( x=0 ; x<=brick ; x+=step ) - { - p1 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+0 , step); - p2 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+step, step); - p1.x -= o.x; p1.z -= o.z; - p2.x -= o.x; p2.z -= o.z; - - if ( m_bMultiText ) - { - if ( x == 0 ) - { - p1.tu = 0.0f+(0.5f/256.0f); - p2.tu = 0.0f+(0.5f/256.0f); - } - if ( x == brick ) - { - p1.tu = 1.0f-(0.5f/256.0f); - p2.tu = 1.0f-(0.5f/256.0f); - } - if ( y == 0 ) - { - p1.tv = 1.0f-(0.5f/256.0f); - } - if ( y == brick-step ) - { - p2.tv = 0.0f+(0.5f/256.0f); - } - } - - if ( m_bLevelText ) - { - p1.tu /= m_subdivMapping; // 0..1 -> 0..0.25 - p1.tv /= m_subdivMapping; - p2.tu /= m_subdivMapping; - p2.tv /= m_subdivMapping; - - if ( x == 0 ) - { - p1.tu = 0.0f+dp; - p2.tu = 0.0f+dp; - } - if ( x == brick ) - { - p1.tu = (1.0f/m_subdivMapping)-dp; - p2.tu = (1.0f/m_subdivMapping)-dp; - } - if ( y == 0 ) - { - p1.tv = (1.0f/m_subdivMapping)-dp; - } - if ( y == brick-step ) - { - p2.tv = 0.0f+dp; - } - - p1.tu += uv.x; - p1.tv += uv.y; - p2.tu += uv.x; - p2.tv += uv.y; - } - -#if 1 - xx = mx*(m_brick/m_subdivMapping) + x; - yy = my*(m_brick/m_subdivMapping) + y; - p1.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5); - p1.tv2 = ((float)(oy%5)*m_brick+yy+0.0f)/(m_brick*5); - p2.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5); - p2.tv2 = ((float)(oy%5)*m_brick+yy+1.0f)/(m_brick*5); - - // Correction for 1 pixel cover (*). - p1.tu2 = (p1.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel); - p1.tv2 = (p1.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel); - p2.tu2 = (p2.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel); - p2.tv2 = (p2.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel); -#endif - - buffer->vertex[i++] = p1; - buffer->vertex[i++] = p2; - } - m_engine->AddQuick(objRank, buffer, texName1, texName2, min, max, true); - } - } - } - - transform.LoadIdentity(); - transform.Set(1, 4, o.x); - transform.Set(3, 4, o.z); - m_engine->SetObjectTransform(objRank, transform); - - return true; -} - -// (*) There is 1 pixel cover around each of the 16 surfaces: -// -// |<--------------256-------------->| -// | |<----------254---------->| | -// |---|---|---|-- ... --|---|---|---| -// | 0.0 1.0 | -// | | | | -// 0.0 min max 1.0 -// -// The uv coordinates used for texturing are between min and max (instead of 0 and 1). -// This allows to exclude the pixels situated in a margin of a pixel around the surface. - - -// Seeks a materials based on theirs identifier. - -TerrainMaterial* CTerrain::LevelSearchMat(int id) -{ - int i; - - for ( i=0 ; itexName); - strcpy(name, tm->texName); - uv.x = tm->u; - uv.y = tm->v; - } -} - -// Returns the height of the terrain. - -float CTerrain::LevelRetHeight(int x, int y) -{ - int size; - - size = (m_mosaic*m_brick+1); - - if ( x < 0 ) x = 0; - if ( x >= size ) x = size-1; - if ( y < 0 ) y = 0; - if ( y >= size ) y = size-1; - - return m_relief[x+y*size]; -} - -// Decide whether a point is using the materials. - -bool CTerrain::LevelGetDot(int x, int y, float min, float max, float slope) -{ - float hc, h[4]; - int i; - - hc = LevelRetHeight(x, y); - h[0] = LevelRetHeight(x+0, y+1); - h[1] = LevelRetHeight(x+1, y+0); - h[2] = LevelRetHeight(x+0, y-1); - h[3] = LevelRetHeight(x-1, y+0); - - if ( hc < min || - hc > max ) return false; - - if ( slope == 0.0f ) - { - return true; - } - - if ( slope > 0.0f ) - { - for ( i=0 ; i<4 ; i++ ) - { - if ( fabs(hc-h[i]) >= slope ) - { - return false; - } - } - return true; - } - - if ( slope < 0.0f ) - { - for ( i=0 ; i<4 ; i++ ) - { - if ( fabs(hc-h[i]) < -slope ) - { - return false; - } - } - return true; - } - - return false; -} - -// Seeks if material exists. -// Returns the index within m_levelMat or -1 if there is not. -// m_levelMat[i].id gives the identifier. - -int CTerrain::LevelTestMat(char *mat) -{ - int i; - - for ( i=0 ; imat[0] != mat[0] || - tm->mat[1] != mat[1] || - tm->mat[2] != mat[2] || - tm->mat[3] != mat[3] ) // id incompatible with mat? - { - ii = LevelTestMat(mat); - if ( ii == -1 ) return; - id = m_levelMat[ii].id; // looking for a id compatible with mat - } - - // Changes the point. - m_levelDot[x+y*m_levelDotSize].id = id; - m_levelDot[x+y*m_levelDotSize].mat[0] = mat[0]; - m_levelDot[x+y*m_levelDotSize].mat[1] = mat[1]; - m_levelDot[x+y*m_levelDotSize].mat[2] = mat[2]; - m_levelDot[x+y*m_levelDotSize].mat[3] = mat[3]; - - // Changes the lower neighbor. - if ( (x+0) >= 0 && (x+0) < m_levelDotSize && - (y-1) >= 0 && (y-1) < m_levelDotSize ) - { - i = (x+0)+(y-1)*m_levelDotSize; - if ( m_levelDot[i].mat[0] != mat[2] ) - { - m_levelDot[i].mat[0] = mat[2]; - ii = LevelTestMat(m_levelDot[i].mat); - if ( ii != -1 ) - { - m_levelDot[i].id = m_levelMat[ii].id; - } - } - } - - // Modifies the left neighbor. - if ( (x-1) >= 0 && (x-1) < m_levelDotSize && - (y+0) >= 0 && (y+0) < m_levelDotSize ) - { - i = (x-1)+(y+0)*m_levelDotSize; - if ( m_levelDot[i].mat[1] != mat[3] ) - { - m_levelDot[i].mat[1] = mat[3]; - ii = LevelTestMat(m_levelDot[i].mat); - if ( ii != -1 ) - { - m_levelDot[i].id = m_levelMat[ii].id; - } - } - } - - // Changes the upper neighbor. - if ( (x+0) >= 0 && (x+0) < m_levelDotSize && - (y+1) >= 0 && (y+1) < m_levelDotSize ) - { - i = (x+0)+(y+1)*m_levelDotSize; - if ( m_levelDot[i].mat[2] != mat[0] ) - { - m_levelDot[i].mat[2] = mat[0]; - ii = LevelTestMat(m_levelDot[i].mat); - if ( ii != -1 ) - { - m_levelDot[i].id = m_levelMat[ii].id; - } - } - } - - // Changes the right neighbor. - if ( (x+1) >= 0 && (x+1) < m_levelDotSize && - (y+0) >= 0 && (y+0) < m_levelDotSize ) - { - i = (x+1)+(y+0)*m_levelDotSize; - if ( m_levelDot[i].mat[3] != mat[1] ) - { - m_levelDot[i].mat[3] = mat[1]; - ii = LevelTestMat(m_levelDot[i].mat); - if ( ii != -1 ) - { - m_levelDot[i].id = m_levelMat[ii].id; - } - } - } -} - -// Tests if a material can give a place, according to its four neighbors. -// If yes, puts the point. - -bool CTerrain::LevelIfDot(int x, int y, int id, char *mat) -{ - char test[4]; - - // Compatible with lower neighbor? - if ( x+0 >= 0 && x+0 < m_levelDotSize && - y-1 >= 0 && y-1 < m_levelDotSize ) - { - test[0] = mat[2]; - test[1] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[1]; - test[2] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[2]; - test[3] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[3]; - - if ( LevelTestMat(test) == -1 ) return false; - } - - // Compatible with left neighbor? - if ( x-1 >= 0 && x-1 < m_levelDotSize && - y+0 >= 0 && y+0 < m_levelDotSize ) - { - test[0] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[0]; - test[1] = mat[3]; - test[2] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[2]; - test[3] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[3]; - - if ( LevelTestMat(test) == -1 ) return false; - } - - // Compatible with upper neighbor? - if ( x+0 >= 0 && x+0 < m_levelDotSize && - y+1 >= 0 && y+1 < m_levelDotSize ) - { - test[0] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[0]; - test[1] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[1]; - test[2] = mat[0]; - test[3] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[3]; - - if ( LevelTestMat(test) == -1 ) return false; - } - - // Compatible with right neighbor? - if ( x+1 >= 0 && x+1 < m_levelDotSize && - y+0 >= 0 && y+0 < m_levelDotSize ) - { - test[0] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[0]; - test[1] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[1]; - test[2] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[2]; - test[3] = mat[1]; - - if ( LevelTestMat(test) == -1 ) return false; - } - - LevelSetDot(x, y, id, mat); // puts the point - return true; -} - -// Modifies the state of a point. - -bool CTerrain::LevelPutDot(int x, int y, int id) -{ - TerrainMaterial *tm; - char mat[4]; - int up, right, down, left; - - x /= m_brick/m_subdivMapping; - y /= m_brick/m_subdivMapping; - - if ( x < 0 || x >= m_levelDotSize || - y < 0 || y >= m_levelDotSize ) return false; - - tm = LevelSearchMat(id); - if ( tm == 0 ) return false; - - // Tries without changing neighbors. - if ( LevelIfDot(x, y, id, tm->mat) ) return true; - - // Tries changing a single neighbor (4x). - for ( up=0 ; upmat[1]; - mat[2] = tm->mat[2]; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - - for ( right=0 ; rightmat[0]; - mat[1] = right; - mat[2] = tm->mat[2]; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - - for ( down=0 ; downmat[0]; - mat[1] = tm->mat[1]; - mat[2] = down; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - - for ( left=0 ; leftmat[0]; - mat[1] = tm->mat[1]; - mat[2] = tm->mat[2]; - mat[3] = left; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - - // Tries changing two neighbors (6x). - for ( up=0 ; upmat[1]; - mat[2] = down; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - for ( right=0 ; rightmat[0]; - mat[1] = right; - mat[2] = tm->mat[2]; - mat[3] = left; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - for ( up=0 ; upmat[2]; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - for ( right=0 ; rightmat[0]; - mat[1] = right; - mat[2] = down; - mat[3] = tm->mat[3]; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - for ( down=0 ; downmat[0]; - mat[1] = tm->mat[1]; - mat[2] = down; - mat[3] = left; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - for ( up=0 ; upmat[1]; - mat[2] = tm->mat[2]; - mat[3] = left; - - if ( LevelIfDot(x, y, id, mat) ) return true; - } - } - - // Tries changing all the neighbors. - for ( up=0 ; upmat[j]; - } - } - - return true; -} - -// Generates a level in the terrain. - -bool CTerrain::LevelGenerate(int *id, float min, float max, - float slope, float freq, - Math::Vector center, float radius) -{ - TerrainMaterial *tm; - Math::Vector pos; - int i, numID, x, y, xx, yy, group, rnd; - float dim; - - static char random[100] = - { - 84,25,12, 6,34,52,85,38,97,16, - 21,31,65,19,62,40,72,22,48,61, - 56,47, 8,53,73,77, 4,91,26,88, - 76, 1,44,93,39,11,71,17,98,95, - 88,83,18,30, 3,57,28,49,74, 9, - 32,13,96,66,15,70,36,10,59,94, - 45,86, 2,29,63,42,51, 0,79,27, - 54, 7,20,69,89,23,64,43,81,92, - 90,33,46,14,67,35,50, 5,87,60, - 68,55,24,78,41,75,58,80,37,82, - }; - - i = 0; - while ( id[i] != 0 ) - { - tm = LevelSearchMat(id[i++]); - if ( tm == 0 ) return false; - } - numID = i; - - group = m_brick/m_subdivMapping; - - if ( radius > 0.0f && radius < 5.0f ) // just a square? - { - dim = (m_mosaic*m_brick*m_size)/2.0f; - - xx = (int)((center.x+dim)/m_size); - yy = (int)((center.z+dim)/m_size); - - x = xx/group; - y = yy/group; - - tm = LevelSearchMat(id[0]); - if ( tm != 0 ) - { - LevelSetDot(x, y, id[0], tm->mat); // puts the point - } -//? LevelPutDot(xx,yy, id[0]); - } - else - { - for ( y=0 ; y radius ) continue; - } - - if ( freq < 100.0f ) - { - rnd = random[(x%10)+(y%10)*10]; - if ( (float)rnd > freq ) continue; - } - - xx = x*group + group/2; - yy = y*group + group/2; - - if ( LevelGetDot(xx,yy, min, max, slope) ) - { - rnd = random[(x%10)+(y%10)*10]; - i = rnd%numID; - LevelPutDot(xx,yy, id[i]); - } - } - } - } - - return true; -} - -// Initializes an table with empty levels. - -void CTerrain::LevelOpenTable() -{ - int i, j; - - if ( !m_bLevelText ) return; - if ( m_levelDot != 0 ) return; // already allocated - - m_levelDotSize = (m_mosaic*m_brick)/(m_brick/m_subdivMapping)+1; - m_levelDot = (DotLevel*)malloc(m_levelDotSize*m_levelDotSize*sizeof(DotLevel)); - - for ( i=0 ; iCreateObject(); - m_engine->SetObjectType(objRank, TYPETERRAIN); // it is a terrain - - m_objRank[x+y*m_mosaic] = objRank; - - if ( bMultiRes ) - { - min = 0.0f; - max = m_vision; - max *= m_engine->RetClippingDistance(); - for ( step=0 ; step tp2.x ) - { - x = tp1.x; - tp1.x = tp2.x; - tp2.x = x; - } - - if ( tp1.y > tp2.y ) - { - y = tp1.y; - tp1.y = tp2.y; - tp2.y = y; - } - - size = (m_mosaic*m_brick)+1; - - // Calculates the current average height. - avg = 0.0f; - nb = 0; - for ( y=tp1.y ; y<=tp2.y ; y++ ) - { - for ( x=tp1.x ; x<=tp2.x ; x++ ) - { - avg += m_relief[x+y*size]; - nb ++; - } - } - avg /= (float)nb; - - // Changes the description of the relief. - for ( y=tp1.y ; y<=tp2.y ; y++ ) - { - for ( x=tp1.x ; x<=tp2.x ; x++ ) - { - m_relief[x+y*size] = avg+height; - - if ( x%m_brick == 0 && y%m_depth != 0 ) - { - m_relief[(x+0)+(y-1)*size] = avg+height; - m_relief[(x+0)+(y+1)*size] = avg+height; - } - - if ( y%m_brick == 0 && x%m_depth != 0 ) - { - m_relief[(x-1)+(y+0)*size] = avg+height; - m_relief[(x+1)+(y+0)*size] = avg+height; - } - } - } - AdjustRelief(); - - pp1.x = (tp1.x-2)/m_brick; - pp1.y = (tp1.y-2)/m_brick; - pp2.x = (tp2.x+1)/m_brick; - pp2.y = (tp2.y+1)/m_brick; - - if ( pp1.x < 0 ) pp1.x = 0; - if ( pp1.x >= m_mosaic ) pp1.x = m_mosaic-1; - if ( pp1.y < 0 ) pp1.y = 0; - if ( pp1.y >= m_mosaic ) pp1.y = m_mosaic-1; - - for ( y=pp1.y ; y<=pp2.y ; y++ ) - { - for ( x=pp1.x ; x<=pp2.x ; x++ ) - { - m_engine->DeleteObject(m_objRank[x+y*m_mosaic]); - CreateSquare(m_bMultiText, x, y); // recreates the square - } - } - m_engine->Update(); - - return true; -} - - -// Management of the wind. - -void CTerrain::SetWind(Math::Vector speed) -{ - m_wind = speed; -} - -Math::Vector CTerrain::RetWind() -{ - return m_wind; -} - - -// Gives the exact slope of the terrain of a place given. - -float CTerrain::RetFineSlope(const Math::Vector &pos) -{ - Math::Vector n; - - if ( !GetNormal(n, pos) ) return 0.0f; - return fabs(Math::RotateAngle(Math::Point(n.x, n.z).Length(), n.y)-Math::PI/2.0f); -} - -// Gives the approximate slope of the terrain of a specific location. - -float CTerrain::RetCoarseSlope(const Math::Vector &pos) -{ - float dim, level[4], min, max; - int x, y; - - if ( m_relief == 0 ) return 0.0f; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((pos.x+dim)/m_size); - y = (int)((pos.z+dim)/m_size); - - if ( x < 0 || x >= m_mosaic*m_brick || - y < 0 || y >= m_mosaic*m_brick ) return 0.0f; - - level[0] = m_relief[(x+0)+(y+0)*(m_mosaic*m_brick+1)]; - level[1] = m_relief[(x+1)+(y+0)*(m_mosaic*m_brick+1)]; - level[2] = m_relief[(x+0)+(y+1)*(m_mosaic*m_brick+1)]; - level[3] = m_relief[(x+1)+(y+1)*(m_mosaic*m_brick+1)]; - - min = Math::Min(level[0], level[1], level[2], level[3]); - max = Math::Max(level[0], level[1], level[2], level[3]); - - return atanf((max-min)/m_size); -} - -// Gives the normal vector at the position p (x,-,z) of the ground. - -bool CTerrain::GetNormal(Math::Vector &n, const Math::Vector &p) -{ - Math::Vector p1, p2, p3, p4; - float dim; - int x, y; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((p.x+dim)/m_size); - y = (int)((p.z+dim)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; - - p1 = RetVector(x+0, y+0); - p2 = RetVector(x+1, y+0); - p3 = RetVector(x+0, y+1); - p4 = RetVector(x+1, y+1); - - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) - { - n = Math::NormalToPlane(p1,p2,p3); - } - else - { - n = Math::NormalToPlane(p2,p4,p3); - } - return true; -} - -// Returns the height of the ground. - -float CTerrain::RetFloorLevel(const Math::Vector &p, bool bBrut, bool bWater) -{ - Math::Vector p1, p2, p3, p4, ps; - float dim, level; - int x, y; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((p.x+dim)/m_size); - y = (int)((p.z+dim)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; - - p1 = RetVector(x+0, y+0); - p2 = RetVector(x+1, y+0); - p3 = RetVector(x+0, y+1); - p4 = RetVector(x+1, y+1); - - ps = p; - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) - { - if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; - } - else - { - if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f; - } - - if ( !bBrut ) AdjustBuildingLevel(ps); - - if ( bWater ) // not going underwater? - { - level = m_water->RetLevel(); - if ( ps.y < level ) ps.y = level; // not under water - } - - return ps.y; -} - -// Returns the height to the ground. -// This height is positive when you are above the ground. - -float CTerrain::RetFloorHeight(const Math::Vector &p, bool bBrut, bool bWater) -{ - Math::Vector p1, p2, p3, p4, ps; - float dim, level; - int x, y; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((p.x+dim)/m_size); - y = (int)((p.z+dim)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; - - p1 = RetVector(x+0, y+0); - p2 = RetVector(x+1, y+0); - p3 = RetVector(x+0, y+1); - p4 = RetVector(x+1, y+1); - - ps = p; - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) - { - if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; - } - else - { - if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f; - } - - if ( !bBrut ) AdjustBuildingLevel(ps); - - if ( bWater ) // not going underwater? - { - level = m_water->RetLevel(); - if ( ps.y < level ) ps.y = level; // not under water - } - - return p.y-ps.y; -} - -// Modifies the coordinate "y" of point "p" to rest on the ground floor. - -bool CTerrain::MoveOnFloor(Math::Vector &p, bool bBrut, bool bWater) -{ - Math::Vector p1, p2, p3, p4; - float dim, level; - int x, y; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((p.x+dim)/m_size); - y = (int)((p.z+dim)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; - - p1 = RetVector(x+0, y+0); - p2 = RetVector(x+1, y+0); - p3 = RetVector(x+0, y+1); - p4 = RetVector(x+1, y+1); - - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) - { - if ( !IntersectY(p1, p2, p3, p) ) return false; - } - else - { - if ( !IntersectY(p2, p4, p3, p) ) return false; - } - - if ( !bBrut ) AdjustBuildingLevel(p); - - if ( bWater ) // not going underwater? - { - level = m_water->RetLevel(); - if ( p.y < level ) p.y = level; // not under water - } - - return true; -} - -// Modifies a coordinate so that it is on the ground. -// Returns false if the initial coordinate was too far. - -bool CTerrain::ValidPosition(Math::Vector &p, float marging) -{ - bool bOK = true; - float limit; - - limit = m_mosaic*m_brick*m_size/2.0f - marging; - - if ( p.x < -limit ) - { - p.x = -limit; - bOK = false; - } - - if ( p.z < -limit ) - { - p.z = -limit; - bOK = false; - } - - if ( p.x > limit ) - { - p.x = limit; - bOK = false; - } - - if ( p.z > limit ) - { - p.z = limit; - bOK = false; - } - - return bOK; -} - - - -// Empty the table of elevations. - -void CTerrain::FlushBuildingLevel() -{ - m_buildingUsed = 0; -} - -// Adds a new elevation for a building. - -bool CTerrain::AddBuildingLevel(Math::Vector center, float min, float max, - float height, float factor) -{ - int i; - - for ( i=0 ; i= MAXBUILDINGLEVEL ) return false; - i = m_buildingUsed++; - - update: - m_buildingTable[i].center = center; - m_buildingTable[i].min = min; - m_buildingTable[i].max = max; - m_buildingTable[i].level = RetFloorLevel(center, true); - m_buildingTable[i].height = height; - m_buildingTable[i].factor = factor; - m_buildingTable[i].bboxMinX = center.x-max; - m_buildingTable[i].bboxMaxX = center.x+max; - m_buildingTable[i].bboxMinZ = center.z-max; - m_buildingTable[i].bboxMaxZ = center.z+max; - - return true; -} - -// Updates the elevation for a building when it was moved up (after a terraforming). - -bool CTerrain::UpdateBuildingLevel(Math::Vector center) -{ - int i; - - for ( i=0 ; i m_buildingTable[i].bboxMaxX || - p.z < m_buildingTable[i].bboxMinZ || - p.z > m_buildingTable[i].bboxMaxZ ) continue; - - dist = Math::DistanceProjected(p, m_buildingTable[i].center); - - if ( dist <= m_buildingTable[i].max ) - { - return m_buildingTable[i].factor; - } - } - return 1.0f; // it is normal on the ground -} - -// Adjusts a position according to a possible rise. - -void CTerrain::AdjustBuildingLevel(Math::Vector &p) -{ - Math::Vector border; - float dist, base; - int i; - - for ( i=0 ; i m_buildingTable[i].bboxMaxX || - p.z < m_buildingTable[i].bboxMinZ || - p.z > m_buildingTable[i].bboxMaxZ ) continue; - - dist = Math::DistanceProjected(p, m_buildingTable[i].center); - - if ( dist > m_buildingTable[i].max ) continue; - - if ( dist < m_buildingTable[i].min ) - { - p.y = m_buildingTable[i].level+m_buildingTable[i].height; - return; - } - -#if 0 - p.y = m_buildingTable[i].level; - p.y += (m_buildingTable[i].max-dist)/ - (m_buildingTable[i].max-m_buildingTable[i].min)* - m_buildingTable[i].height; - - base = RetFloorLevel(p, true); - if ( p.y < base ) p.y = base; -#else - border.x = ((p.x-m_buildingTable[i].center.x)*m_buildingTable[i].max)/ - dist+m_buildingTable[i].center.x; - border.z = ((p.z-m_buildingTable[i].center.z)*m_buildingTable[i].max)/ - dist+m_buildingTable[i].center.z; - - base = RetFloorLevel(border, true); - - p.y = (m_buildingTable[i].max-dist)/ - (m_buildingTable[i].max-m_buildingTable[i].min)* - (m_buildingTable[i].level+m_buildingTable[i].height-base)+ - base; -#endif - return; - } -} - - -// Returns the hardness of the ground in a given place. -// The hardness determines the noise (SOUND_STEP and SOUND_BOUM). - -float CTerrain::RetHardness(const Math::Vector &p) -{ - TerrainMaterial* tm; - float factor, dim; - int x, y, id; - - factor = RetBuildingFactor(p); - if ( factor != 1.0f ) return 1.0f; // on building - - if ( m_levelDot == 0 ) return m_defHardness; - - dim = (m_mosaic*m_brick*m_size)/2.0f; - - x = (int)((p.x+dim)/m_size); - y = (int)((p.z+dim)/m_size); - - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return m_defHardness; - - x /= m_brick/m_subdivMapping; - y /= m_brick/m_subdivMapping; - - if ( x < 0 || x >= m_levelDotSize || - y < 0 || y >= m_levelDotSize ) return m_defHardness; - - id = m_levelDot[x+y*m_levelDotSize].id; - tm = LevelSearchMat(id); - if ( tm == 0 ) return m_defHardness; - - return tm->hardness; -} - - -// Shows the flat areas on the ground. - -void CTerrain::GroundFlat(Math::Vector pos) -{ - Math::Vector p; - float rapport, angle; - int x, y, i; - static char table[41*41]; - - - rapport = 3200.0f/1024.0f; - - for ( y=0 ; y<=40 ; y++ ) - { - for ( x=0 ; x<=40 ; x++ ) - { - i = x + y*41; - table[i] = 0; - - p.x = (x-20)*rapport; - p.z = (y-20)*rapport; - p.y = 0.0f; - if ( Math::Point(p.x, p.y).Length() > 20.0f*rapport ) continue; - - angle = RetFineSlope(pos+p); - - if ( angle < FLATLIMIT ) - { - table[i] = 1; - } - else - { - table[i] = 2; - } - } - } - - m_engine->GroundMarkCreate(pos, 40.0f, 0.001f, 15.0f, 0.001f, 41, 41, table); -} - - -// Calculates the radius of the largest flat area available. -// This calculation is not optimized! - -float CTerrain::RetFlatZoneRadius(Math::Vector center, float max) -{ - Math::Vector pos; - Math::Point c, p; - float ref, radius, angle, h; - int i, nb; - - angle = RetFineSlope(center); - if ( angle >= FLATLIMIT ) return 0.0f; - - ref = RetFloorLevel(center, true); - - radius = 1.0f; - while ( radius <= max ) - { - angle = 0.0f; - nb = (int)(2.0f*Math::PI*radius); - if ( nb < 8 ) nb = 8; - for ( i=0 ; i 1.0f ) return radius; - - angle += Math::PI*2.0f/8.0f; - } - radius += 1.0f; - } - return max; -} - - - -// Specifies the maximum height of flight. - -void CTerrain::SetFlyingMaxHeight(float height) -{ - m_flyingMaxHeight = height; -} - -// Returns the maximum height of flight. - -float CTerrain::RetFlyingMaxHeight() -{ - return m_flyingMaxHeight; -} - - -// Empty the limits table of flight. - -void CTerrain::FlushFlyingLimit() -{ - m_flyingMaxHeight = 280.0f; - m_flyingLimitTotal = 0; -} - -// Empty the limits table of flight. - -bool CTerrain::AddFlyingLimit(Math::Vector center, - float extRadius, float intRadius, - float maxHeight) -{ - int i; - - if ( m_flyingLimitTotal >= MAXFLYINGLIMIT ) return false; - - i = m_flyingLimitTotal; - m_flyingLimit[i].center = center; - m_flyingLimit[i].extRadius = extRadius; - m_flyingLimit[i].intRadius = intRadius; - m_flyingLimit[i].maxHeight = maxHeight; - m_flyingLimitTotal = i+1; - - return true; -} - -// Returns the maximum height of flight. - -float CTerrain::RetFlyingLimit(Math::Vector pos, bool bNoLimit) -{ - float dist, h; - int i; - - if ( bNoLimit ) return 280.0f; - if ( m_flyingLimitTotal == 0 ) return m_flyingMaxHeight; - - for ( i=0 ; i= m_flyingLimit[i].extRadius ) continue; - - if ( dist <= m_flyingLimit[i].intRadius ) - { - return m_flyingLimit[i].maxHeight; - } - - dist -= m_flyingLimit[i].intRadius; - - h = dist*(m_flyingMaxHeight-m_flyingLimit[i].maxHeight)/ - (m_flyingLimit[i].extRadius-m_flyingLimit[i].intRadius); - - return h + m_flyingLimit[i].maxHeight; - } - - return m_flyingMaxHeight; -} - +// * 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/. + +// terrain.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/const.h" +#include "math/geometry.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "common/language.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/modfile.h" +#include "old/water.h" +#include "old/terrain.h" + + +const int BMPHEAD = 1078; + + + +// Constructor of the terrain. + +CTerrain::CTerrain(CInstanceManager* iMan) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_TERRAIN, this); + + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); + + m_mosaic = 20; + m_brick = 1<<4; + m_size = 10.0f; + m_vision = 200.0f; + m_relief = 0; + m_texture = 0; + m_objRank = 0; + m_scaleMapping = 0.01f; + m_scaleRelief = 1.0f; + m_subdivMapping = 1; + m_depth = 2; + m_texBaseName[0]= 0; + m_texBaseExt[0] = 0; + m_bMultiText = true; + m_bLevelText = false; + m_resources = 0; + m_levelMatTotal = 0; + m_levelMatMax = 0; + m_levelDot = 0; + m_wind = Math::Vector(0.0f, 0.0f, 0.0f); + m_defHardness = 0.5f; + + FlushBuildingLevel(); + FlushFlyingLimit(); +} + +// Destructor of the terrain. + +CTerrain::~CTerrain() +{ + free(m_relief); + free(m_texture); + free(m_objRank); + free(m_resources); +} + + +// Generates a new flat terrain. +// The terrain is composed of mosaics, themselves composed of bricks. +// Each brick is composed of two triangles. +// mosaic: number of mosaics along the axes X and Z +// brick: number of bricks (power of 2) +// size: size of a brick along the axes X and Z +// vision: vision before a change of resolution +// scaleMapping: scale textures for mapping +// +// ^ z +// | <---> brick*size +// +---+---+---+---+ +// | | | |_|_| mosaic = 4 +// | | | | | | brick = 2 (brickP2=1) +// +---+---+---+---+ +// |\ \| | | | +// |\ \| | | | +// +---+---o---+---+---> x +// | | | | | +// | | | | | +// +---+---+---+---+ +// | | | | | The land is viewed from above here. +// | | | | | +// +---+---+---+---+ +// <---------------> mosaic*brick*size + +bool CTerrain::Generate(int mosaic, int brickP2, float size, float vision, + int depth, float hardness) +{ + int dim; + + m_mosaic = mosaic; + m_brick = 1<SetTerrainVision(vision); + + m_bMultiText = true; + m_bLevelText = false; + m_scaleMapping = 1.0f/(m_brick*m_size); + m_subdivMapping = 1; + + dim = (m_mosaic*m_brick+1)*(m_mosaic*m_brick+1); + m_relief = (float*)malloc(sizeof(float)*dim); + ZeroMemory(m_relief, sizeof(float)*dim); + + dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping; + m_texture = (int*)malloc(sizeof(int)*dim); + ZeroMemory(m_texture, sizeof(int)*dim); + + dim = m_mosaic*m_mosaic; + m_objRank = (int*)malloc(sizeof(int)*dim); + ZeroMemory(m_objRank, sizeof(int)*dim); + + return true; +} + + +int CTerrain::RetMosaic() +{ + return m_mosaic; +} + +int CTerrain::RetBrick() +{ + return m_brick; +} + +float CTerrain::RetSize() +{ + return m_size; +} + +float CTerrain::RetScaleRelief() +{ + return m_scaleRelief; +} + + +// Initializes the names of textures to use for the land. + +bool CTerrain::InitTextures(char* baseName, int* table, int dx, int dy) +{ + int x, y; + char* p; + + m_bLevelText = false; + + strcpy(m_texBaseName, baseName); + p = strchr(m_texBaseName, '.'); // p <- ^beginning of the extension + if ( p == 0 ) + { + strcpy(m_texBaseExt, ".tga"); + } + else + { + strcpy(m_texBaseExt, p); // m_texBaseExt <- ".tga" or ".bmp" + *p = 0; // m_texBaseName <- name without extension + } + + for ( y=0 ; y= MAXMATTERRAIN-1 ) return false; + + LevelOpenTable(); + + if ( id == 0 ) + { + id = m_levelID++; // puts an ID internal standard + } + + strcpy(m_levelMat[i].texName, baseName); + m_levelMat[i].id = id; + m_levelMat[i].u = u; + m_levelMat[i].v = v; + m_levelMat[i].mat[0] = up; + m_levelMat[i].mat[1] = right; + m_levelMat[i].mat[2] = down; + m_levelMat[i].mat[3] = left; + m_levelMat[i].hardness = hardness; + + if ( m_levelMatMax < up+1 ) m_levelMatMax = up+1; + if ( m_levelMatMax < right+1 ) m_levelMatMax = right+1; + if ( m_levelMatMax < down+1 ) m_levelMatMax = down+1; + if ( m_levelMatMax < left+1 ) m_levelMatMax = left+1; + + m_bLevelText = true; + m_subdivMapping = 4; + + m_levelMatTotal ++; + return true; +} + + +// Load relief from a BMP file. +// The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. +// The image must be 8 bits/pixel, 256 colors with a standard pallet. + +// Converts coordinated image (x;y) -> world (x;-;z) : +// Wx = 5*Ix-400 +// Wz = -(5*Iy-400) + +// Converts coordinated world (x;-;z) -> image (x;y) : +// Ix = (400+Wx)/5 +// Iy = (400-Wz)/5 + +bool CTerrain::ResFromBMP(const char* filename) +{ + FILE* file; + int size, sizem; + + file = fopen(filename, "rb"); + if ( file == NULL ) return false; + + size = (m_mosaic*m_brick)+1; + sizem = ((size+4-1)/4)*4; // upper size multiple of 4 + + if ( m_resources != 0 ) + { + free(m_resources); + } + + m_resources = (unsigned char*)malloc(BMPHEAD+sizem*size); + fread(m_resources, BMPHEAD+sizem*size, 1, file); + + if ( m_resources[18] != (size&0xff) || m_resources[19] != (size>>8) || + m_resources[22] != (size&0xff) || m_resources[23] != (size>>8) ) + { + free(m_resources); + m_resources = 0; + fclose(file); + return false; + } + + fclose(file); + return true; +} + +// Returns the resource type available underground. + +TerrainRes CTerrain::RetResource(const Math::Vector &p) +{ + int x, y, size, sizem, ress; + + if ( m_resources == 0 ) return TR_NULL; + + x = (int)((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size); + y = (int)((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return TR_NULL; + + size = (m_mosaic*m_brick)+1; + sizem = ((size+4-1)/4)*4; // upper size multiple of 4 + + ress = m_resources[BMPHEAD+x+sizem*y]; + if ( ress == 5 ) return TR_STONE; // red? + if ( ress == 35 ) return TR_URANIUM; // yellow? + if ( ress == 30 ) return TR_POWER; // green? + if ( ress == 24 ) return TR_KEYa; // ~green? + if ( ress == 25 ) return TR_KEYb; // ~green? + if ( ress == 26 ) return TR_KEYc; // ~green? + if ( ress == 27 ) return TR_KEYd; // ~green? + + return TR_NULL; +} + + +// Initializes a completely flat terrain. + +void CTerrain::FlushRelief() +{ + free(m_relief); + m_relief = 0; +} + +// Load relief from a BMP file. +// The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. +// The image must be 8 bits/pixel, 256 gray scale: +// white = ground (y=0) +// black = mountain (y=255*scaleRelief) + +// Converts coordinated image(x;y) -> world (x;-;z) : +// Wx = 5*Ix-400 +// Wz = -(5*Iy-400) + +// Converts coordinated world (x;-;z) -> image (x;y) : +// Ix = (400+Wx)/5 +// Iy = (400-Wz)/5 + +bool CTerrain::ReliefFromBMP(const char* filename, float scaleRelief, + bool adjustBorder) +{ + FILE* file; + unsigned char* buffer; + int size, sizem, x, y; + float level, limit, dist, border; + + m_scaleRelief = scaleRelief; + + file = fopen(filename, "rb"); + if ( file == NULL ) return false; + + size = (m_mosaic*m_brick)+1; + sizem = ((size+4-1)/4)*4; // upper size multiple of 4 + + buffer = (unsigned char*)malloc(BMPHEAD+sizem*size); + fread(buffer, BMPHEAD+sizem*size, 1, file); + + if ( buffer[18] != (size&0xff) || buffer[19] != (size>>8) || + buffer[22] != (size&0xff) || buffer[23] != (size>>8) ) + { + free(buffer); + fclose(file); + return false; + } + + limit = 0.9f; + for ( y=0 ; y limit && adjustBorder ) + { + dist = (dist-limit)/(1.0f-limit); // 0..1 + if ( dist > 1.0f ) dist = 1.0f; + border = 300.0f+Math::Rand()*20.0f; + level = level+dist*(border-level); + } + + m_relief[x+y*size] = level; + } + } + + free(buffer); + fclose(file); + return true; +} + +// Adds a point of elevation in the buffer of relief. + +bool CTerrain::ReliefAddDot(Math::Vector pos, float scaleRelief) +{ + float dim; + int size, x, y; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + size = (m_mosaic*m_brick)+1; + + pos.x = (pos.x+dim)/m_size; + pos.z = (pos.z+dim)/m_size; + + x = (int)pos.x; + y = (int)pos.z; + + if ( x < 0 || x >= size || + y < 0 || y >= size ) return false; + + if ( m_relief[x+y*size] < pos.y*scaleRelief ) + { + m_relief[x+y*size] = pos.y*scaleRelief; + } + return true; +} + +// Load relief from a DXF file. + +bool CTerrain::ReliefFromDXF(const char* filename, float scaleRelief) +{ + FILE* file = NULL; + char line[100]; + int command, rankSommet, nbSommet, nbFace, size; + Math::Vector* table; + bool bWaitNbSommet; + bool bWaitNbFace; + bool bWaitSommetX; + bool bWaitSommetY; + bool bWaitSommetZ; + bool bWaitFaceX; + bool bWaitFaceY; + bool bWaitFaceZ; + float x,y,z; + int p1,p2,p3; + + ZeroMemory(m_relief, sizeof(float)*(m_mosaic*m_brick+1)*(m_mosaic*m_brick+1)); + + file = fopen(filename, "r"); + if ( file == NULL ) return false; + + size = (m_mosaic*m_brick)+1; + table = (Math::Vector*)malloc(sizeof(Math::Vector)*size*size); + + rankSommet = 0; + bWaitNbSommet = false; + bWaitNbFace = false; + bWaitSommetX = false; + bWaitSommetY = false; + bWaitSommetZ = false; + bWaitFaceX = false; + bWaitFaceY = false; + bWaitFaceZ = false; + + while ( fgets(line, 100, file) != NULL ) + { + sscanf(line, "%d", &command); + if ( fgets(line, 100, file) == NULL ) break; + + if ( command == 66 ) + { + bWaitNbSommet = true; + } + + if ( command == 71 && bWaitNbSommet ) + { + bWaitNbSommet = false; + sscanf(line, "%d", &nbSommet); + if ( nbSommet > size*size ) nbSommet = size*size; + rankSommet = 0; + bWaitNbFace = true; + } + + if ( command == 72 && bWaitNbFace ) + { + bWaitNbFace = false; + sscanf(line, "%d", &nbFace); + bWaitSommetX = true; + } + + if ( command == 10 && bWaitSommetX ) + { + bWaitSommetX = false; + sscanf(line, "%f", &x); + bWaitSommetY = true; + } + + if ( command == 20 && bWaitSommetY ) + { + bWaitSommetY = false; + sscanf(line, "%f", &y); + bWaitSommetZ = true; + } + + if ( command == 30 && bWaitSommetZ ) + { + bWaitSommetZ = false; + sscanf(line, "%f", &z); + + nbSommet --; + if ( nbSommet >= 0 ) + { + Math::Vector p(x,z,y); // permutation of Y and Z! + table[rankSommet++] = p; + bWaitSommetX = true; + } + else + { + bWaitFaceX = true; + } + } + + if ( command == 71 && bWaitFaceX ) + { + bWaitFaceX = false; + sscanf(line, "%d", &p1); + if ( p1 < 0 ) p1 = -p1; + bWaitFaceY = true; + } + + if ( command == 72 && bWaitFaceY ) + { + bWaitFaceY = false; + sscanf(line, "%d", &p2); + if ( p2 < 0 ) p2 = -p2; + bWaitFaceZ = true; + } + + if ( command == 73 && bWaitFaceZ ) + { + bWaitFaceZ = false; + sscanf(line, "%d", &p3); + if ( p3 < 0 ) p3 = -p3; + + nbFace --; + if ( nbFace >= 0 ) + { + ReliefAddDot(table[p3-1], scaleRelief); + ReliefAddDot(table[p2-1], scaleRelief); + ReliefAddDot(table[p1-1], scaleRelief); + bWaitFaceX = true; + } + } + + } + + free(table); + fclose(file); + return true; +} + + +// Adjusts a position so that it does not exceed the boundaries. + +void CTerrain::LimitPos(Math::Vector &pos) +{ + float dim; + +#if _TEEN + dim = (m_mosaic*m_brick*m_size)/2.0f*0.98f; +#else + dim = (m_mosaic*m_brick*m_size)/2.0f*0.92f; +#endif + + if ( pos.x < -dim ) pos.x = -dim; + if ( pos.x > dim ) pos.x = dim; + if ( pos.z < -dim ) pos.z = -dim; + if ( pos.z > dim ) pos.z = dim; +} + + +// Adjust the edges of each mosaic to be compatible with all lower resolutions. + +void CTerrain::AdjustRelief() +{ + int x, y, xx, yy, ii, b; + float level1, level2; + + if ( m_depth == 1 ) return; + + ii = m_mosaic*m_brick+1; + b = 1<<(m_depth-1); + + for ( y=0 ; y= 0 && x <= m_mosaic*m_brick && + y >= 0 && y <= m_mosaic*m_brick ) + { + p.y = m_relief[x+y*(m_mosaic*m_brick+1)]; + } + else + { + p.y = 0.0f; + } + + return p; +} + +// Calculates a vertex of the terrain. +// Calculates a normal soft, taking into account the six adjacent triangles: +// +// ^ y +// | +// b---c---+ +// |\ |\ | +// | \| \| +// a---o---d +// |\ |\ | +// | \| \| +// +---f---e--> x + +D3DVERTEX2 CTerrain::RetVertex(int x, int y, int step) +{ + D3DVERTEX2 v; + Math::Vector o, oo, a,b,c,d,e,f, n, s; + int brick; + + o = RetVector(x, y); + v.x = o.x; + v.y = o.y; + v.z = o.z; + + a = RetVector(x-step, y ); + b = RetVector(x-step, y+step); + c = RetVector(x, y+step); + d = RetVector(x+step, y ); + e = RetVector(x+step, y-step); + f = RetVector(x, y-step); + + s = Math::Vector(0.0f, 0.0f, 0.0f); + + if ( x-step >= 0 && y+step <= m_mosaic*m_brick+1 ) + { + s += Math::NormalToPlane(b,a,o); + s += Math::NormalToPlane(c,b,o); + } + + if ( x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1 ) + { + s += Math::NormalToPlane(d,c,o); + } + + if ( x+step <= m_mosaic*m_brick+1 && y-step >= 0 ) + { + s += Math::NormalToPlane(e,d,o); + s += Math::NormalToPlane(f,e,o); + } + + if ( x-step >= 0 && y-step >= 0 ) + { + s += Math::NormalToPlane(a,f,o); + } + + s = Normalize(s); + v.nx = s.x; + v.ny = s.y; + v.nz = s.z; + + if ( m_bMultiText ) + { + brick = m_brick/m_subdivMapping; + oo = RetVector((x/brick)*brick, (y/brick)*brick); + o = RetVector(x, y); + v.tu = (o.x-oo.x)*m_scaleMapping*m_subdivMapping; + v.tv = 1.0f - (o.z-oo.z)*m_scaleMapping*m_subdivMapping; + } + else + { + v.tu = o.x*m_scaleMapping; + v.tv = o.z*m_scaleMapping; + } + + return v; +} + +// Creates all objects of a mosaic. +// The origin of mosaic is his center. +// +// ^ z +// | +// | 2---4---6-- +// | |\ |\ |\ +// | | \| \| +// | 1---3---5--- ... +// | +// +-------------------> x + +bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, + const D3DMATERIAL7 &mat, + float min, float max) +{ + Math::Matrix transform; + D3DVERTEX2 o, p1, p2; + D3DObjLevel6* buffer; + Math::Point uv; + int brick, total, size, mx, my, x, y, xx, yy, i; + char texName1[20]; + char texName2[20]; + float pixel, dp; + + if ( step == 1 && m_engine->RetGroundSpot() ) + { + i = (ox/5) + (oy/5)*(m_mosaic/5); + sprintf(texName2, "shadow%.2d.tga", i); + } + else + { + texName2[0] = 0; + } + + brick = m_brick/m_subdivMapping; + + o = RetVertex(ox*m_brick+m_brick/2, oy*m_brick+m_brick/2, step); + total = ((brick/step)+1)*2; + size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1); + + pixel = 1.0f/256.0f; // 1 pixel cover (*) +//? dp = 0.5f/512.0f; + dp = 1.0f/512.0f; + + for ( my=0 ; mytotalPossible = total; + buffer->totalUsed = total; + buffer->type = D3DTYPE6S; + buffer->material = mat; + if ( m_bMultiText ) + { +//? buffer->state = D3DSTATENORMAL; + buffer->state = D3DSTATEWRAP; + } + else + { + buffer->state = D3DSTATEWRAP; + } + buffer->state |= D3DSTATESECOND; + if ( step == 1 ) + { + buffer->state |= D3DSTATEDUALb; + } + i = 0; + for ( x=0 ; x<=brick ; x+=step ) + { + p1 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+0 , step); + p2 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+step, step); + p1.x -= o.x; p1.z -= o.z; + p2.x -= o.x; p2.z -= o.z; + + if ( m_bMultiText ) + { + if ( x == 0 ) + { + p1.tu = 0.0f+(0.5f/256.0f); + p2.tu = 0.0f+(0.5f/256.0f); + } + if ( x == brick ) + { + p1.tu = 1.0f-(0.5f/256.0f); + p2.tu = 1.0f-(0.5f/256.0f); + } + if ( y == 0 ) + { + p1.tv = 1.0f-(0.5f/256.0f); + } + if ( y == brick-step ) + { + p2.tv = 0.0f+(0.5f/256.0f); + } + } + + if ( m_bLevelText ) + { + p1.tu /= m_subdivMapping; // 0..1 -> 0..0.25 + p1.tv /= m_subdivMapping; + p2.tu /= m_subdivMapping; + p2.tv /= m_subdivMapping; + + if ( x == 0 ) + { + p1.tu = 0.0f+dp; + p2.tu = 0.0f+dp; + } + if ( x == brick ) + { + p1.tu = (1.0f/m_subdivMapping)-dp; + p2.tu = (1.0f/m_subdivMapping)-dp; + } + if ( y == 0 ) + { + p1.tv = (1.0f/m_subdivMapping)-dp; + } + if ( y == brick-step ) + { + p2.tv = 0.0f+dp; + } + + p1.tu += uv.x; + p1.tv += uv.y; + p2.tu += uv.x; + p2.tv += uv.y; + } + +#if 1 + xx = mx*(m_brick/m_subdivMapping) + x; + yy = my*(m_brick/m_subdivMapping) + y; + p1.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5); + p1.tv2 = ((float)(oy%5)*m_brick+yy+0.0f)/(m_brick*5); + p2.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5); + p2.tv2 = ((float)(oy%5)*m_brick+yy+1.0f)/(m_brick*5); + + // Correction for 1 pixel cover (*). + p1.tu2 = (p1.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel); + p1.tv2 = (p1.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel); + p2.tu2 = (p2.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel); + p2.tv2 = (p2.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel); +#endif + + buffer->vertex[i++] = p1; + buffer->vertex[i++] = p2; + } + m_engine->AddQuick(objRank, buffer, texName1, texName2, min, max, true); + } + } + } + + transform.LoadIdentity(); + transform.Set(1, 4, o.x); + transform.Set(3, 4, o.z); + m_engine->SetObjectTransform(objRank, transform); + + return true; +} + +// (*) There is 1 pixel cover around each of the 16 surfaces: +// +// |<--------------256-------------->| +// | |<----------254---------->| | +// |---|---|---|-- ... --|---|---|---| +// | 0.0 1.0 | +// | | | | +// 0.0 min max 1.0 +// +// The uv coordinates used for texturing are between min and max (instead of 0 and 1). +// This allows to exclude the pixels situated in a margin of a pixel around the surface. + + +// Seeks a materials based on theirs identifier. + +TerrainMaterial* CTerrain::LevelSearchMat(int id) +{ + int i; + + for ( i=0 ; itexName); + strcpy(name, tm->texName); + uv.x = tm->u; + uv.y = tm->v; + } +} + +// Returns the height of the terrain. + +float CTerrain::LevelRetHeight(int x, int y) +{ + int size; + + size = (m_mosaic*m_brick+1); + + if ( x < 0 ) x = 0; + if ( x >= size ) x = size-1; + if ( y < 0 ) y = 0; + if ( y >= size ) y = size-1; + + return m_relief[x+y*size]; +} + +// Decide whether a point is using the materials. + +bool CTerrain::LevelGetDot(int x, int y, float min, float max, float slope) +{ + float hc, h[4]; + int i; + + hc = LevelRetHeight(x, y); + h[0] = LevelRetHeight(x+0, y+1); + h[1] = LevelRetHeight(x+1, y+0); + h[2] = LevelRetHeight(x+0, y-1); + h[3] = LevelRetHeight(x-1, y+0); + + if ( hc < min || + hc > max ) return false; + + if ( slope == 0.0f ) + { + return true; + } + + if ( slope > 0.0f ) + { + for ( i=0 ; i<4 ; i++ ) + { + if ( fabs(hc-h[i]) >= slope ) + { + return false; + } + } + return true; + } + + if ( slope < 0.0f ) + { + for ( i=0 ; i<4 ; i++ ) + { + if ( fabs(hc-h[i]) < -slope ) + { + return false; + } + } + return true; + } + + return false; +} + +// Seeks if material exists. +// Returns the index within m_levelMat or -1 if there is not. +// m_levelMat[i].id gives the identifier. + +int CTerrain::LevelTestMat(char *mat) +{ + int i; + + for ( i=0 ; imat[0] != mat[0] || + tm->mat[1] != mat[1] || + tm->mat[2] != mat[2] || + tm->mat[3] != mat[3] ) // id incompatible with mat? + { + ii = LevelTestMat(mat); + if ( ii == -1 ) return; + id = m_levelMat[ii].id; // looking for a id compatible with mat + } + + // Changes the point. + m_levelDot[x+y*m_levelDotSize].id = id; + m_levelDot[x+y*m_levelDotSize].mat[0] = mat[0]; + m_levelDot[x+y*m_levelDotSize].mat[1] = mat[1]; + m_levelDot[x+y*m_levelDotSize].mat[2] = mat[2]; + m_levelDot[x+y*m_levelDotSize].mat[3] = mat[3]; + + // Changes the lower neighbor. + if ( (x+0) >= 0 && (x+0) < m_levelDotSize && + (y-1) >= 0 && (y-1) < m_levelDotSize ) + { + i = (x+0)+(y-1)*m_levelDotSize; + if ( m_levelDot[i].mat[0] != mat[2] ) + { + m_levelDot[i].mat[0] = mat[2]; + ii = LevelTestMat(m_levelDot[i].mat); + if ( ii != -1 ) + { + m_levelDot[i].id = m_levelMat[ii].id; + } + } + } + + // Modifies the left neighbor. + if ( (x-1) >= 0 && (x-1) < m_levelDotSize && + (y+0) >= 0 && (y+0) < m_levelDotSize ) + { + i = (x-1)+(y+0)*m_levelDotSize; + if ( m_levelDot[i].mat[1] != mat[3] ) + { + m_levelDot[i].mat[1] = mat[3]; + ii = LevelTestMat(m_levelDot[i].mat); + if ( ii != -1 ) + { + m_levelDot[i].id = m_levelMat[ii].id; + } + } + } + + // Changes the upper neighbor. + if ( (x+0) >= 0 && (x+0) < m_levelDotSize && + (y+1) >= 0 && (y+1) < m_levelDotSize ) + { + i = (x+0)+(y+1)*m_levelDotSize; + if ( m_levelDot[i].mat[2] != mat[0] ) + { + m_levelDot[i].mat[2] = mat[0]; + ii = LevelTestMat(m_levelDot[i].mat); + if ( ii != -1 ) + { + m_levelDot[i].id = m_levelMat[ii].id; + } + } + } + + // Changes the right neighbor. + if ( (x+1) >= 0 && (x+1) < m_levelDotSize && + (y+0) >= 0 && (y+0) < m_levelDotSize ) + { + i = (x+1)+(y+0)*m_levelDotSize; + if ( m_levelDot[i].mat[3] != mat[1] ) + { + m_levelDot[i].mat[3] = mat[1]; + ii = LevelTestMat(m_levelDot[i].mat); + if ( ii != -1 ) + { + m_levelDot[i].id = m_levelMat[ii].id; + } + } + } +} + +// Tests if a material can give a place, according to its four neighbors. +// If yes, puts the point. + +bool CTerrain::LevelIfDot(int x, int y, int id, char *mat) +{ + char test[4]; + + // Compatible with lower neighbor? + if ( x+0 >= 0 && x+0 < m_levelDotSize && + y-1 >= 0 && y-1 < m_levelDotSize ) + { + test[0] = mat[2]; + test[1] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[1]; + test[2] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[2]; + test[3] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[3]; + + if ( LevelTestMat(test) == -1 ) return false; + } + + // Compatible with left neighbor? + if ( x-1 >= 0 && x-1 < m_levelDotSize && + y+0 >= 0 && y+0 < m_levelDotSize ) + { + test[0] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[0]; + test[1] = mat[3]; + test[2] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[2]; + test[3] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[3]; + + if ( LevelTestMat(test) == -1 ) return false; + } + + // Compatible with upper neighbor? + if ( x+0 >= 0 && x+0 < m_levelDotSize && + y+1 >= 0 && y+1 < m_levelDotSize ) + { + test[0] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[0]; + test[1] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[1]; + test[2] = mat[0]; + test[3] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[3]; + + if ( LevelTestMat(test) == -1 ) return false; + } + + // Compatible with right neighbor? + if ( x+1 >= 0 && x+1 < m_levelDotSize && + y+0 >= 0 && y+0 < m_levelDotSize ) + { + test[0] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[0]; + test[1] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[1]; + test[2] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[2]; + test[3] = mat[1]; + + if ( LevelTestMat(test) == -1 ) return false; + } + + LevelSetDot(x, y, id, mat); // puts the point + return true; +} + +// Modifies the state of a point. + +bool CTerrain::LevelPutDot(int x, int y, int id) +{ + TerrainMaterial *tm; + char mat[4]; + int up, right, down, left; + + x /= m_brick/m_subdivMapping; + y /= m_brick/m_subdivMapping; + + if ( x < 0 || x >= m_levelDotSize || + y < 0 || y >= m_levelDotSize ) return false; + + tm = LevelSearchMat(id); + if ( tm == 0 ) return false; + + // Tries without changing neighbors. + if ( LevelIfDot(x, y, id, tm->mat) ) return true; + + // Tries changing a single neighbor (4x). + for ( up=0 ; upmat[1]; + mat[2] = tm->mat[2]; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + + for ( right=0 ; rightmat[0]; + mat[1] = right; + mat[2] = tm->mat[2]; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + + for ( down=0 ; downmat[0]; + mat[1] = tm->mat[1]; + mat[2] = down; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + + for ( left=0 ; leftmat[0]; + mat[1] = tm->mat[1]; + mat[2] = tm->mat[2]; + mat[3] = left; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + + // Tries changing two neighbors (6x). + for ( up=0 ; upmat[1]; + mat[2] = down; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + for ( right=0 ; rightmat[0]; + mat[1] = right; + mat[2] = tm->mat[2]; + mat[3] = left; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + for ( up=0 ; upmat[2]; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + for ( right=0 ; rightmat[0]; + mat[1] = right; + mat[2] = down; + mat[3] = tm->mat[3]; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + for ( down=0 ; downmat[0]; + mat[1] = tm->mat[1]; + mat[2] = down; + mat[3] = left; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + for ( up=0 ; upmat[1]; + mat[2] = tm->mat[2]; + mat[3] = left; + + if ( LevelIfDot(x, y, id, mat) ) return true; + } + } + + // Tries changing all the neighbors. + for ( up=0 ; upmat[j]; + } + } + + return true; +} + +// Generates a level in the terrain. + +bool CTerrain::LevelGenerate(int *id, float min, float max, + float slope, float freq, + Math::Vector center, float radius) +{ + TerrainMaterial *tm; + Math::Vector pos; + int i, numID, x, y, xx, yy, group, rnd; + float dim; + + static char random[100] = + { + 84,25,12, 6,34,52,85,38,97,16, + 21,31,65,19,62,40,72,22,48,61, + 56,47, 8,53,73,77, 4,91,26,88, + 76, 1,44,93,39,11,71,17,98,95, + 88,83,18,30, 3,57,28,49,74, 9, + 32,13,96,66,15,70,36,10,59,94, + 45,86, 2,29,63,42,51, 0,79,27, + 54, 7,20,69,89,23,64,43,81,92, + 90,33,46,14,67,35,50, 5,87,60, + 68,55,24,78,41,75,58,80,37,82, + }; + + i = 0; + while ( id[i] != 0 ) + { + tm = LevelSearchMat(id[i++]); + if ( tm == 0 ) return false; + } + numID = i; + + group = m_brick/m_subdivMapping; + + if ( radius > 0.0f && radius < 5.0f ) // just a square? + { + dim = (m_mosaic*m_brick*m_size)/2.0f; + + xx = (int)((center.x+dim)/m_size); + yy = (int)((center.z+dim)/m_size); + + x = xx/group; + y = yy/group; + + tm = LevelSearchMat(id[0]); + if ( tm != 0 ) + { + LevelSetDot(x, y, id[0], tm->mat); // puts the point + } +//? LevelPutDot(xx,yy, id[0]); + } + else + { + for ( y=0 ; y radius ) continue; + } + + if ( freq < 100.0f ) + { + rnd = random[(x%10)+(y%10)*10]; + if ( (float)rnd > freq ) continue; + } + + xx = x*group + group/2; + yy = y*group + group/2; + + if ( LevelGetDot(xx,yy, min, max, slope) ) + { + rnd = random[(x%10)+(y%10)*10]; + i = rnd%numID; + LevelPutDot(xx,yy, id[i]); + } + } + } + } + + return true; +} + +// Initializes an table with empty levels. + +void CTerrain::LevelOpenTable() +{ + int i, j; + + if ( !m_bLevelText ) return; + if ( m_levelDot != 0 ) return; // already allocated + + m_levelDotSize = (m_mosaic*m_brick)/(m_brick/m_subdivMapping)+1; + m_levelDot = (DotLevel*)malloc(m_levelDotSize*m_levelDotSize*sizeof(DotLevel)); + + for ( i=0 ; iCreateObject(); + m_engine->SetObjectType(objRank, TYPETERRAIN); // it is a terrain + + m_objRank[x+y*m_mosaic] = objRank; + + if ( bMultiRes ) + { + min = 0.0f; + max = m_vision; + max *= m_engine->RetClippingDistance(); + for ( step=0 ; step tp2.x ) + { + x = tp1.x; + tp1.x = tp2.x; + tp2.x = x; + } + + if ( tp1.y > tp2.y ) + { + y = tp1.y; + tp1.y = tp2.y; + tp2.y = y; + } + + size = (m_mosaic*m_brick)+1; + + // Calculates the current average height. + avg = 0.0f; + nb = 0; + for ( y=tp1.y ; y<=tp2.y ; y++ ) + { + for ( x=tp1.x ; x<=tp2.x ; x++ ) + { + avg += m_relief[x+y*size]; + nb ++; + } + } + avg /= (float)nb; + + // Changes the description of the relief. + for ( y=tp1.y ; y<=tp2.y ; y++ ) + { + for ( x=tp1.x ; x<=tp2.x ; x++ ) + { + m_relief[x+y*size] = avg+height; + + if ( x%m_brick == 0 && y%m_depth != 0 ) + { + m_relief[(x+0)+(y-1)*size] = avg+height; + m_relief[(x+0)+(y+1)*size] = avg+height; + } + + if ( y%m_brick == 0 && x%m_depth != 0 ) + { + m_relief[(x-1)+(y+0)*size] = avg+height; + m_relief[(x+1)+(y+0)*size] = avg+height; + } + } + } + AdjustRelief(); + + pp1.x = (tp1.x-2)/m_brick; + pp1.y = (tp1.y-2)/m_brick; + pp2.x = (tp2.x+1)/m_brick; + pp2.y = (tp2.y+1)/m_brick; + + if ( pp1.x < 0 ) pp1.x = 0; + if ( pp1.x >= m_mosaic ) pp1.x = m_mosaic-1; + if ( pp1.y < 0 ) pp1.y = 0; + if ( pp1.y >= m_mosaic ) pp1.y = m_mosaic-1; + + for ( y=pp1.y ; y<=pp2.y ; y++ ) + { + for ( x=pp1.x ; x<=pp2.x ; x++ ) + { + m_engine->DeleteObject(m_objRank[x+y*m_mosaic]); + CreateSquare(m_bMultiText, x, y); // recreates the square + } + } + m_engine->Update(); + + return true; +} + + +// Management of the wind. + +void CTerrain::SetWind(Math::Vector speed) +{ + m_wind = speed; +} + +Math::Vector CTerrain::RetWind() +{ + return m_wind; +} + + +// Gives the exact slope of the terrain of a place given. + +float CTerrain::RetFineSlope(const Math::Vector &pos) +{ + Math::Vector n; + + if ( !GetNormal(n, pos) ) return 0.0f; + return fabs(Math::RotateAngle(Math::Point(n.x, n.z).Length(), n.y)-Math::PI/2.0f); +} + +// Gives the approximate slope of the terrain of a specific location. + +float CTerrain::RetCoarseSlope(const Math::Vector &pos) +{ + float dim, level[4], min, max; + int x, y; + + if ( m_relief == 0 ) return 0.0f; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((pos.x+dim)/m_size); + y = (int)((pos.z+dim)/m_size); + + if ( x < 0 || x >= m_mosaic*m_brick || + y < 0 || y >= m_mosaic*m_brick ) return 0.0f; + + level[0] = m_relief[(x+0)+(y+0)*(m_mosaic*m_brick+1)]; + level[1] = m_relief[(x+1)+(y+0)*(m_mosaic*m_brick+1)]; + level[2] = m_relief[(x+0)+(y+1)*(m_mosaic*m_brick+1)]; + level[3] = m_relief[(x+1)+(y+1)*(m_mosaic*m_brick+1)]; + + min = Math::Min(level[0], level[1], level[2], level[3]); + max = Math::Max(level[0], level[1], level[2], level[3]); + + return atanf((max-min)/m_size); +} + +// Gives the normal vector at the position p (x,-,z) of the ground. + +bool CTerrain::GetNormal(Math::Vector &n, const Math::Vector &p) +{ + Math::Vector p1, p2, p3, p4; + float dim; + int x, y; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((p.x+dim)/m_size); + y = (int)((p.z+dim)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return false; + + p1 = RetVector(x+0, y+0); + p2 = RetVector(x+1, y+0); + p3 = RetVector(x+0, y+1); + p4 = RetVector(x+1, y+1); + + if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + { + n = Math::NormalToPlane(p1,p2,p3); + } + else + { + n = Math::NormalToPlane(p2,p4,p3); + } + return true; +} + +// Returns the height of the ground. + +float CTerrain::RetFloorLevel(const Math::Vector &p, bool bBrut, bool bWater) +{ + Math::Vector p1, p2, p3, p4, ps; + float dim, level; + int x, y; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((p.x+dim)/m_size); + y = (int)((p.z+dim)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return false; + + p1 = RetVector(x+0, y+0); + p2 = RetVector(x+1, y+0); + p3 = RetVector(x+0, y+1); + p4 = RetVector(x+1, y+1); + + ps = p; + if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + { + if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; + } + else + { + if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f; + } + + if ( !bBrut ) AdjustBuildingLevel(ps); + + if ( bWater ) // not going underwater? + { + level = m_water->RetLevel(); + if ( ps.y < level ) ps.y = level; // not under water + } + + return ps.y; +} + +// Returns the height to the ground. +// This height is positive when you are above the ground. + +float CTerrain::RetFloorHeight(const Math::Vector &p, bool bBrut, bool bWater) +{ + Math::Vector p1, p2, p3, p4, ps; + float dim, level; + int x, y; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((p.x+dim)/m_size); + y = (int)((p.z+dim)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return false; + + p1 = RetVector(x+0, y+0); + p2 = RetVector(x+1, y+0); + p3 = RetVector(x+0, y+1); + p4 = RetVector(x+1, y+1); + + ps = p; + if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + { + if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; + } + else + { + if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f; + } + + if ( !bBrut ) AdjustBuildingLevel(ps); + + if ( bWater ) // not going underwater? + { + level = m_water->RetLevel(); + if ( ps.y < level ) ps.y = level; // not under water + } + + return p.y-ps.y; +} + +// Modifies the coordinate "y" of point "p" to rest on the ground floor. + +bool CTerrain::MoveOnFloor(Math::Vector &p, bool bBrut, bool bWater) +{ + Math::Vector p1, p2, p3, p4; + float dim, level; + int x, y; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((p.x+dim)/m_size); + y = (int)((p.z+dim)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return false; + + p1 = RetVector(x+0, y+0); + p2 = RetVector(x+1, y+0); + p3 = RetVector(x+0, y+1); + p4 = RetVector(x+1, y+1); + + if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + { + if ( !IntersectY(p1, p2, p3, p) ) return false; + } + else + { + if ( !IntersectY(p2, p4, p3, p) ) return false; + } + + if ( !bBrut ) AdjustBuildingLevel(p); + + if ( bWater ) // not going underwater? + { + level = m_water->RetLevel(); + if ( p.y < level ) p.y = level; // not under water + } + + return true; +} + +// Modifies a coordinate so that it is on the ground. +// Returns false if the initial coordinate was too far. + +bool CTerrain::ValidPosition(Math::Vector &p, float marging) +{ + bool bOK = true; + float limit; + + limit = m_mosaic*m_brick*m_size/2.0f - marging; + + if ( p.x < -limit ) + { + p.x = -limit; + bOK = false; + } + + if ( p.z < -limit ) + { + p.z = -limit; + bOK = false; + } + + if ( p.x > limit ) + { + p.x = limit; + bOK = false; + } + + if ( p.z > limit ) + { + p.z = limit; + bOK = false; + } + + return bOK; +} + + + +// Empty the table of elevations. + +void CTerrain::FlushBuildingLevel() +{ + m_buildingUsed = 0; +} + +// Adds a new elevation for a building. + +bool CTerrain::AddBuildingLevel(Math::Vector center, float min, float max, + float height, float factor) +{ + int i; + + for ( i=0 ; i= MAXBUILDINGLEVEL ) return false; + i = m_buildingUsed++; + + update: + m_buildingTable[i].center = center; + m_buildingTable[i].min = min; + m_buildingTable[i].max = max; + m_buildingTable[i].level = RetFloorLevel(center, true); + m_buildingTable[i].height = height; + m_buildingTable[i].factor = factor; + m_buildingTable[i].bboxMinX = center.x-max; + m_buildingTable[i].bboxMaxX = center.x+max; + m_buildingTable[i].bboxMinZ = center.z-max; + m_buildingTable[i].bboxMaxZ = center.z+max; + + return true; +} + +// Updates the elevation for a building when it was moved up (after a terraforming). + +bool CTerrain::UpdateBuildingLevel(Math::Vector center) +{ + int i; + + for ( i=0 ; i m_buildingTable[i].bboxMaxX || + p.z < m_buildingTable[i].bboxMinZ || + p.z > m_buildingTable[i].bboxMaxZ ) continue; + + dist = Math::DistanceProjected(p, m_buildingTable[i].center); + + if ( dist <= m_buildingTable[i].max ) + { + return m_buildingTable[i].factor; + } + } + return 1.0f; // it is normal on the ground +} + +// Adjusts a position according to a possible rise. + +void CTerrain::AdjustBuildingLevel(Math::Vector &p) +{ + Math::Vector border; + float dist, base; + int i; + + for ( i=0 ; i m_buildingTable[i].bboxMaxX || + p.z < m_buildingTable[i].bboxMinZ || + p.z > m_buildingTable[i].bboxMaxZ ) continue; + + dist = Math::DistanceProjected(p, m_buildingTable[i].center); + + if ( dist > m_buildingTable[i].max ) continue; + + if ( dist < m_buildingTable[i].min ) + { + p.y = m_buildingTable[i].level+m_buildingTable[i].height; + return; + } + +#if 0 + p.y = m_buildingTable[i].level; + p.y += (m_buildingTable[i].max-dist)/ + (m_buildingTable[i].max-m_buildingTable[i].min)* + m_buildingTable[i].height; + + base = RetFloorLevel(p, true); + if ( p.y < base ) p.y = base; +#else + border.x = ((p.x-m_buildingTable[i].center.x)*m_buildingTable[i].max)/ + dist+m_buildingTable[i].center.x; + border.z = ((p.z-m_buildingTable[i].center.z)*m_buildingTable[i].max)/ + dist+m_buildingTable[i].center.z; + + base = RetFloorLevel(border, true); + + p.y = (m_buildingTable[i].max-dist)/ + (m_buildingTable[i].max-m_buildingTable[i].min)* + (m_buildingTable[i].level+m_buildingTable[i].height-base)+ + base; +#endif + return; + } +} + + +// Returns the hardness of the ground in a given place. +// The hardness determines the noise (SOUND_STEP and SOUND_BOUM). + +float CTerrain::RetHardness(const Math::Vector &p) +{ + TerrainMaterial* tm; + float factor, dim; + int x, y, id; + + factor = RetBuildingFactor(p); + if ( factor != 1.0f ) return 1.0f; // on building + + if ( m_levelDot == 0 ) return m_defHardness; + + dim = (m_mosaic*m_brick*m_size)/2.0f; + + x = (int)((p.x+dim)/m_size); + y = (int)((p.z+dim)/m_size); + + if ( x < 0 || x > m_mosaic*m_brick || + y < 0 || y > m_mosaic*m_brick ) return m_defHardness; + + x /= m_brick/m_subdivMapping; + y /= m_brick/m_subdivMapping; + + if ( x < 0 || x >= m_levelDotSize || + y < 0 || y >= m_levelDotSize ) return m_defHardness; + + id = m_levelDot[x+y*m_levelDotSize].id; + tm = LevelSearchMat(id); + if ( tm == 0 ) return m_defHardness; + + return tm->hardness; +} + + +// Shows the flat areas on the ground. + +void CTerrain::GroundFlat(Math::Vector pos) +{ + Math::Vector p; + float rapport, angle; + int x, y, i; + static char table[41*41]; + + + rapport = 3200.0f/1024.0f; + + for ( y=0 ; y<=40 ; y++ ) + { + for ( x=0 ; x<=40 ; x++ ) + { + i = x + y*41; + table[i] = 0; + + p.x = (x-20)*rapport; + p.z = (y-20)*rapport; + p.y = 0.0f; + if ( Math::Point(p.x, p.y).Length() > 20.0f*rapport ) continue; + + angle = RetFineSlope(pos+p); + + if ( angle < FLATLIMIT ) + { + table[i] = 1; + } + else + { + table[i] = 2; + } + } + } + + m_engine->GroundMarkCreate(pos, 40.0f, 0.001f, 15.0f, 0.001f, 41, 41, table); +} + + +// Calculates the radius of the largest flat area available. +// This calculation is not optimized! + +float CTerrain::RetFlatZoneRadius(Math::Vector center, float max) +{ + Math::Vector pos; + Math::Point c, p; + float ref, radius, angle, h; + int i, nb; + + angle = RetFineSlope(center); + if ( angle >= FLATLIMIT ) return 0.0f; + + ref = RetFloorLevel(center, true); + + radius = 1.0f; + while ( radius <= max ) + { + angle = 0.0f; + nb = (int)(2.0f*Math::PI*radius); + if ( nb < 8 ) nb = 8; + for ( i=0 ; i 1.0f ) return radius; + + angle += Math::PI*2.0f/8.0f; + } + radius += 1.0f; + } + return max; +} + + + +// Specifies the maximum height of flight. + +void CTerrain::SetFlyingMaxHeight(float height) +{ + m_flyingMaxHeight = height; +} + +// Returns the maximum height of flight. + +float CTerrain::RetFlyingMaxHeight() +{ + return m_flyingMaxHeight; +} + + +// Empty the limits table of flight. + +void CTerrain::FlushFlyingLimit() +{ + m_flyingMaxHeight = 280.0f; + m_flyingLimitTotal = 0; +} + +// Empty the limits table of flight. + +bool CTerrain::AddFlyingLimit(Math::Vector center, + float extRadius, float intRadius, + float maxHeight) +{ + int i; + + if ( m_flyingLimitTotal >= MAXFLYINGLIMIT ) return false; + + i = m_flyingLimitTotal; + m_flyingLimit[i].center = center; + m_flyingLimit[i].extRadius = extRadius; + m_flyingLimit[i].intRadius = intRadius; + m_flyingLimit[i].maxHeight = maxHeight; + m_flyingLimitTotal = i+1; + + return true; +} + +// Returns the maximum height of flight. + +float CTerrain::RetFlyingLimit(Math::Vector pos, bool bNoLimit) +{ + float dist, h; + int i; + + if ( bNoLimit ) return 280.0f; + if ( m_flyingLimitTotal == 0 ) return m_flyingMaxHeight; + + for ( i=0 ; i= m_flyingLimit[i].extRadius ) continue; + + if ( dist <= m_flyingLimit[i].intRadius ) + { + return m_flyingLimit[i].maxHeight; + } + + dist -= m_flyingLimit[i].intRadius; + + h = dist*(m_flyingMaxHeight-m_flyingLimit[i].maxHeight)/ + (m_flyingLimit[i].extRadius-m_flyingLimit[i].intRadius); + + return h + m_flyingLimit[i].maxHeight; + } + + return m_flyingMaxHeight; +} + diff --git a/src/old/terrain.h b/src/old/terrain.h index e2ca566..38e7287 100644 --- a/src/old/terrain.h +++ b/src/old/terrain.h @@ -1,209 +1,209 @@ -// * 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/. - -// terrain.h - -#pragma once - - -#include "common/struct.h" -#include "math/point.h" -#include "old/d3dengine.h" - - -class CInstanceManager; -class CD3DEngine; -class CWater; - - - -const float FLATLIMIT = (5.0f*Math::PI/180.0f); - - -enum TerrainRes -{ - TR_NULL = 0, - TR_STONE = 1, - TR_URANIUM = 2, - TR_POWER = 3, - TR_KEYa = 4, - TR_KEYb = 5, - TR_KEYc = 6, - TR_KEYd = 7, -}; - - -const int MAXBUILDINGLEVEL = 100; - -struct BuildingLevel -{ - Math::Vector center; - float factor; - float min; - float max; - float level; - float height; - float bboxMinX; - float bboxMaxX; - float bboxMinZ; - float bboxMaxZ; -}; - - -const int MAXMATTERRAIN = 100; - -struct TerrainMaterial -{ - short id; - char texName[20]; - float u,v; - float hardness; - char mat[4]; // up, right, down, left -}; - -struct DotLevel -{ - short id; - char mat[4]; // up, right, down, left -}; - - -const int MAXFLYINGLIMIT = 10; - -struct FlyingLimit -{ - Math::Vector center; - float extRadius; - float intRadius; - float maxHeight; -}; - - - -class CTerrain -{ -public: - CTerrain(CInstanceManager* iMan); - ~CTerrain(); - - bool Generate(int mosaic, int brickP2, float size, float vision, int depth, float hardness); - bool InitTextures(char* baseName, int* table, int dx, int dy); - void LevelFlush(); - bool LevelMaterial(int id, char* baseName, float u, float v, int up, int right, int down, int left, float hardness); - bool LevelInit(int id); - bool LevelGenerate(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius); - void FlushRelief(); - bool ReliefFromBMP(const char* filename, float scaleRelief, bool adjustBorder); - bool ReliefFromDXF(const char* filename, float scaleRelief); - bool ResFromBMP(const char* filename); - bool CreateObjects(bool bMultiRes); - bool Terraform(const Math::Vector &p1, const Math::Vector &p2, float height); - - void SetWind(Math::Vector speed); - Math::Vector RetWind(); - - float RetFineSlope(const Math::Vector &pos); - float RetCoarseSlope(const Math::Vector &pos); - bool GetNormal(Math::Vector &n, const Math::Vector &p); - float RetFloorLevel(const Math::Vector &p, bool bBrut=false, bool bWater=false); - float RetFloorHeight(const Math::Vector &p, bool bBrut=false, bool bWater=false); - bool MoveOnFloor(Math::Vector &p, bool bBrut=false, bool bWater=false); - bool ValidPosition(Math::Vector &p, float marging); - TerrainRes RetResource(const Math::Vector &p); - void LimitPos(Math::Vector &pos); - - void FlushBuildingLevel(); - bool AddBuildingLevel(Math::Vector center, float min, float max, float height, float factor); - bool UpdateBuildingLevel(Math::Vector center); - bool DeleteBuildingLevel(Math::Vector center); - float RetBuildingFactor(const Math::Vector &p); - float RetHardness(const Math::Vector &p); - - int RetMosaic(); - int RetBrick(); - float RetSize(); - float RetScaleRelief(); - - void GroundFlat(Math::Vector pos); - float RetFlatZoneRadius(Math::Vector center, float max); - - void SetFlyingMaxHeight(float height); - float RetFlyingMaxHeight(); - void FlushFlyingLimit(); - bool AddFlyingLimit(Math::Vector center, float extRadius, float intRadius, float maxHeight); - float RetFlyingLimit(Math::Vector pos, bool bNoLimit); - -protected: - bool ReliefAddDot(Math::Vector pos, float scaleRelief); - void AdjustRelief(); - Math::Vector RetVector(int x, int y); - D3DVERTEX2 RetVertex(int x, int y, int step); - bool CreateMosaic(int ox, int oy, int step, int objRank, const D3DMATERIAL7 &mat, float min, float max); - bool CreateSquare(bool bMultiRes, int x, int y); - - TerrainMaterial* LevelSearchMat(int id); - void LevelTextureName(int x, int y, char *name, Math::Point &uv); - float LevelRetHeight(int x, int y); - bool LevelGetDot(int x, int y, float min, float max, float slope); - int LevelTestMat(char *mat); - void LevelSetDot(int x, int y, int id, char *mat); - bool LevelIfDot(int x, int y, int id, char *mat); - bool LevelPutDot(int x, int y, int id); - void LevelOpenTable(); - void LevelCloseTable(); - - void AdjustBuildingLevel(Math::Vector &p); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - CWater* m_water; - - int m_mosaic; // number of mosaics - int m_brick; // number of bricks per mosaics - float m_size; // size of an item in an brick - float m_vision; // vision before a change of resolution - float* m_relief; // table of the relief - int* m_texture; // table of textures - int* m_objRank; // table of rows of objects - bool m_bMultiText; - bool m_bLevelText; - float m_scaleMapping; // scale of the mapping - float m_scaleRelief; - int m_subdivMapping; - int m_depth; // number of different resolutions (1,2,3,4) - char m_texBaseName[20]; - char m_texBaseExt[10]; - float m_defHardness; - - TerrainMaterial m_levelMat[MAXMATTERRAIN+1]; - int m_levelMatTotal; - int m_levelMatMax; - int m_levelDotSize; - DotLevel* m_levelDot; - int m_levelID; - - int m_buildingUsed; - BuildingLevel m_buildingTable[MAXBUILDINGLEVEL]; - - unsigned char* m_resources; - Math::Vector m_wind; // wind speed - - float m_flyingMaxHeight; - int m_flyingLimitTotal; - FlyingLimit m_flyingLimit[MAXFLYINGLIMIT]; -}; - +// * 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/. + +// terrain.h + +#pragma once + + +#include "common/struct.h" +#include "math/point.h" +#include "old/d3dengine.h" + + +class CInstanceManager; +class CD3DEngine; +class CWater; + + + +const float FLATLIMIT = (5.0f*Math::PI/180.0f); + + +enum TerrainRes +{ + TR_NULL = 0, + TR_STONE = 1, + TR_URANIUM = 2, + TR_POWER = 3, + TR_KEYa = 4, + TR_KEYb = 5, + TR_KEYc = 6, + TR_KEYd = 7, +}; + + +const int MAXBUILDINGLEVEL = 100; + +struct BuildingLevel +{ + Math::Vector center; + float factor; + float min; + float max; + float level; + float height; + float bboxMinX; + float bboxMaxX; + float bboxMinZ; + float bboxMaxZ; +}; + + +const int MAXMATTERRAIN = 100; + +struct TerrainMaterial +{ + short id; + char texName[20]; + float u,v; + float hardness; + char mat[4]; // up, right, down, left +}; + +struct DotLevel +{ + short id; + char mat[4]; // up, right, down, left +}; + + +const int MAXFLYINGLIMIT = 10; + +struct FlyingLimit +{ + Math::Vector center; + float extRadius; + float intRadius; + float maxHeight; +}; + + + +class CTerrain +{ +public: + CTerrain(CInstanceManager* iMan); + ~CTerrain(); + + bool Generate(int mosaic, int brickP2, float size, float vision, int depth, float hardness); + bool InitTextures(char* baseName, int* table, int dx, int dy); + void LevelFlush(); + bool LevelMaterial(int id, char* baseName, float u, float v, int up, int right, int down, int left, float hardness); + bool LevelInit(int id); + bool LevelGenerate(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius); + void FlushRelief(); + bool ReliefFromBMP(const char* filename, float scaleRelief, bool adjustBorder); + bool ReliefFromDXF(const char* filename, float scaleRelief); + bool ResFromBMP(const char* filename); + bool CreateObjects(bool bMultiRes); + bool Terraform(const Math::Vector &p1, const Math::Vector &p2, float height); + + void SetWind(Math::Vector speed); + Math::Vector RetWind(); + + float RetFineSlope(const Math::Vector &pos); + float RetCoarseSlope(const Math::Vector &pos); + bool GetNormal(Math::Vector &n, const Math::Vector &p); + float RetFloorLevel(const Math::Vector &p, bool bBrut=false, bool bWater=false); + float RetFloorHeight(const Math::Vector &p, bool bBrut=false, bool bWater=false); + bool MoveOnFloor(Math::Vector &p, bool bBrut=false, bool bWater=false); + bool ValidPosition(Math::Vector &p, float marging); + TerrainRes RetResource(const Math::Vector &p); + void LimitPos(Math::Vector &pos); + + void FlushBuildingLevel(); + bool AddBuildingLevel(Math::Vector center, float min, float max, float height, float factor); + bool UpdateBuildingLevel(Math::Vector center); + bool DeleteBuildingLevel(Math::Vector center); + float RetBuildingFactor(const Math::Vector &p); + float RetHardness(const Math::Vector &p); + + int RetMosaic(); + int RetBrick(); + float RetSize(); + float RetScaleRelief(); + + void GroundFlat(Math::Vector pos); + float RetFlatZoneRadius(Math::Vector center, float max); + + void SetFlyingMaxHeight(float height); + float RetFlyingMaxHeight(); + void FlushFlyingLimit(); + bool AddFlyingLimit(Math::Vector center, float extRadius, float intRadius, float maxHeight); + float RetFlyingLimit(Math::Vector pos, bool bNoLimit); + +protected: + bool ReliefAddDot(Math::Vector pos, float scaleRelief); + void AdjustRelief(); + Math::Vector RetVector(int x, int y); + D3DVERTEX2 RetVertex(int x, int y, int step); + bool CreateMosaic(int ox, int oy, int step, int objRank, const D3DMATERIAL7 &mat, float min, float max); + bool CreateSquare(bool bMultiRes, int x, int y); + + TerrainMaterial* LevelSearchMat(int id); + void LevelTextureName(int x, int y, char *name, Math::Point &uv); + float LevelRetHeight(int x, int y); + bool LevelGetDot(int x, int y, float min, float max, float slope); + int LevelTestMat(char *mat); + void LevelSetDot(int x, int y, int id, char *mat); + bool LevelIfDot(int x, int y, int id, char *mat); + bool LevelPutDot(int x, int y, int id); + void LevelOpenTable(); + void LevelCloseTable(); + + void AdjustBuildingLevel(Math::Vector &p); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + CWater* m_water; + + int m_mosaic; // number of mosaics + int m_brick; // number of bricks per mosaics + float m_size; // size of an item in an brick + float m_vision; // vision before a change of resolution + float* m_relief; // table of the relief + int* m_texture; // table of textures + int* m_objRank; // table of rows of objects + bool m_bMultiText; + bool m_bLevelText; + float m_scaleMapping; // scale of the mapping + float m_scaleRelief; + int m_subdivMapping; + int m_depth; // number of different resolutions (1,2,3,4) + char m_texBaseName[20]; + char m_texBaseExt[10]; + float m_defHardness; + + TerrainMaterial m_levelMat[MAXMATTERRAIN+1]; + int m_levelMatTotal; + int m_levelMatMax; + int m_levelDotSize; + DotLevel* m_levelDot; + int m_levelID; + + int m_buildingUsed; + BuildingLevel m_buildingTable[MAXBUILDINGLEVEL]; + + unsigned char* m_resources; + Math::Vector m_wind; // wind speed + + float m_flyingMaxHeight; + int m_flyingLimitTotal; + FlyingLimit m_flyingLimit[MAXFLYINGLIMIT]; +}; + diff --git a/src/old/text.cpp b/src/old/text.cpp index a7faa95..d174358 100644 --- a/src/old/text.cpp +++ b/src/old/text.cpp @@ -1,1879 +1,1879 @@ -// * 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/. - -// text.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "old/d3dengine.h" -#include "common/language.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/text.h" - - - -static short table_text_colobot[] = -{ -// x1, y1, x2, y2 - 219,34, 225,50, // 0 - 1,188, 9,203, // . - 51,188,59,203, // square - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 11,188,19,203, // \t - 21,188,29,203, // \n - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, // \r - 219,34, 225,50, - 219,34, 225,50, - 41,188,49,203, // > - 31,188,39,203, // < - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - -#if _NEWLOOK - 0, 0, 4, 16, // 32 - 7, 0, 9, 16, // ! - 9, 0, 13, 16, // " - 13, 0, 24, 16, // # - 24, 0, 31, 16, // $ - 31, 0, 43, 16, // % - 43, 0, 54, 16, // & - 54, 0, 56, 16, // ' - 56, 0, 61, 16, // ( - 61, 0, 67, 16, // ) - 67, 0, 73, 16, // * - 73, 0, 83, 16, // + - 83, 0, 87, 16, // , - 87, 0, 92, 16, // - - 92, 0, 94, 16, // . - 94, 0, 101,16, // / - 101,0, 109,16, // 0 - 109,0, 114,16, // 1 - 114,0, 122,16, // 2 - 122,0, 129,16, // 3 - 129,0, 138,16, // 4 - 138,0, 146,16, // 5 - 146,0, 154,16, // 6 - 154,0, 161,16, // 7 - 161,0, 169,16, // 8 - 169,0, 177,16, // 9 - 177,0, 179,16, // : - 179,0, 183,16, // ; - 183,0, 193,16, // < - 193,0, 203,16, // = - 203,0, 213,16, // > - 213,0, 219,16, // ? - - 0, 17, 14, 33, // @ 64 - 14, 17, 26, 33, // A - 26, 17, 33, 33, // B - 33, 17, 42, 33, // C - 42, 17, 51, 33, // D - 51, 17, 58, 33, // E - 58, 17, 63, 33, // F - 63, 17, 73, 33, // G - 73, 17, 82, 33, // H - 82, 17, 84, 33, // I - 84, 17, 90, 33, // J - 90, 17, 98, 33, // K - 98, 17, 103,33, // L - 103,17, 115,33, // M - 115,17, 124,33, // N - 124,17, 136,33, // O - 136,17, 142,33, // P - 142,17, 154,33, // Q - 154,17, 160,33, // R - 160,17, 167,33, // S - 167,17, 175,33, // T - 175,17, 183,33, // U - 183,17, 194,33, // V - 194,17, 208,33, // W - 208,17, 218,33, // X - 218,17, 227,33, // Y - 227,17, 236,33, // Z - 236,17, 241,33, // [ - 241,17, 248,33, // \ - 248,17, 252,33, // ] - 219,0, 229,16, // ^ - 0, 34, 9, 50, // _ - - 54, 0, 56, 16, // ` 96 - 9, 34, 16, 50, // a - 16, 34, 25, 50, // b - 25, 34, 33, 50, // c - 33, 34, 42, 50, // d - 42, 34, 50, 50, // e - 50, 34, 55, 50, // f - 55, 34, 62, 50, // g - 62, 34, 69, 50, // h - 69, 34, 71, 50, // i - 71, 34, 75, 50, // j - 75, 34, 81, 50, // k - 81, 34, 83, 50, // l - 83, 34, 93, 50, // m - 93, 34, 100,50, // n - 100,34, 109,50, // o - 109,34, 118,50, // p - 118,34, 127,50, // q - 127,34, 132,50, // r - 132,34, 138,50, // s - 138,34, 143,50, // t - 143,34, 150,50, // u - 150,34, 158,50, // v - 158,34, 171,50, // w - 171,34, 179,50, // x - 179,34, 187,50, // y - 187,34, 195,50, // z - 195,34, 201,50, // { - 201,34, 203,50, // | - 203,34, 209,50, // } - 209,34, 219,50, // ~ - 219,34, 228,50, // - - 219,34, 225,50, // 128 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 144 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 160 - 219,34, 225,50, // 161 A1 ! reverse - 219,34, 225,50, - 219,34, 225,50, // 163 A3 Ł - 219,34, 225,50, - 219,34, 225,50, - 0, 0, 4, 16, // 166 A6 ¦ (space) - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 176 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, // 191 BF ? reverse - - 12, 51, 24, 67, // 192 C0 ŕ big - 0, 51, 12, 67, // 193 C1 á big - 24, 51, 36, 67, // 194 C2 â big - 48, 51, 60, 67, // 195 C3 ă big - 36, 51, 48, 67, // 196 C4 ä big - 219,34, 225,50, - 219,34, 225,50, - 60, 51, 69, 67, // 199 C7 ç big - 77, 51, 84, 67, // 200 C8 č big - 70, 51, 77, 67, // 201 C9 é big - 85, 51, 92, 67, // 202 CA ę big - 93, 51, 100,67, // 203 CB ë big - 219,34, 225,50, - 100,51, 104,67, // 205 CD í big - 108,51, 113,67, // 206 CE î big - 113,51, 117,67, // 207 CF ď big - - 219,34, 225,50, // 208 - 117,51, 126,67, // 209 D1 ń big - 219,34, 225,50, - 126,51, 138,67, // 211 D3 ó big - 150,51, 162,67, // 212 D4 ô big - 219,34, 225,50, - 162,51, 174,67, // 214 D6 ö big - 219,34, 225,50, - 219,34, 225,50, - 194,51, 202,67, // 217 D9 ů big - 186,51, 194,67, // 218 DA ú big - 202,51, 210,67, // 219 DB ű big - 210,51, 218,67, // 220 DC ü big - 219,34, 225,50, - 219,34, 225,50, - 218,51, 227,67, // 223 DF German SS - - 7, 68, 14, 84, // 224 E0 ŕ small - 0, 68, 7, 84, // 225 E1 á small - 14, 68, 21, 84, // 226 E2 â small - 28, 68, 35, 84, // 227 E3 ă small - 21, 68, 28, 84, // 228 E4 ä small - 219,34, 225,50, - 219,34, 225,50, - 35, 68, 43, 84, // 231 E7 ç small - 51, 68, 59, 84, // 232 E8 č small - 43, 68, 51, 84, // 233 E9 é small - 59, 68, 67, 84, // 234 EA ę small - 67, 68, 75, 84, // 235 EB ë small - 219,34, 225,50, - 75, 68, 79, 84, // 237 ED í small - 83, 68, 88, 84, // 238 EE î small - 88, 68, 92, 84, // 239 EF ď small - - 219,34, 225,50, // 240 - 92, 68, 99, 84, // 241 F1 ń small - 219,34, 225,50, - 99, 68, 108,84, // 243 F3 ó small - 117,68, 126,84, // 244 F4 ô small - 219,34, 225,50, - 126,68, 135,84, // 246 F6 ö small - 219,34, 225,50, - 219,34, 225,50, - 151,68, 158,84, // 249 F9 ů small - 144,68, 151,84, // 250 FA ú small - 158,68, 165,84, // 251 FB ű small - 165,68, 172,84, // 252 FC ü small - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, -#else - 0, 0, 4, 16, // 32 - 4, 0, 7, 16, // ! - 7, 0, 13, 16, - 14, 0, 21, 16, - 22, 0, 28, 16, - 29, 0, 38, 16, - 39, 0, 48, 16, - 48, 0, 51, 16, - 51, 0, 55, 16, - 55, 0, 59, 16, - 59, 0, 65, 16, - 66, 0, 72, 16, - 73, 0, 76, 16, - 76, 0, 82, 16, - 82, 0, 85, 16, - 85, 0, 90, 16, - 90, 0, 97, 16, - 98, 0, 103,16, - 104,0, 111,16, - 111,0, 118,16, - 118,0, 125,16, - 125,0, 132,16, - 132,0, 139,16, - 139,0, 146,16, - 146,0, 153,16, - 153,0, 160,16, - 160,0, 165,16, // : - 164,0, 169,16, // ; - 169,0, 177,16, // < - 177,0, 185,16, // = - 185,0, 193,16, // > - 193,0, 201,16, // ? - - 201,0, 215,16, // 64 - 0, 17, 10, 33, // A - 10, 17, 18, 33, - 19, 17, 28, 33, - 28, 17, 36, 33, - 37, 17, 44, 33, - 45, 17, 52, 33, - 53, 17, 62, 33, - 63, 17, 71, 33, - 72, 17, 75, 33, - 75, 17, 82, 33, - 83, 17, 91, 33, - 92, 17, 99, 33, - 100,17, 110,33, - 111,17, 119,33, -//? 120,17, 129,33, // O - 216,0, 227,16, // O - 130,17, 138,33, - 139,17, 148,33, - 149,17, 158,33, - 158,17, 166,33, - 166,17, 175,33, - 175,17, 183,33, - 183,17, 193,33, - 193,17, 207,33, - 207,17, 215,33, - 215,17, 224,33, - 224,17, 232,33, // Z - 232,17, 236,33, - 236,17, 241,33, - 241,17, 245,33, - 245,17, 252,33, // ^ - 0, 34, 8, 50, // _ - - 45, 17, 52, 33, // 96 - 8, 34, 15, 50, // a - 16, 34, 23, 50, - 24, 34, 31, 50, - 31, 34, 38, 50, - 39, 34, 46, 50, - 46, 34, 52, 50, - 52, 34, 59, 50, - 60, 34, 67, 50, - 68, 34, 71, 50, - 71, 34, 76, 50, - 77, 34, 84, 50, - 84, 34, 87, 50, - 88, 34, 99, 50, - 100,34, 107,50, -//? 108,34, 115,50, // o - 238,0, 246,16, // o - 116,34, 123,50, - 124,34, 131,50, - 132,34, 137,50, - 137,34, 144,50, - 144,34, 149,50, - 149,34, 156,50, - 156,34, 164,50, - 164,34, 176,50, - 176,34, 183,50, - 183,34, 191,50, - 191,34, 197,50, // z - 197,34, 203,50, - 203,34, 205,50, - 205,34, 211,50, - 211,34, 219,50, - 219,34, 225,50, - -#if _POLISH - 219,34, 225,50, // 128 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 0, 51, 8, 67, // 140 S´ - 219,34, 225,50, - 219,34, 225,50, - 9, 51, 17, 67, // 143 Z´ - - 219,34, 225,50, // 144 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 0, 68, 7, 84, // 156 s´ - 219,34, 225,50, - 219,34, 225,50, - 8, 68, 14, 84, // 159 z´ - - 219,34, 225,50, // 160 - 219,34, 225,50, - 219,34, 225,50, - 18, 51, 27, 67, // 163 L/ - 219,34, 225,50, - 28, 51, 39, 67, // 165 A, - 0, 0, 4, 16, // 166 A6 ¦ (space) - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 40, 51, 48, 67, // 175 Zo - - 219,34, 225,50, // 176 - 219,34, 225,50, - 219,34, 225,50, - 16, 68, 21, 84, // 179 l/ - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 23, 68, 31, 84, // 185 a, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 32, 68, 38, 84, // 191 zo - - 219,34, 225,50, // 192 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 49, 51, 58, 67, // 198 C´ - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 59, 51, 66, 67, // 202 E, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 208 - 67, 51, 75, 67, // 209 N´ - 219,34, 225,50, -//? 76, 51, 85, 67, // 211 O´ - 86, 51, 97, 67, // 211 O´ - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 224 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 39, 68, 46, 84, // 230 c´ - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 47, 68, 54, 84, // 234 e, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 240 - 55, 68, 62, 84, // 241 n´ - 219,34, 225,50, -//? 63, 68, 70, 84, // 243 o´ - 71, 68, 79, 84, // 243 o´ - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, -#else - 219,34, 225,50, // 128 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 144 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 160 - 219,34, 225,50, // 161 A1 ! reverse - 219,34, 225,50, - 219,34, 225,50, // 163 A3 Ł - 219,34, 225,50, - 219,34, 225,50, - 0, 0, 4, 16, // 166 A6 ¦ (space) - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - - 219,34, 225,50, // 176 - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, // 191 BF ? reverse - - 10, 51, 20, 67, // 192 C0 ŕ big - 0, 51, 10, 67, // 193 C1 á big - 20, 51, 30, 67, // 194 C2 â big - 40, 51, 50, 67, // 195 C3 ă big - 30, 51, 40, 67, // 196 C4 ä big - 219,34, 225,50, - 219,34, 225,50, - 50, 51, 59, 67, // 199 C7 ç big - 67, 51, 74, 67, // 200 C8 č big - 59, 51, 66, 67, // 201 C9 é big - 75, 51, 82, 67, // 202 CA ę big - 83, 51, 90, 67, // 203 CB ë big - 219,34, 225,50, - 91, 51, 95, 67, // 205 CD í big - 100,51, 103,67, // 206 CE î big - 104,51, 109,67, // 207 CF ď big - - 219,34, 225,50, // 208 - 109,51, 117,67, // 209 D1 ń big - 219,34, 225,50, - 118,51, 127,67, // 211 D3 ó big - 138,51, 147,67, // 212 D4 ô big - 219,34, 225,50, - 148,51, 157,67, // 214 D6 ö big - 219,34, 225,50, - 219,34, 225,50, - 177,51, 185,67, // 217 D9 ů big - 168,51, 176,67, // 218 DA ú big - 186,51, 194,67, // 219 DB ű big - 195,51, 203,67, // 220 DC ü big - 219,34, 225,50, - 219,34, 225,50, - 211,51, 220,67, // 223 DF German SS - - 8, 68, 15, 84, // 224 E0 ŕ small - 0, 68, 7, 84, // 225 E1 á small - 16, 68, 23, 84, // 226 E2 â small - 32, 68, 39, 84, // 227 E3 ă small - 24, 68, 31, 84, // 228 E4 ä small - 219,34, 225,50, - 219,34, 225,50, - 40, 68, 47, 84, // 231 E7 ç small - 55, 68, 62, 84, // 232 E8 č small - 47, 68, 54, 84, // 233 E9 é small - 63, 68, 70, 84, // 234 EA ę small - 71, 68, 78, 84, // 235 EB ë small - 219,34, 225,50, - 79, 68, 83, 84, // 237 ED í small - 88, 68, 92, 84, // 238 EE î small - 92, 68, 97, 84, // 239 EF ď small - - 219,34, 225,50, // 240 - 97, 68, 104,84, // 241 F1 ń small - 219,34, 225,50, - 105,68, 112,84, // 243 F3 ó small - 121,68, 128,84, // 244 F4 ô small - 219,34, 225,50, - 129,68, 136,84, // 246 F6 ö small - 219,34, 225,50, - 219,34, 225,50, - 153,68, 160,84, // 249 F9 ů small - 145,68, 152,84, // 250 FA ú small - 161,68, 168,84, // 251 FB ű small - 169,68, 176,84, // 252 FC ü small - 219,34, 225,50, - 219,34, 225,50, - 219,34, 225,50, -#endif -#endif -}; - - -static short table_text_courier[] = -{ -// x1, y1, x2, y2 - 231,137,239,153, // 0 - 1,188, 9,204, // . - 51,188,59,204, // square - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 11,188,19,204, // \t - 21,188,29,204, // \n - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, // \r - 231,137,239,153, - 231,137,239,153, - 41,188,49,204, // > - 31,188,39,204, // < - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 1, 86, 9,102, // 32 - 11, 86, 19,102, - 21, 86, 29,102, - 31, 86, 39,102, - 41, 86, 49,102, - 51, 86, 59,102, - 61, 86, 69,102, - 71, 86, 79,102, - 81, 86, 89,102, - 91, 86, 99,102, - 101, 86,109,102, - 111, 86,119,102, - 121, 86,129,102, - 131, 86,139,102, - 141, 86,149,102, - 151, 86,159,102, - 161, 86,169,102, - 171, 86,179,102, - 181, 86,189,102, - 191, 86,199,102, - 201, 86,209,102, - 211, 86,219,102, - 221, 86,229,102, - 231, 86,239,102, - 1,103, 9,119, // 56 - 11,103, 19,119, - 21,103, 29,119, - 31,103, 39,119, - 41,103, 49,119, - 51,103, 59,119, - 61,103, 69,119, - 71,103, 79,119, - - 81,103, 89,119, // @ - 91,103, 99,119, - 101,103,109,119, - 111,103,119,119, - 121,103,129,119, - 131,103,139,119, - 141,103,149,119, - 151,103,159,119, - 161,103,169,119, - 171,103,179,119, - 181,103,189,119, - 191,103,199,119, - 201,103,209,119, - 211,103,219,119, - 221,103,229,119, - 231,103,239,119, - 1,120, 9,136, // P - 11,120, 19,136, - 21,120, 29,136, - 31,120, 39,136, - 41,120, 49,136, - 51,120, 59,136, - 61,120, 69,136, - 71,120, 79,136, - 81,120, 89,136, - 91,120, 99,136, - 101,120,109,136, - 111,120,119,136, // [ - 121,120,129,136, - 131,120,139,136, - 141,120,149,136, - 151,120,159,136, // _ - - 161,120,169,136, - 171,120,179,136, // a - 181,120,189,136, - 191,120,199,136, - 201,120,209,136, - 211,120,219,136, - 221,120,229,136, - 231,120,239,136, - 1,137, 9,153, - 11,137, 19,153, - 21,137, 29,153, - 31,137, 39,153, - 41,137, 49,153, - 51,137, 59,153, - 61,137, 69,153, - 71,137, 79,153, // o - 81,137, 89,153, - 91,137, 99,153, - 101,137,109,153, - 111,137,119,153, - 121,137,129,153, - 131,137,139,153, - 141,137,149,153, - 151,137,159,153, - 161,137,169,153, - 171,137,179,153, - 181,137,189,153, - 191,137,199,153, - 201,137,209,153, - 211,137,219,153, - 221,137,229,153, // ~ - 231,137,239,153, - -#if _POLISH - 231,137,239,153, // 128 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 1,154, 9,170, // 140 S´ - 231,137,239,153, - 231,137,239,153, - 11,154, 19,170, // 143 Z´ - - 231,137,239,153, // 144 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 1,171, 9,187, // 156 s´ - 231,137,239,153, - 231,137,239,153, - 11,171, 19,187, // 159 z´ - - 231,137,239,153, // 160 - 231,137,239,153, - 231,137,239,153, - 21,154, 29,170, // 163 L/ - 231,137,239,153, - 31,154, 39,170, // 165 A, - 1, 86, 9,102, // 166 A6 ¦ (space) - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 41,154, 49,170, // 175 Zo - - 231,137,239,153, // 176 - 231,137,239,153, - 231,137,239,153, - 21,171, 29,187, // 179 l/ - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 31,171, 39,187, // 185 a, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 41,171, 49,187, // 191 zo - - 231,137,239,153, // 192 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 51,154, 59,170, // 198 C´ - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 61,154, 69,170, // 202 E, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 208 - 71,154, 79,170, // 209 N´ - 231,137,239,153, - 81,171, 89,187, // 211 O´ - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 224 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 51,171, 59,187, // 230 c´ - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 61,171, 69,187, // 234 e, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 240 - 71,171, 79,187, // 241 n´ - 231,137,239,153, - 81,171, 89,187, // 243 ó small - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, -#else - 231,137,239,153, // 128 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 144 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 160 - 231,137,239,153, // 161 A1 ! reverse - 231,137,239,153, - 231,137,239,153, // 163 A3 Ł - 231,137,239,153, - 231,137,239,153, - 1, 86, 9,102, // 166 A6 ¦ (space) - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - - 231,137,239,153, // 176 - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, // 191 BF ? reverse - - 11,154, 19,170, // ŕ big - 1,154, 9,170, // á big - 21,154, 29,170, // â big - 41,154, 49,170, // ă big - 31,154, 39,170, // ä big - 231,137,239,153, - 231,137,239,153, - 51,154, 59,170, // ç big - 71,154, 79,170, // č big - 61,154, 69,170, // é big - 81,154, 89,170, // ę big - 91,154, 99,170, // ë big - 231,137,239,153, - 101,154,109,170, // í big - 121,154,129,170, // î big - 131,154,139,170, // ď big - 231,137,239,153, - 141,154,149,170, // ń big - 231,137,239,153, - 151,154,159,170, // ó big - 171,154,179,170, // ô big - 231,137,239,153, - 181,154,189,170, // ö big - 231,137,239,153, - 231,137,239,153, - 211,154,219,170, // ů big - 201,154,209,170, // ú big - 221,154,229,170, // ű big - 231,154,239,170, // ü big - 231,137,239,153, - 231,137,239,153, - 241,154,249,170, // 223 DF German SS - - 11,171, 19,187, // ŕ small - 1,171, 9,187, // á small - 21,171, 29,187, // â small - 41,171, 49,187, // ă small - 31,171, 39,187, // ä small - 231,137,239,153, - 231,137,239,153, - 51,171, 59,187, // ç small - 71,171, 79,187, // č small - 61,171, 69,187, // é small - 81,171, 89,187, // ę small - 91,171, 99,187, // ë small - 231,137,239,153, - 111,171,119,187, // ě small - 121,171,129,187, // î small - 131,171,139,187, // ď small - 231,137,239,153, - 141,171,149,187, // ń small - 231,137,239,153, - 151,171,159,187, // ó small - 171,171,179,187, // ô small - 231,137,239,153, - 181,171,189,187, // ö small - 231,137,239,153, - 231,137,239,153, - 211,171,219,187, // ů small - 201,171,209,187, // ú small - 221,171,229,187, // ű small - 231,171,239,187, // ü small - 231,137,239,153, - 231,137,239,153, - 231,137,239,153, -#endif -}; - - -// Returns the pointer to the table by the font. - -short* RetTable(FontType font) -{ - if ( font == FONT_COLOBOT ) return table_text_colobot; - else return table_text_courier; -} - - - -// Object's constructor. - -CText::CText(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_TEXT, this); - - m_pD3DDevice = 0; - m_engine = engine; -} - -// Object's destructor. - -CText::~CText() -{ - m_iMan->DeleteInstance(CLASS_TEXT, this); -} - - -void CText::SetD3DDevice(LPDIRECT3DDEVICE7 device) -{ - m_pD3DDevice = device; -} - - -// Displays multi-font text. -// The vertical position is at the bottom of the box of the character. - -void CText::DrawText(char *string, char *format, int len, Math::Point pos, - float width, int justif, float size, float stretch, - int eol) -{ - float sw; - - if ( justif == 0 ) // center? - { - sw = RetStringWidth(string, format, len, size, stretch); - if ( sw > width ) sw = width; - pos.x -= sw/2.0f; - } - if ( justif < 0 ) // flag was left? - { - sw = RetStringWidth(string, format, len, size, stretch); - if ( sw > width ) sw = width; - pos.x -= sw; - } - DrawString(string, format, len, pos, width, size, stretch, eol); -} - -// Displays multi-font text. -// The vertical position is at the bottom of the box of the character. - -void CText::DrawText(char *string, char *format, Math::Point pos, float width, - int justif, float size, float stretch, - int eol) -{ - DrawText(string, format, strlen(string), pos, width, justif, size, stretch, eol); -} - -// Displays text. -// The vertical position is at the bottom of the box of the character. - -void CText::DrawText(char *string, int len, Math::Point pos, float width, - int justif, float size, float stretch, FontType font, - int eol) -{ - float sw; - - if ( justif == 0 ) // center? - { - sw = RetStringWidth(string, len, size, stretch, font); - if ( sw > width ) sw = width; - pos.x -= sw/2.0f; - } - if ( justif < 0 ) // flag was left? - { - sw = RetStringWidth(string, len, size, stretch, font); - if ( sw > width ) sw = width; - pos.x -= sw; - } - DrawString(string, len, pos, width, size, stretch, font, eol); -} - -// Displays text. -// The vertical position is at the bottom of the box of the character. - -void CText::DrawText(char *string, Math::Point pos, float width, - int justif, float size, float stretch, FontType font, - int eol) -{ - DrawText(string, strlen(string), pos, width, justif, size, stretch, font, eol); -} - - -// Returns the size of a multi-font text. - -void CText::DimText(char *string, char *format, int len, Math::Point pos, - int justif, float size, float stretch, - Math::Point &start, Math::Point &end) -{ - float sw; - - start = end = pos; - - sw = RetStringWidth(string, format, len, size, stretch); - end.x += sw; - if ( justif == 0 ) // center? - { - start.x -= sw/2.0f; - end.x -= sw/2.0f; - } - if ( justif < 0 ) // flag was left? - { - start.x -= sw; - end.x -= sw; - } - - start.y -= RetDescent(size, FONT_COLOBOT); - end.y += RetAscent(size, FONT_COLOBOT); -} - -// Returns the size of a multi-font text. - -void CText::DimText(char *string, char *format, Math::Point pos, int justif, - float size, float stretch, - Math::Point &start, Math::Point &end) -{ - DimText(string, format, strlen(string), pos, justif, size, stretch, start, end); -} - -// Returns the size of a text. - -void CText::DimText(char *string, int len, Math::Point pos, int justif, - float size, float stretch, FontType font, - Math::Point &start, Math::Point &end) -{ - float sw; - - start = end = pos; - - sw = RetStringWidth(string, len, size, stretch, font); - end.x += sw; - if ( justif == 0 ) // center? - { - start.x -= sw/2.0f; - end.x -= sw/2.0f; - } - if ( justif < 0 ) // flag was left? - { - start.x -= sw; - end.x -= sw; - } - - start.y -= RetDescent(size, font); - end.y += RetAscent(size, font); -} - -// Returns the size of a text. - -void CText::DimText(char *string, Math::Point pos, int justif, - float size, float stretch, FontType font, - Math::Point &start, Math::Point &end) -{ - DimText(string, strlen(string), pos, justif, size, stretch, font, start, end); -} - - -// Returns the height above the baseline. - -float CText::RetAscent(float size, FontType font) -{ - return (13.0f/256.0f)*(size/20.0f); -} - -// Returns the height below the baseline. - -float CText::RetDescent(float size, FontType font) -{ - return (3.0f/256.0f)*(size/20.0f); -} - -// Returns the total height of the character. - -float CText::RetHeight(float size, FontType font) -{ - return (16.0f/256.0f)*(size/20.0f); -} - - -// Returns the width of a string of multi-font characters. - -float CText::RetStringWidth(char *string, char *format, int len, - float size, float stretch) -{ - FontType font; - float st, tab, w, width = 0.0f; - short *table, *pt; - int i, c; - - for ( i=0 ; iRetEditIndentValue(); - w = tab-Math::Mod(width, tab); - if ( w < tab*0.1f ) w += tab; - width += w; - continue; - } - - if ( c > 255 ) continue; - - pt = table+c*4; - st = stretch; - if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f; - width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; - } - } - - return width; -} - -// Returns the width of a string of characters. - -float CText::RetStringWidth(char *string, int len, - float size, float stretch, FontType font) -{ - float st, tab, w, width = 0.0f; - short *table, *pt; - int i, c; - - table = RetTable(font); - for ( i=0 ; iRetEditIndentValue(); - w = tab-Math::Mod(width, tab); - if ( w < tab*0.1f ) w += tab; - width += w; - continue; - } - - if ( c > 255 ) continue; - - pt = table+c*4; - st = stretch; - if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f; - width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; - } - - return width; -} - -// Returns the width of a character. -// 'offset' is the current position in the line. - -float CText::RetCharWidth(int character, float offset, - float size, float stretch, FontType font) -{ - float st, tab, w; - short* pt; - - if ( font == FONT_BUTTON ) return (12.0f/256.0f)*(size/20.0f); - - if ( character == '\t' ) - { - pt = RetTable(font)+' '*4; - tab = (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*stretch*m_engine->RetEditIndentValue(); - w = tab-Math::Mod(offset, tab); - if ( w < tab*0.1f ) w += tab; - return w; - } - - if ( character > 255 ) return 0.0f; - - pt = RetTable(font)+character*4; - st = stretch; -#if !_NEWLOOK - if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') ) st = 0.8f; -#endif - return (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; -} - - -// Justifies a line of multi-font text. Returns the offset of the cut. - -int CText::Justif(char *string, char *format, int len, float width, - float size, float stretch) -{ - FontType font; - float pos; - int i, character, cut; - - pos = 0.0f; - cut = 0; - for ( i=0 ; i width ) - { - if ( cut == 0 ) return i; - else return cut; - } - } - return i; -} - -// Justify a line of text. Returns the offset of the cut. - -int CText::Justif(char *string, int len, float width, - float size, float stretch, FontType font) -{ - float pos; - int i, character, cut; - - pos = 0.0f; - cut = 0; - for ( i=0 ; i width ) - { - if ( cut == 0 ) return i; - else return cut; - } - } - return i; -} - -// Returns the most suitable position to a given offset (multi-font). - -int CText::Detect(char *string, char *format, int len, float offset, - float size, float stretch) -{ - FontType font; - float pos, width; - int i, character, cut; - - pos = 0.0f; - cut = 0; - for ( i=0 ; iSetTexture("textp.tga"); -#else - m_engine->SetTexture("text.tga"); -#endif - m_engine->SetState(D3DSTATETTw); - - font = FONT_COLOBOT; - - start = pos.x; - offset = 0.0f; - for ( i=0 ; i width ) // exceeds the maximum width? - { - cw = RetCharWidth(16, offset, size, stretch, font); - pos.x = start+width-cw; - DrawChar(16, pos, size, stretch, font); // > - break; - } - - if ( (format[i]&COLOR_MASK) != 0 ) - { - DrawColor(pos, size, cw, format[i]&COLOR_MASK); - } - DrawChar(c, pos, size, stretch, font); - offset += cw; - pos.x += cw; - } - - if ( eol != 0 ) - { - DrawChar(eol, pos, size, stretch, font); - } -} - -// Displays text. - -void CText::DrawString(char *string, int len, Math::Point pos, float width, - float size, float stretch, FontType font, - int eol) -{ - float start, offset, cw; - int i, c; - -#if _POLISH - m_engine->SetTexture("textp.tga"); -#else - m_engine->SetTexture("text.tga"); -#endif - m_engine->SetState(D3DSTATETTw); - - start = pos.x; - offset = 0.0f; - for ( i=0 ; i width ) // exceeds the maximum width? - { - cw = RetCharWidth(16, offset, size, stretch, font); - pos.x = start+width-cw; - DrawChar(16, pos, size, stretch, font); // > - break; - } - - DrawChar(c, pos, size, stretch, font); - offset += cw; - pos.x += cw; - } - - if ( eol != 0 ) - { - DrawChar(eol, pos, size, stretch, font); - } -} - -// Displays the link to a character. - -void CText::DrawColor(Math::Point pos, float size, float width, int color) -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Point p1, p2; - POINT dim; - Math::Vector n; - float h, u1, u2, v1, v2, dp; - int icon; - - icon = -1; - if ( color == COLOR_LINK ) icon = 9; // blue - if ( color == COLOR_TOKEN ) icon = 4; // orange - if ( color == COLOR_TYPE ) icon = 5; // green - if ( color == COLOR_CONST ) icon = 8; // red - if ( color == COLOR_REM ) icon = 6; // magenta - if ( color == COLOR_KEY ) icon = 10; // gray - if ( icon == -1 ) return; - - if ( color == COLOR_LINK ) - { - m_engine->SetState(D3DSTATENORMAL); - } - - dim = m_engine->RetDim(); - if ( dim.y <= 768.0f ) // 1024x768 or less? - { - h = 1.01f/dim.y; // 1 pixel - } - else // more than 1024x768? - { - h = 2.0f/dim.y; // 2 pixels - } - - p1.x = pos.x; - p2.x = pos.x + width; - - if ( color == COLOR_LINK ) - { - p1.y = pos.y; - p2.y = pos.y + h; // just emphasized - } - else - { -#if 1 - p1.y = pos.y; - p2.y = pos.y + (16.0f/256.0f)*(size/20.0f); -//? p2.y = pos.y + h*4.0f; // just emphasized thick -#else - p1.y = pos.y; - p2.y = pos.y + (16.0f/256.0f)*(size/20.0f)/4.0f; -#endif - } - - u1 = (16.0f/256.0f)*(icon%16); - v1 = (240.0f/256.0f); - u2 = (16.0f/256.0f)+u1; - v2 = (16.0f/256.0f)+v1; - - dp = 0.5f/256.0f; - u1 += dp; - v1 += dp; - u2 -= dp; - v2 -= dp; - - n = Math::Vector(0.0f, 0.0f, -1.0f); // normal - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - - if ( color == COLOR_LINK ) - { - m_engine->SetState(D3DSTATETTw); - } -} - -// Displays a character. - -void CText::DrawChar(int character, Math::Point pos, float size, - float stretch, FontType font) -{ - D3DVERTEX2 vertex[4]; // 2 triangles - Math::Point p1, p2; - Math::Vector n; - float width, height, u1, u2, v1, v2, dp; - short* pt; - - dp = 0.5f/256.0f; - n = Math::Vector(0.0f, 0.0f, -1.0f); // normal - - if ( font == FONT_BUTTON ) - { - m_engine->SetTexture("button1.tga"); - m_engine->SetState(D3DSTATENORMAL); - - p1.x = pos.x; - p1.y = pos.y; - p2.x = pos.x + (12.0f/256.0f)*(size/20.0f); - p2.y = pos.y + (16.0f/256.0f)*(size/20.0f); - - if ( character <= 64 || character >= 128+56 ) - { - u1 = 66.0f/256.0f; - v1 = 2.0f/256.0f; - u2 = 94.0f/256.0f; - v2 = 30.0f/256.0f; - } - else - { - u1 = 224.0f/256.0f; - v1 = 32.0f/256.0f; - u2 = 256.0f/256.0f; - v2 = 64.0f/256.0f; - } - - u1 += dp; - v1 += dp; - u2 -= dp; - v2 -= dp; - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - -//? p1.x += (12.0f/256.0f)*(size/20.0f)*0.1f; -//? p1.y += (16.0f/256.0f)*(size/20.0f)*0.1f; -//? p2.x -= (12.0f/256.0f)*(size/20.0f)*0.1f; -//? p2.y -= (16.0f/256.0f)*(size/20.0f)*0.1f; - - if ( character >= 64 && character < 64+64 ) - { - character -= 64; - m_engine->SetTexture("button2.tga"); - } - if ( character >= 128 && character < 128+64 ) - { - character -= 128; - m_engine->SetTexture("button3.tga"); - } - - m_engine->SetState(D3DSTATETTw); - - u1 = (32.0f/256.0f)*(character%8); - v1 = (32.0f/256.0f)*(character/8); // uv texture - u2 = (32.0f/256.0f)+u1; - v2 = (32.0f/256.0f)+v1; - - u1 += dp; - v1 += dp; - u2 -= dp; - v2 -= dp; - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - - -#if _POLISH - m_engine->SetTexture("textp.tga"); -#else - m_engine->SetTexture("text.tga"); -#endif - return; - } - - if ( character > 255 ) return; - -//? if ( character == '\t' ) character = ' '; // if tab, does not display -> - -#if !_NEWLOOK - if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') ) - { - stretch = 0.8f; - } -#endif - if ( font == FONT_COURIER ) - { - stretch *= 1.2f; - } - - pt = RetTable(font)+character*4; - width = (float)(pt[2]-pt[0])/256.0f*stretch*0.9f; -//? width = (float)(pt[2]-pt[0])/256.0f*stretch; - height = (float)(pt[3]-pt[1])/256.0f; - -#if _NEWLOOK - pos.y += height*(size/20.0f)/17.0f; -#endif - p1.x = pos.x; - p1.y = pos.y; - p2.x = pos.x + width*(size/20.0f); - p2.y = pos.y + height*(size/20.0f); - - u1 = (float)pt[0]/256.0f; - v1 = (float)pt[1]/256.0f; - u2 = (float)pt[2]/256.0f; - v2 = (float)pt[3]/256.0f; - - if ( font == FONT_COLOBOT ) - { - u1 += dp; - u2 += dp; -#if _NEWLOOK - v2 += dp; -#endif - } - if ( font == FONT_COURIER ) - { - u1 -= dp; - u2 += dp*2.0f; - } - - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); - - m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); -} - +// * 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/. + +// text.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "old/d3dengine.h" +#include "common/language.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/text.h" + + + +static short table_text_colobot[] = +{ +// x1, y1, x2, y2 + 219,34, 225,50, // 0 + 1,188, 9,203, // . + 51,188,59,203, // square + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 11,188,19,203, // \t + 21,188,29,203, // \n + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, // \r + 219,34, 225,50, + 219,34, 225,50, + 41,188,49,203, // > + 31,188,39,203, // < + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + +#if _NEWLOOK + 0, 0, 4, 16, // 32 + 7, 0, 9, 16, // ! + 9, 0, 13, 16, // " + 13, 0, 24, 16, // # + 24, 0, 31, 16, // $ + 31, 0, 43, 16, // % + 43, 0, 54, 16, // & + 54, 0, 56, 16, // ' + 56, 0, 61, 16, // ( + 61, 0, 67, 16, // ) + 67, 0, 73, 16, // * + 73, 0, 83, 16, // + + 83, 0, 87, 16, // , + 87, 0, 92, 16, // - + 92, 0, 94, 16, // . + 94, 0, 101,16, // / + 101,0, 109,16, // 0 + 109,0, 114,16, // 1 + 114,0, 122,16, // 2 + 122,0, 129,16, // 3 + 129,0, 138,16, // 4 + 138,0, 146,16, // 5 + 146,0, 154,16, // 6 + 154,0, 161,16, // 7 + 161,0, 169,16, // 8 + 169,0, 177,16, // 9 + 177,0, 179,16, // : + 179,0, 183,16, // ; + 183,0, 193,16, // < + 193,0, 203,16, // = + 203,0, 213,16, // > + 213,0, 219,16, // ? + + 0, 17, 14, 33, // @ 64 + 14, 17, 26, 33, // A + 26, 17, 33, 33, // B + 33, 17, 42, 33, // C + 42, 17, 51, 33, // D + 51, 17, 58, 33, // E + 58, 17, 63, 33, // F + 63, 17, 73, 33, // G + 73, 17, 82, 33, // H + 82, 17, 84, 33, // I + 84, 17, 90, 33, // J + 90, 17, 98, 33, // K + 98, 17, 103,33, // L + 103,17, 115,33, // M + 115,17, 124,33, // N + 124,17, 136,33, // O + 136,17, 142,33, // P + 142,17, 154,33, // Q + 154,17, 160,33, // R + 160,17, 167,33, // S + 167,17, 175,33, // T + 175,17, 183,33, // U + 183,17, 194,33, // V + 194,17, 208,33, // W + 208,17, 218,33, // X + 218,17, 227,33, // Y + 227,17, 236,33, // Z + 236,17, 241,33, // [ + 241,17, 248,33, // \ + 248,17, 252,33, // ] + 219,0, 229,16, // ^ + 0, 34, 9, 50, // _ + + 54, 0, 56, 16, // ` 96 + 9, 34, 16, 50, // a + 16, 34, 25, 50, // b + 25, 34, 33, 50, // c + 33, 34, 42, 50, // d + 42, 34, 50, 50, // e + 50, 34, 55, 50, // f + 55, 34, 62, 50, // g + 62, 34, 69, 50, // h + 69, 34, 71, 50, // i + 71, 34, 75, 50, // j + 75, 34, 81, 50, // k + 81, 34, 83, 50, // l + 83, 34, 93, 50, // m + 93, 34, 100,50, // n + 100,34, 109,50, // o + 109,34, 118,50, // p + 118,34, 127,50, // q + 127,34, 132,50, // r + 132,34, 138,50, // s + 138,34, 143,50, // t + 143,34, 150,50, // u + 150,34, 158,50, // v + 158,34, 171,50, // w + 171,34, 179,50, // x + 179,34, 187,50, // y + 187,34, 195,50, // z + 195,34, 201,50, // { + 201,34, 203,50, // | + 203,34, 209,50, // } + 209,34, 219,50, // ~ + 219,34, 228,50, // + + 219,34, 225,50, // 128 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 144 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 160 + 219,34, 225,50, // 161 A1 ! reverse + 219,34, 225,50, + 219,34, 225,50, // 163 A3 Ł + 219,34, 225,50, + 219,34, 225,50, + 0, 0, 4, 16, // 166 A6 ¦ (space) + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 176 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, // 191 BF ? reverse + + 12, 51, 24, 67, // 192 C0 ŕ big + 0, 51, 12, 67, // 193 C1 á big + 24, 51, 36, 67, // 194 C2 â big + 48, 51, 60, 67, // 195 C3 ă big + 36, 51, 48, 67, // 196 C4 ä big + 219,34, 225,50, + 219,34, 225,50, + 60, 51, 69, 67, // 199 C7 ç big + 77, 51, 84, 67, // 200 C8 č big + 70, 51, 77, 67, // 201 C9 é big + 85, 51, 92, 67, // 202 CA ę big + 93, 51, 100,67, // 203 CB ë big + 219,34, 225,50, + 100,51, 104,67, // 205 CD í big + 108,51, 113,67, // 206 CE î big + 113,51, 117,67, // 207 CF ď big + + 219,34, 225,50, // 208 + 117,51, 126,67, // 209 D1 ń big + 219,34, 225,50, + 126,51, 138,67, // 211 D3 ó big + 150,51, 162,67, // 212 D4 ô big + 219,34, 225,50, + 162,51, 174,67, // 214 D6 ö big + 219,34, 225,50, + 219,34, 225,50, + 194,51, 202,67, // 217 D9 ů big + 186,51, 194,67, // 218 DA ú big + 202,51, 210,67, // 219 DB ű big + 210,51, 218,67, // 220 DC ü big + 219,34, 225,50, + 219,34, 225,50, + 218,51, 227,67, // 223 DF German SS + + 7, 68, 14, 84, // 224 E0 ŕ small + 0, 68, 7, 84, // 225 E1 á small + 14, 68, 21, 84, // 226 E2 â small + 28, 68, 35, 84, // 227 E3 ă small + 21, 68, 28, 84, // 228 E4 ä small + 219,34, 225,50, + 219,34, 225,50, + 35, 68, 43, 84, // 231 E7 ç small + 51, 68, 59, 84, // 232 E8 č small + 43, 68, 51, 84, // 233 E9 é small + 59, 68, 67, 84, // 234 EA ę small + 67, 68, 75, 84, // 235 EB ë small + 219,34, 225,50, + 75, 68, 79, 84, // 237 ED í small + 83, 68, 88, 84, // 238 EE î small + 88, 68, 92, 84, // 239 EF ď small + + 219,34, 225,50, // 240 + 92, 68, 99, 84, // 241 F1 ń small + 219,34, 225,50, + 99, 68, 108,84, // 243 F3 ó small + 117,68, 126,84, // 244 F4 ô small + 219,34, 225,50, + 126,68, 135,84, // 246 F6 ö small + 219,34, 225,50, + 219,34, 225,50, + 151,68, 158,84, // 249 F9 ů small + 144,68, 151,84, // 250 FA ú small + 158,68, 165,84, // 251 FB ű small + 165,68, 172,84, // 252 FC ü small + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, +#else + 0, 0, 4, 16, // 32 + 4, 0, 7, 16, // ! + 7, 0, 13, 16, + 14, 0, 21, 16, + 22, 0, 28, 16, + 29, 0, 38, 16, + 39, 0, 48, 16, + 48, 0, 51, 16, + 51, 0, 55, 16, + 55, 0, 59, 16, + 59, 0, 65, 16, + 66, 0, 72, 16, + 73, 0, 76, 16, + 76, 0, 82, 16, + 82, 0, 85, 16, + 85, 0, 90, 16, + 90, 0, 97, 16, + 98, 0, 103,16, + 104,0, 111,16, + 111,0, 118,16, + 118,0, 125,16, + 125,0, 132,16, + 132,0, 139,16, + 139,0, 146,16, + 146,0, 153,16, + 153,0, 160,16, + 160,0, 165,16, // : + 164,0, 169,16, // ; + 169,0, 177,16, // < + 177,0, 185,16, // = + 185,0, 193,16, // > + 193,0, 201,16, // ? + + 201,0, 215,16, // 64 + 0, 17, 10, 33, // A + 10, 17, 18, 33, + 19, 17, 28, 33, + 28, 17, 36, 33, + 37, 17, 44, 33, + 45, 17, 52, 33, + 53, 17, 62, 33, + 63, 17, 71, 33, + 72, 17, 75, 33, + 75, 17, 82, 33, + 83, 17, 91, 33, + 92, 17, 99, 33, + 100,17, 110,33, + 111,17, 119,33, +//? 120,17, 129,33, // O + 216,0, 227,16, // O + 130,17, 138,33, + 139,17, 148,33, + 149,17, 158,33, + 158,17, 166,33, + 166,17, 175,33, + 175,17, 183,33, + 183,17, 193,33, + 193,17, 207,33, + 207,17, 215,33, + 215,17, 224,33, + 224,17, 232,33, // Z + 232,17, 236,33, + 236,17, 241,33, + 241,17, 245,33, + 245,17, 252,33, // ^ + 0, 34, 8, 50, // _ + + 45, 17, 52, 33, // 96 + 8, 34, 15, 50, // a + 16, 34, 23, 50, + 24, 34, 31, 50, + 31, 34, 38, 50, + 39, 34, 46, 50, + 46, 34, 52, 50, + 52, 34, 59, 50, + 60, 34, 67, 50, + 68, 34, 71, 50, + 71, 34, 76, 50, + 77, 34, 84, 50, + 84, 34, 87, 50, + 88, 34, 99, 50, + 100,34, 107,50, +//? 108,34, 115,50, // o + 238,0, 246,16, // o + 116,34, 123,50, + 124,34, 131,50, + 132,34, 137,50, + 137,34, 144,50, + 144,34, 149,50, + 149,34, 156,50, + 156,34, 164,50, + 164,34, 176,50, + 176,34, 183,50, + 183,34, 191,50, + 191,34, 197,50, // z + 197,34, 203,50, + 203,34, 205,50, + 205,34, 211,50, + 211,34, 219,50, + 219,34, 225,50, + +#if _POLISH + 219,34, 225,50, // 128 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 0, 51, 8, 67, // 140 S´ + 219,34, 225,50, + 219,34, 225,50, + 9, 51, 17, 67, // 143 Z´ + + 219,34, 225,50, // 144 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 0, 68, 7, 84, // 156 s´ + 219,34, 225,50, + 219,34, 225,50, + 8, 68, 14, 84, // 159 z´ + + 219,34, 225,50, // 160 + 219,34, 225,50, + 219,34, 225,50, + 18, 51, 27, 67, // 163 L/ + 219,34, 225,50, + 28, 51, 39, 67, // 165 A, + 0, 0, 4, 16, // 166 A6 ¦ (space) + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 40, 51, 48, 67, // 175 Zo + + 219,34, 225,50, // 176 + 219,34, 225,50, + 219,34, 225,50, + 16, 68, 21, 84, // 179 l/ + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 23, 68, 31, 84, // 185 a, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 32, 68, 38, 84, // 191 zo + + 219,34, 225,50, // 192 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 49, 51, 58, 67, // 198 C´ + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 59, 51, 66, 67, // 202 E, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 208 + 67, 51, 75, 67, // 209 N´ + 219,34, 225,50, +//? 76, 51, 85, 67, // 211 O´ + 86, 51, 97, 67, // 211 O´ + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 224 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 39, 68, 46, 84, // 230 c´ + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 47, 68, 54, 84, // 234 e, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 240 + 55, 68, 62, 84, // 241 n´ + 219,34, 225,50, +//? 63, 68, 70, 84, // 243 o´ + 71, 68, 79, 84, // 243 o´ + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, +#else + 219,34, 225,50, // 128 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 144 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 160 + 219,34, 225,50, // 161 A1 ! reverse + 219,34, 225,50, + 219,34, 225,50, // 163 A3 Ł + 219,34, 225,50, + 219,34, 225,50, + 0, 0, 4, 16, // 166 A6 ¦ (space) + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + + 219,34, 225,50, // 176 + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, // 191 BF ? reverse + + 10, 51, 20, 67, // 192 C0 ŕ big + 0, 51, 10, 67, // 193 C1 á big + 20, 51, 30, 67, // 194 C2 â big + 40, 51, 50, 67, // 195 C3 ă big + 30, 51, 40, 67, // 196 C4 ä big + 219,34, 225,50, + 219,34, 225,50, + 50, 51, 59, 67, // 199 C7 ç big + 67, 51, 74, 67, // 200 C8 č big + 59, 51, 66, 67, // 201 C9 é big + 75, 51, 82, 67, // 202 CA ę big + 83, 51, 90, 67, // 203 CB ë big + 219,34, 225,50, + 91, 51, 95, 67, // 205 CD í big + 100,51, 103,67, // 206 CE î big + 104,51, 109,67, // 207 CF ď big + + 219,34, 225,50, // 208 + 109,51, 117,67, // 209 D1 ń big + 219,34, 225,50, + 118,51, 127,67, // 211 D3 ó big + 138,51, 147,67, // 212 D4 ô big + 219,34, 225,50, + 148,51, 157,67, // 214 D6 ö big + 219,34, 225,50, + 219,34, 225,50, + 177,51, 185,67, // 217 D9 ů big + 168,51, 176,67, // 218 DA ú big + 186,51, 194,67, // 219 DB ű big + 195,51, 203,67, // 220 DC ü big + 219,34, 225,50, + 219,34, 225,50, + 211,51, 220,67, // 223 DF German SS + + 8, 68, 15, 84, // 224 E0 ŕ small + 0, 68, 7, 84, // 225 E1 á small + 16, 68, 23, 84, // 226 E2 â small + 32, 68, 39, 84, // 227 E3 ă small + 24, 68, 31, 84, // 228 E4 ä small + 219,34, 225,50, + 219,34, 225,50, + 40, 68, 47, 84, // 231 E7 ç small + 55, 68, 62, 84, // 232 E8 č small + 47, 68, 54, 84, // 233 E9 é small + 63, 68, 70, 84, // 234 EA ę small + 71, 68, 78, 84, // 235 EB ë small + 219,34, 225,50, + 79, 68, 83, 84, // 237 ED í small + 88, 68, 92, 84, // 238 EE î small + 92, 68, 97, 84, // 239 EF ď small + + 219,34, 225,50, // 240 + 97, 68, 104,84, // 241 F1 ń small + 219,34, 225,50, + 105,68, 112,84, // 243 F3 ó small + 121,68, 128,84, // 244 F4 ô small + 219,34, 225,50, + 129,68, 136,84, // 246 F6 ö small + 219,34, 225,50, + 219,34, 225,50, + 153,68, 160,84, // 249 F9 ů small + 145,68, 152,84, // 250 FA ú small + 161,68, 168,84, // 251 FB ű small + 169,68, 176,84, // 252 FC ü small + 219,34, 225,50, + 219,34, 225,50, + 219,34, 225,50, +#endif +#endif +}; + + +static short table_text_courier[] = +{ +// x1, y1, x2, y2 + 231,137,239,153, // 0 + 1,188, 9,204, // . + 51,188,59,204, // square + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 11,188,19,204, // \t + 21,188,29,204, // \n + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, // \r + 231,137,239,153, + 231,137,239,153, + 41,188,49,204, // > + 31,188,39,204, // < + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 1, 86, 9,102, // 32 + 11, 86, 19,102, + 21, 86, 29,102, + 31, 86, 39,102, + 41, 86, 49,102, + 51, 86, 59,102, + 61, 86, 69,102, + 71, 86, 79,102, + 81, 86, 89,102, + 91, 86, 99,102, + 101, 86,109,102, + 111, 86,119,102, + 121, 86,129,102, + 131, 86,139,102, + 141, 86,149,102, + 151, 86,159,102, + 161, 86,169,102, + 171, 86,179,102, + 181, 86,189,102, + 191, 86,199,102, + 201, 86,209,102, + 211, 86,219,102, + 221, 86,229,102, + 231, 86,239,102, + 1,103, 9,119, // 56 + 11,103, 19,119, + 21,103, 29,119, + 31,103, 39,119, + 41,103, 49,119, + 51,103, 59,119, + 61,103, 69,119, + 71,103, 79,119, + + 81,103, 89,119, // @ + 91,103, 99,119, + 101,103,109,119, + 111,103,119,119, + 121,103,129,119, + 131,103,139,119, + 141,103,149,119, + 151,103,159,119, + 161,103,169,119, + 171,103,179,119, + 181,103,189,119, + 191,103,199,119, + 201,103,209,119, + 211,103,219,119, + 221,103,229,119, + 231,103,239,119, + 1,120, 9,136, // P + 11,120, 19,136, + 21,120, 29,136, + 31,120, 39,136, + 41,120, 49,136, + 51,120, 59,136, + 61,120, 69,136, + 71,120, 79,136, + 81,120, 89,136, + 91,120, 99,136, + 101,120,109,136, + 111,120,119,136, // [ + 121,120,129,136, + 131,120,139,136, + 141,120,149,136, + 151,120,159,136, // _ + + 161,120,169,136, + 171,120,179,136, // a + 181,120,189,136, + 191,120,199,136, + 201,120,209,136, + 211,120,219,136, + 221,120,229,136, + 231,120,239,136, + 1,137, 9,153, + 11,137, 19,153, + 21,137, 29,153, + 31,137, 39,153, + 41,137, 49,153, + 51,137, 59,153, + 61,137, 69,153, + 71,137, 79,153, // o + 81,137, 89,153, + 91,137, 99,153, + 101,137,109,153, + 111,137,119,153, + 121,137,129,153, + 131,137,139,153, + 141,137,149,153, + 151,137,159,153, + 161,137,169,153, + 171,137,179,153, + 181,137,189,153, + 191,137,199,153, + 201,137,209,153, + 211,137,219,153, + 221,137,229,153, // ~ + 231,137,239,153, + +#if _POLISH + 231,137,239,153, // 128 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 1,154, 9,170, // 140 S´ + 231,137,239,153, + 231,137,239,153, + 11,154, 19,170, // 143 Z´ + + 231,137,239,153, // 144 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 1,171, 9,187, // 156 s´ + 231,137,239,153, + 231,137,239,153, + 11,171, 19,187, // 159 z´ + + 231,137,239,153, // 160 + 231,137,239,153, + 231,137,239,153, + 21,154, 29,170, // 163 L/ + 231,137,239,153, + 31,154, 39,170, // 165 A, + 1, 86, 9,102, // 166 A6 ¦ (space) + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 41,154, 49,170, // 175 Zo + + 231,137,239,153, // 176 + 231,137,239,153, + 231,137,239,153, + 21,171, 29,187, // 179 l/ + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 31,171, 39,187, // 185 a, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 41,171, 49,187, // 191 zo + + 231,137,239,153, // 192 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 51,154, 59,170, // 198 C´ + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 61,154, 69,170, // 202 E, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 208 + 71,154, 79,170, // 209 N´ + 231,137,239,153, + 81,171, 89,187, // 211 O´ + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 224 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 51,171, 59,187, // 230 c´ + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 61,171, 69,187, // 234 e, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 240 + 71,171, 79,187, // 241 n´ + 231,137,239,153, + 81,171, 89,187, // 243 ó small + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, +#else + 231,137,239,153, // 128 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 144 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 160 + 231,137,239,153, // 161 A1 ! reverse + 231,137,239,153, + 231,137,239,153, // 163 A3 Ł + 231,137,239,153, + 231,137,239,153, + 1, 86, 9,102, // 166 A6 ¦ (space) + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + + 231,137,239,153, // 176 + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, // 191 BF ? reverse + + 11,154, 19,170, // ŕ big + 1,154, 9,170, // á big + 21,154, 29,170, // â big + 41,154, 49,170, // ă big + 31,154, 39,170, // ä big + 231,137,239,153, + 231,137,239,153, + 51,154, 59,170, // ç big + 71,154, 79,170, // č big + 61,154, 69,170, // é big + 81,154, 89,170, // ę big + 91,154, 99,170, // ë big + 231,137,239,153, + 101,154,109,170, // í big + 121,154,129,170, // î big + 131,154,139,170, // ď big + 231,137,239,153, + 141,154,149,170, // ń big + 231,137,239,153, + 151,154,159,170, // ó big + 171,154,179,170, // ô big + 231,137,239,153, + 181,154,189,170, // ö big + 231,137,239,153, + 231,137,239,153, + 211,154,219,170, // ů big + 201,154,209,170, // ú big + 221,154,229,170, // ű big + 231,154,239,170, // ü big + 231,137,239,153, + 231,137,239,153, + 241,154,249,170, // 223 DF German SS + + 11,171, 19,187, // ŕ small + 1,171, 9,187, // á small + 21,171, 29,187, // â small + 41,171, 49,187, // ă small + 31,171, 39,187, // ä small + 231,137,239,153, + 231,137,239,153, + 51,171, 59,187, // ç small + 71,171, 79,187, // č small + 61,171, 69,187, // é small + 81,171, 89,187, // ę small + 91,171, 99,187, // ë small + 231,137,239,153, + 111,171,119,187, // ě small + 121,171,129,187, // î small + 131,171,139,187, // ď small + 231,137,239,153, + 141,171,149,187, // ń small + 231,137,239,153, + 151,171,159,187, // ó small + 171,171,179,187, // ô small + 231,137,239,153, + 181,171,189,187, // ö small + 231,137,239,153, + 231,137,239,153, + 211,171,219,187, // ů small + 201,171,209,187, // ú small + 221,171,229,187, // ű small + 231,171,239,187, // ü small + 231,137,239,153, + 231,137,239,153, + 231,137,239,153, +#endif +}; + + +// Returns the pointer to the table by the font. + +short* RetTable(FontType font) +{ + if ( font == FONT_COLOBOT ) return table_text_colobot; + else return table_text_courier; +} + + + +// Object's constructor. + +CText::CText(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_TEXT, this); + + m_pD3DDevice = 0; + m_engine = engine; +} + +// Object's destructor. + +CText::~CText() +{ + m_iMan->DeleteInstance(CLASS_TEXT, this); +} + + +void CText::SetD3DDevice(LPDIRECT3DDEVICE7 device) +{ + m_pD3DDevice = device; +} + + +// Displays multi-font text. +// The vertical position is at the bottom of the box of the character. + +void CText::DrawText(char *string, char *format, int len, Math::Point pos, + float width, int justif, float size, float stretch, + int eol) +{ + float sw; + + if ( justif == 0 ) // center? + { + sw = RetStringWidth(string, format, len, size, stretch); + if ( sw > width ) sw = width; + pos.x -= sw/2.0f; + } + if ( justif < 0 ) // flag was left? + { + sw = RetStringWidth(string, format, len, size, stretch); + if ( sw > width ) sw = width; + pos.x -= sw; + } + DrawString(string, format, len, pos, width, size, stretch, eol); +} + +// Displays multi-font text. +// The vertical position is at the bottom of the box of the character. + +void CText::DrawText(char *string, char *format, Math::Point pos, float width, + int justif, float size, float stretch, + int eol) +{ + DrawText(string, format, strlen(string), pos, width, justif, size, stretch, eol); +} + +// Displays text. +// The vertical position is at the bottom of the box of the character. + +void CText::DrawText(char *string, int len, Math::Point pos, float width, + int justif, float size, float stretch, FontType font, + int eol) +{ + float sw; + + if ( justif == 0 ) // center? + { + sw = RetStringWidth(string, len, size, stretch, font); + if ( sw > width ) sw = width; + pos.x -= sw/2.0f; + } + if ( justif < 0 ) // flag was left? + { + sw = RetStringWidth(string, len, size, stretch, font); + if ( sw > width ) sw = width; + pos.x -= sw; + } + DrawString(string, len, pos, width, size, stretch, font, eol); +} + +// Displays text. +// The vertical position is at the bottom of the box of the character. + +void CText::DrawText(char *string, Math::Point pos, float width, + int justif, float size, float stretch, FontType font, + int eol) +{ + DrawText(string, strlen(string), pos, width, justif, size, stretch, font, eol); +} + + +// Returns the size of a multi-font text. + +void CText::DimText(char *string, char *format, int len, Math::Point pos, + int justif, float size, float stretch, + Math::Point &start, Math::Point &end) +{ + float sw; + + start = end = pos; + + sw = RetStringWidth(string, format, len, size, stretch); + end.x += sw; + if ( justif == 0 ) // center? + { + start.x -= sw/2.0f; + end.x -= sw/2.0f; + } + if ( justif < 0 ) // flag was left? + { + start.x -= sw; + end.x -= sw; + } + + start.y -= RetDescent(size, FONT_COLOBOT); + end.y += RetAscent(size, FONT_COLOBOT); +} + +// Returns the size of a multi-font text. + +void CText::DimText(char *string, char *format, Math::Point pos, int justif, + float size, float stretch, + Math::Point &start, Math::Point &end) +{ + DimText(string, format, strlen(string), pos, justif, size, stretch, start, end); +} + +// Returns the size of a text. + +void CText::DimText(char *string, int len, Math::Point pos, int justif, + float size, float stretch, FontType font, + Math::Point &start, Math::Point &end) +{ + float sw; + + start = end = pos; + + sw = RetStringWidth(string, len, size, stretch, font); + end.x += sw; + if ( justif == 0 ) // center? + { + start.x -= sw/2.0f; + end.x -= sw/2.0f; + } + if ( justif < 0 ) // flag was left? + { + start.x -= sw; + end.x -= sw; + } + + start.y -= RetDescent(size, font); + end.y += RetAscent(size, font); +} + +// Returns the size of a text. + +void CText::DimText(char *string, Math::Point pos, int justif, + float size, float stretch, FontType font, + Math::Point &start, Math::Point &end) +{ + DimText(string, strlen(string), pos, justif, size, stretch, font, start, end); +} + + +// Returns the height above the baseline. + +float CText::RetAscent(float size, FontType font) +{ + return (13.0f/256.0f)*(size/20.0f); +} + +// Returns the height below the baseline. + +float CText::RetDescent(float size, FontType font) +{ + return (3.0f/256.0f)*(size/20.0f); +} + +// Returns the total height of the character. + +float CText::RetHeight(float size, FontType font) +{ + return (16.0f/256.0f)*(size/20.0f); +} + + +// Returns the width of a string of multi-font characters. + +float CText::RetStringWidth(char *string, char *format, int len, + float size, float stretch) +{ + FontType font; + float st, tab, w, width = 0.0f; + short *table, *pt; + int i, c; + + for ( i=0 ; iRetEditIndentValue(); + w = tab-Math::Mod(width, tab); + if ( w < tab*0.1f ) w += tab; + width += w; + continue; + } + + if ( c > 255 ) continue; + + pt = table+c*4; + st = stretch; + if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f; + width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; + } + } + + return width; +} + +// Returns the width of a string of characters. + +float CText::RetStringWidth(char *string, int len, + float size, float stretch, FontType font) +{ + float st, tab, w, width = 0.0f; + short *table, *pt; + int i, c; + + table = RetTable(font); + for ( i=0 ; iRetEditIndentValue(); + w = tab-Math::Mod(width, tab); + if ( w < tab*0.1f ) w += tab; + width += w; + continue; + } + + if ( c > 255 ) continue; + + pt = table+c*4; + st = stretch; + if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f; + width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; + } + + return width; +} + +// Returns the width of a character. +// 'offset' is the current position in the line. + +float CText::RetCharWidth(int character, float offset, + float size, float stretch, FontType font) +{ + float st, tab, w; + short* pt; + + if ( font == FONT_BUTTON ) return (12.0f/256.0f)*(size/20.0f); + + if ( character == '\t' ) + { + pt = RetTable(font)+' '*4; + tab = (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*stretch*m_engine->RetEditIndentValue(); + w = tab-Math::Mod(offset, tab); + if ( w < tab*0.1f ) w += tab; + return w; + } + + if ( character > 255 ) return 0.0f; + + pt = RetTable(font)+character*4; + st = stretch; +#if !_NEWLOOK + if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') ) st = 0.8f; +#endif + return (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st; +} + + +// Justifies a line of multi-font text. Returns the offset of the cut. + +int CText::Justif(char *string, char *format, int len, float width, + float size, float stretch) +{ + FontType font; + float pos; + int i, character, cut; + + pos = 0.0f; + cut = 0; + for ( i=0 ; i width ) + { + if ( cut == 0 ) return i; + else return cut; + } + } + return i; +} + +// Justify a line of text. Returns the offset of the cut. + +int CText::Justif(char *string, int len, float width, + float size, float stretch, FontType font) +{ + float pos; + int i, character, cut; + + pos = 0.0f; + cut = 0; + for ( i=0 ; i width ) + { + if ( cut == 0 ) return i; + else return cut; + } + } + return i; +} + +// Returns the most suitable position to a given offset (multi-font). + +int CText::Detect(char *string, char *format, int len, float offset, + float size, float stretch) +{ + FontType font; + float pos, width; + int i, character, cut; + + pos = 0.0f; + cut = 0; + for ( i=0 ; iSetTexture("textp.tga"); +#else + m_engine->SetTexture("text.tga"); +#endif + m_engine->SetState(D3DSTATETTw); + + font = FONT_COLOBOT; + + start = pos.x; + offset = 0.0f; + for ( i=0 ; i width ) // exceeds the maximum width? + { + cw = RetCharWidth(16, offset, size, stretch, font); + pos.x = start+width-cw; + DrawChar(16, pos, size, stretch, font); // > + break; + } + + if ( (format[i]&COLOR_MASK) != 0 ) + { + DrawColor(pos, size, cw, format[i]&COLOR_MASK); + } + DrawChar(c, pos, size, stretch, font); + offset += cw; + pos.x += cw; + } + + if ( eol != 0 ) + { + DrawChar(eol, pos, size, stretch, font); + } +} + +// Displays text. + +void CText::DrawString(char *string, int len, Math::Point pos, float width, + float size, float stretch, FontType font, + int eol) +{ + float start, offset, cw; + int i, c; + +#if _POLISH + m_engine->SetTexture("textp.tga"); +#else + m_engine->SetTexture("text.tga"); +#endif + m_engine->SetState(D3DSTATETTw); + + start = pos.x; + offset = 0.0f; + for ( i=0 ; i width ) // exceeds the maximum width? + { + cw = RetCharWidth(16, offset, size, stretch, font); + pos.x = start+width-cw; + DrawChar(16, pos, size, stretch, font); // > + break; + } + + DrawChar(c, pos, size, stretch, font); + offset += cw; + pos.x += cw; + } + + if ( eol != 0 ) + { + DrawChar(eol, pos, size, stretch, font); + } +} + +// Displays the link to a character. + +void CText::DrawColor(Math::Point pos, float size, float width, int color) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Point p1, p2; + POINT dim; + Math::Vector n; + float h, u1, u2, v1, v2, dp; + int icon; + + icon = -1; + if ( color == COLOR_LINK ) icon = 9; // blue + if ( color == COLOR_TOKEN ) icon = 4; // orange + if ( color == COLOR_TYPE ) icon = 5; // green + if ( color == COLOR_CONST ) icon = 8; // red + if ( color == COLOR_REM ) icon = 6; // magenta + if ( color == COLOR_KEY ) icon = 10; // gray + if ( icon == -1 ) return; + + if ( color == COLOR_LINK ) + { + m_engine->SetState(D3DSTATENORMAL); + } + + dim = m_engine->RetDim(); + if ( dim.y <= 768.0f ) // 1024x768 or less? + { + h = 1.01f/dim.y; // 1 pixel + } + else // more than 1024x768? + { + h = 2.0f/dim.y; // 2 pixels + } + + p1.x = pos.x; + p2.x = pos.x + width; + + if ( color == COLOR_LINK ) + { + p1.y = pos.y; + p2.y = pos.y + h; // just emphasized + } + else + { +#if 1 + p1.y = pos.y; + p2.y = pos.y + (16.0f/256.0f)*(size/20.0f); +//? p2.y = pos.y + h*4.0f; // just emphasized thick +#else + p1.y = pos.y; + p2.y = pos.y + (16.0f/256.0f)*(size/20.0f)/4.0f; +#endif + } + + u1 = (16.0f/256.0f)*(icon%16); + v1 = (240.0f/256.0f); + u2 = (16.0f/256.0f)+u1; + v2 = (16.0f/256.0f)+v1; + + dp = 0.5f/256.0f; + u1 += dp; + v1 += dp; + u2 -= dp; + v2 -= dp; + + n = Math::Vector(0.0f, 0.0f, -1.0f); // normal + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + if ( color == COLOR_LINK ) + { + m_engine->SetState(D3DSTATETTw); + } +} + +// Displays a character. + +void CText::DrawChar(int character, Math::Point pos, float size, + float stretch, FontType font) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + Math::Point p1, p2; + Math::Vector n; + float width, height, u1, u2, v1, v2, dp; + short* pt; + + dp = 0.5f/256.0f; + n = Math::Vector(0.0f, 0.0f, -1.0f); // normal + + if ( font == FONT_BUTTON ) + { + m_engine->SetTexture("button1.tga"); + m_engine->SetState(D3DSTATENORMAL); + + p1.x = pos.x; + p1.y = pos.y; + p2.x = pos.x + (12.0f/256.0f)*(size/20.0f); + p2.y = pos.y + (16.0f/256.0f)*(size/20.0f); + + if ( character <= 64 || character >= 128+56 ) + { + u1 = 66.0f/256.0f; + v1 = 2.0f/256.0f; + u2 = 94.0f/256.0f; + v2 = 30.0f/256.0f; + } + else + { + u1 = 224.0f/256.0f; + v1 = 32.0f/256.0f; + u2 = 256.0f/256.0f; + v2 = 64.0f/256.0f; + } + + u1 += dp; + v1 += dp; + u2 -= dp; + v2 -= dp; + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + +//? p1.x += (12.0f/256.0f)*(size/20.0f)*0.1f; +//? p1.y += (16.0f/256.0f)*(size/20.0f)*0.1f; +//? p2.x -= (12.0f/256.0f)*(size/20.0f)*0.1f; +//? p2.y -= (16.0f/256.0f)*(size/20.0f)*0.1f; + + if ( character >= 64 && character < 64+64 ) + { + character -= 64; + m_engine->SetTexture("button2.tga"); + } + if ( character >= 128 && character < 128+64 ) + { + character -= 128; + m_engine->SetTexture("button3.tga"); + } + + m_engine->SetState(D3DSTATETTw); + + u1 = (32.0f/256.0f)*(character%8); + v1 = (32.0f/256.0f)*(character/8); // uv texture + u2 = (32.0f/256.0f)+u1; + v2 = (32.0f/256.0f)+v1; + + u1 += dp; + v1 += dp; + u2 -= dp; + v2 -= dp; + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + +#if _POLISH + m_engine->SetTexture("textp.tga"); +#else + m_engine->SetTexture("text.tga"); +#endif + return; + } + + if ( character > 255 ) return; + +//? if ( character == '\t' ) character = ' '; // if tab, does not display -> + +#if !_NEWLOOK + if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') ) + { + stretch = 0.8f; + } +#endif + if ( font == FONT_COURIER ) + { + stretch *= 1.2f; + } + + pt = RetTable(font)+character*4; + width = (float)(pt[2]-pt[0])/256.0f*stretch*0.9f; +//? width = (float)(pt[2]-pt[0])/256.0f*stretch; + height = (float)(pt[3]-pt[1])/256.0f; + +#if _NEWLOOK + pos.y += height*(size/20.0f)/17.0f; +#endif + p1.x = pos.x; + p1.y = pos.y; + p2.x = pos.x + width*(size/20.0f); + p2.y = pos.y + height*(size/20.0f); + + u1 = (float)pt[0]/256.0f; + v1 = (float)pt[1]/256.0f; + u2 = (float)pt[2]/256.0f; + v2 = (float)pt[3]/256.0f; + + if ( font == FONT_COLOBOT ) + { + u1 += dp; + u2 += dp; +#if _NEWLOOK + v2 += dp; +#endif + } + if ( font == FONT_COURIER ) + { + u1 -= dp; + u2 += dp*2.0f; + } + + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); +} + diff --git a/src/old/text.h b/src/old/text.h index 6ba30a3..3b2fd90 100644 --- a/src/old/text.h +++ b/src/old/text.h @@ -1,111 +1,111 @@ -// * 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/. - -// text.h - -#pragma once - - -#include "math/point.h" -#include "old/d3dengine.h" - - -class CInstanceManager; - - - -const float SMALLFONT = 10.0f; -const float BIGFONT = 15.0f; - -const float NORMSTRETCH = 0.8f; - - - -enum FontType -{ - FONT_COLOBOT = 0, - FONT_COURIER = 1, - FONT_BUTTON = 2, -}; - -enum FontTitle -{ - TITLE_BIG = 0x04, - TITLE_NORM = 0x08, - TITLE_LITTLE = 0x0c, -}; - -enum FontColor -{ - COLOR_LINK = 0x10, - COLOR_TOKEN = 0x20, - COLOR_TYPE = 0x30, - COLOR_CONST = 0x40, - COLOR_REM = 0x50, - COLOR_KEY = 0x60, - COLOR_TABLE = 0x70, -}; - -const int FONT_MASK = 0x03; -const int TITLE_MASK = 0x0c; -const int COLOR_MASK = 0x70; -const int IMAGE_MASK = 0x80; - - - -class CText -{ -public: - CText(CInstanceManager *iMan, CD3DEngine* engine); - ~CText(); - - void SetD3DDevice(LPDIRECT3DDEVICE7 device); - - void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol); - void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol); - void DrawText(char *string, int len, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol); - void DrawText(char *string, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol); - void DimText(char *string, char *format, int len, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end); - void DimText(char *string, char *format, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end); - void DimText(char *string, int len, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end); - void DimText(char *string, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end); - - float RetAscent(float size, FontType font); - float RetDescent(float size, FontType font); - float RetHeight(float size, FontType font); - - float RetStringWidth(char *string, char *format, int len, float size, float stretch); - float RetStringWidth(char *string, int len, float size, float stretch, FontType font); - float RetCharWidth(int character, float offset, float size, float stretch, FontType font); - - int Justif(char *string, char *format, int len, float width, float size, float stretch); - int Justif(char *string, int len, float width, float size, float stretch, FontType font); - int Detect(char *string, char *format, int len, float offset, float size, float stretch); - int Detect(char *string, int len, float offset, float size, float stretch, FontType font); - -protected: - void DrawString(char *string, char *format, int len, Math::Point pos, float width, float size, float stretch, int eol); - void DrawString(char *string, int len, Math::Point pos, float width, float size, float stretch, FontType font, int eol); - void DrawColor(Math::Point pos, float size, float width, int color); - void DrawChar(int character, Math::Point pos, float size, float stretch, FontType font); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - LPDIRECT3DDEVICE7 m_pD3DDevice; - -}; - +// * 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/. + +// text.h + +#pragma once + + +#include "math/point.h" +#include "old/d3dengine.h" + + +class CInstanceManager; + + + +const float SMALLFONT = 10.0f; +const float BIGFONT = 15.0f; + +const float NORMSTRETCH = 0.8f; + + + +enum FontType +{ + FONT_COLOBOT = 0, + FONT_COURIER = 1, + FONT_BUTTON = 2, +}; + +enum FontTitle +{ + TITLE_BIG = 0x04, + TITLE_NORM = 0x08, + TITLE_LITTLE = 0x0c, +}; + +enum FontColor +{ + COLOR_LINK = 0x10, + COLOR_TOKEN = 0x20, + COLOR_TYPE = 0x30, + COLOR_CONST = 0x40, + COLOR_REM = 0x50, + COLOR_KEY = 0x60, + COLOR_TABLE = 0x70, +}; + +const int FONT_MASK = 0x03; +const int TITLE_MASK = 0x0c; +const int COLOR_MASK = 0x70; +const int IMAGE_MASK = 0x80; + + + +class CText +{ +public: + CText(CInstanceManager *iMan, CD3DEngine* engine); + ~CText(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + + void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol); + void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol); + void DrawText(char *string, int len, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol); + void DrawText(char *string, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol); + void DimText(char *string, char *format, int len, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end); + void DimText(char *string, char *format, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end); + void DimText(char *string, int len, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end); + void DimText(char *string, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end); + + float RetAscent(float size, FontType font); + float RetDescent(float size, FontType font); + float RetHeight(float size, FontType font); + + float RetStringWidth(char *string, char *format, int len, float size, float stretch); + float RetStringWidth(char *string, int len, float size, float stretch, FontType font); + float RetCharWidth(int character, float offset, float size, float stretch, FontType font); + + int Justif(char *string, char *format, int len, float width, float size, float stretch); + int Justif(char *string, int len, float width, float size, float stretch, FontType font); + int Detect(char *string, char *format, int len, float offset, float size, float stretch); + int Detect(char *string, int len, float offset, float size, float stretch, FontType font); + +protected: + void DrawString(char *string, char *format, int len, Math::Point pos, float width, float size, float stretch, int eol); + void DrawString(char *string, int len, Math::Point pos, float width, float size, float stretch, FontType font, int eol); + void DrawColor(Math::Point pos, float size, float width, int color); + void DrawChar(int character, Math::Point pos, float size, float stretch, FontType font); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + LPDIRECT3DDEVICE7 m_pD3DDevice; + +}; + diff --git a/src/old/water.cpp b/src/old/water.cpp index 215bac9..dfde09e 100644 --- a/src/old/water.cpp +++ b/src/old/water.cpp @@ -1,844 +1,844 @@ -// * 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/. - -// water.cpp - - -#include -#include -#include - -#include "common/struct.h" -#include "math/geometry.h" -#include "math/conv.h" -#include "old/d3dengine.h" -#include "old/d3dmath.h" -#include "old/d3dutil.h" -#include "common/event.h" -#include "common/misc.h" -#include "common/iman.h" -#include "old/math3d.h" -#include "old/particule.h" -#include "old/terrain.h" -#include "object/object.h" -#include "old/sound.h" -#include "old/water.h" - - - - -// Constructor of the terrain. - -CWater::CWater(CInstanceManager* iMan, CD3DEngine* engine) -{ - m_iMan = iMan; - m_iMan->AddInstance(CLASS_WATER, this); - - m_engine = engine; - m_terrain = 0; - m_particule = 0; - m_sound = 0; - - m_type[0] = WATER_NULL; - m_type[1] = WATER_NULL; - m_level = 0.0f; - m_bDraw = true; - m_bLava = false; - m_color = 0xffffffff; - m_subdiv = 4; - m_filename[0] = 0; -} - -// Destructor of the terrain. - -CWater::~CWater() -{ -} - - -bool CWater::EventProcess(const Event &event) -{ - if ( event.event == EVENT_FRAME ) - { - return EventFrame(event); - } - - if ( event.event == EVENT_KEYDOWN ) - { -#if 0 - if ( event.param == 'S' ) - { - if ( m_subdiv == 1 ) m_subdiv = 2; - else if ( m_subdiv == 2 ) m_subdiv = 4; - else if ( m_subdiv == 4 ) m_subdiv = 8; - else if ( m_subdiv == 8 ) m_subdiv = 1; - SetLevel(m_level); - } - if ( event.param == 'M' ) - { - SetLevel(m_level+1.0f); - } - if ( event.param == 'D' ) - { - SetLevel(m_level-1.0f); - } - if ( event.param == 'H' ) - { - m_bDraw = !m_bDraw; - } - if ( event.param == 'C' ) - { - if ( m_color == 0xffffffff ) m_color = 0xcccccccc; - else if ( m_color == 0xcccccccc ) m_color = 0x88888888; - else if ( m_color == 0x88888888 ) m_color = 0x44444444; - else if ( m_color == 0x44444444 ) m_color = 0x00000000; - else if ( m_color == 0x00000000 ) m_color = 0xffffffff; - } - if ( event.param == 'Q' ) - { - int i; - i = (m_color>>24); - i += 0x44; - i &= 0xff; - i = (i<<24); - m_color &= 0x00ffffff; - m_color |= i; - } - if ( event.param == 'W' ) - { - int i; - i = (m_color>>16); - i += 0x44; - i &= 0xff; - i = (i<<16); - m_color &= 0xff00ffff; - m_color |= i; - } - if ( event.param == 'E' ) - { - int i; - i = (m_color>>8); - i += 0x44; - i &= 0xff; - i = (i<<8); - m_color &= 0xffff00ff; - m_color |= i; - } - if ( event.param == 'R' ) - { - int i; - i = m_color; - i += 0x44; - i &= 0xff; - m_color &= 0xffffff00; - m_color |= i; - } -#endif - } - return true; -} - -// Makes water evolve. - -bool CWater::EventFrame(const Event &event) -{ - if ( m_engine->RetPause() ) return true; - - m_time += event.rTime; - - if ( m_type[0] == WATER_NULL ) return true; - - if ( m_bLava ) - { - LavaFrame(event.rTime); - } - return true; -} - -// Makes evolve the steam jets on the lava. - -void CWater::LavaFrame(float rTime) -{ - Math::Vector eye, lookat, dir, perp, pos; - float distance, shift, level; - int i; - - if ( m_particule == 0 ) - { - m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); - } - - for ( i=0 ; i= 0.1f ) - { - eye = m_engine->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - distance = Math::Rand()*200.0f; - shift = (Math::Rand()-0.5f)*200.0f; - - dir = Normalize(lookat-eye); - pos = eye + dir*distance; - - perp.x = -dir.z; - perp.y = dir.y; - perp.z = dir.x; - pos = pos + perp*shift; - - level = m_terrain->RetFloorLevel(pos, true); - if ( level < m_level ) - { - pos.y = m_level; - - level = Math::Rand(); - if ( level < 0.8f ) - { - if ( VaporCreate(PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) ) - { - m_lastLava = m_time; - } - } - else if ( level < 0.9f ) - { - if ( VaporCreate(PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) ) - { - m_lastLava = m_time; - } - } - else - { - if ( VaporCreate(PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) ) - { - m_lastLava = m_time; - } - } - } - } -} - -// Removes all the steam jets. - -void CWater::VaporFlush() -{ - int i; - - for ( i=0 ; iPlay(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f); - } - if ( m_vapor[i].type == PARTIFLAME ) - { -//? m_sound->Play(SOUND_SWIM, pos, 1.0f, 1.0f-Math::Rand()*0.5f); - } - if ( m_vapor[i].type == PARTIVAPOR ) - { - m_sound->Play(SOUND_PSHHH, pos, 0.3f, 2.0f); - } - - return true; - } - } - return false; -} - -// Makes evolve a steam jet, - -void CWater::VaporFrame(int i, float rTime) -{ - Math::Vector pos, speed; - Math::Point dim; - int j; - - m_vapor[i].time += rTime; - - if ( m_sound == 0 ) - { - m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); - } - - if ( m_vapor[i].time <= m_vapor[i].delay ) - { - if ( m_time-m_vapor[i].last >= m_engine->ParticuleAdapt(0.02f) ) - { - m_vapor[i].last = m_time; - - if ( m_vapor[i].type == PARTIFIRE ) - { - for ( j=0 ; j<10 ; j++ ) - { - pos = m_vapor[i].pos; - pos.x += (Math::Rand()-0.5f)*2.0f; - pos.z += (Math::Rand()-0.5f)*2.0f; - pos.y -= 1.0f; - speed.x = (Math::Rand()-0.5f)*6.0f; - speed.z = (Math::Rand()-0.5f)*6.0f; - speed.y = 8.0f+Math::Rand()*5.0f; - dim.x = Math::Rand()*1.5f+1.5f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 2.0f, 10.0f); - } - } - else if ( m_vapor[i].type == PARTIFLAME ) - { - pos = m_vapor[i].pos; - pos.x += (Math::Rand()-0.5f)*8.0f; - pos.z += (Math::Rand()-0.5f)*8.0f; - pos.y -= 2.0f; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 4.0f+Math::Rand()*4.0f; - dim.x = Math::Rand()*2.0f+2.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIFLAME); - } - else - { - pos = m_vapor[i].pos; - pos.x += (Math::Rand()-0.5f)*4.0f; - pos.z += (Math::Rand()-0.5f)*4.0f; - pos.y -= 2.0f; - speed.x = (Math::Rand()-0.5f)*2.0f; - speed.z = (Math::Rand()-0.5f)*2.0f; - speed.y = 8.0f+Math::Rand()*8.0f; - dim.x = Math::Rand()*1.0f+1.0f; - dim.y = dim.x; - m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR); - } - } - } - else - { - m_vapor[i].bUsed = false; - } -} - - -// Adjusts the position to normal, to imitate reflections on an expanse of water at rest. - -void CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm, - Math::Point &uv1, Math::Point &uv2) -{ -#if 0 - float t1, t2; - - uv1.x = (pos.x+10000.0f)/40.0f; - uv1.y = (pos.z+10000.0f)/40.0f; - - t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; - pos.y += sinf(t1)*m_eddy.y; - - t1 = m_time*0.6f + pos.x*0.1f * pos.z*0.2f; - t2 = m_time*0.7f + pos.x*0.3f * pos.z*0.4f; - pos.x += sinf(t1)*m_eddy.x; - pos.z += sinf(t2)*m_eddy.z; - -//? uv2.x = (pos.x+10000.0f)/40.0f+0.3f; -//? uv2.y = (pos.z+10000.0f)/40.0f+0.4f; - uv2.x = (pos.x+10000.0f)/20.0f; - uv2.y = (pos.z+10000.0f)/20.0f; - - t1 = m_time*0.7f + pos.x*5.5f + pos.z*5.6f; - t2 = m_time*0.8f + pos.x*5.7f + pos.z*5.8f; - norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); -#else - float t1, t2; - - t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; - pos.y += sinf(t1)*m_eddy.y; - - t1 = m_time*1.5f; - uv1.x = (pos.x+10000.0f)/40.0f+sinf(t1)*m_eddy.x*0.02f; - uv1.y = (pos.z+10000.0f)/40.0f-cosf(t1)*m_eddy.z*0.02f; - uv2.x = (pos.x+10010.0f)/20.0f+cosf(-t1)*m_eddy.x*0.02f; - uv2.y = (pos.z+10010.0f)/20.0f-sinf(-t1)*m_eddy.z*0.02f; - - t1 = m_time*0.50f + pos.x*2.1f + pos.z*1.1f; - t2 = m_time*0.75f + pos.x*2.0f + pos.z*1.0f; - norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); -#endif -} - -// Draw the back surface of the water. -// This surface prevents to see the sky (background) underwater! - -void CWater::DrawBack() -{ - LPDIRECT3DDEVICE7 device; - D3DVERTEX2 vertex[4]; // 2 triangles - D3DMATERIAL7 material; - Math::Matrix matrix; - Math::Vector eye, lookat, n, p, p1, p2; - Math::Point uv1, uv2; - float deep, dist; - - if ( !m_bDraw ) return; - if ( m_type[0] == WATER_NULL ) return; - if ( m_lineUsed == 0 ) return; - - eye = m_engine->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - ZeroMemory( &material, sizeof(D3DMATERIAL7) ); - material.diffuse = m_diffuse; - material.ambient = m_ambient; - m_engine->SetMaterial(material); - - m_engine->SetTexture("", 0); - - device = m_engine->RetD3DDevice(); - device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); - device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - m_engine->SetState(D3DSTATENORMAL); - - deep = m_engine->RetDeepView(0); - m_engine->SetDeepView(deep*2.0f, 0); - m_engine->SetFocus(m_engine->RetFocus()); - m_engine->UpdateMatProj(); // twice the depth of view - - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - p.x = eye.x; - p.z = eye.z; - dist = Math::DistanceProjected(eye, lookat); - p.x = (lookat.x-eye.x)*deep*1.0f/dist + eye.x; - p.z = (lookat.z-eye.z)*deep*1.0f/dist + eye.z; - - p1.x = (lookat.z-eye.z)*deep*2.0f/dist + p.x; - p1.z = -(lookat.x-eye.x)*deep*2.0f/dist + p.z; - p2.x = -(lookat.z-eye.z)*deep*2.0f/dist + p.x; - p2.z = (lookat.x-eye.x)*deep*2.0f/dist + p.z; - - p1.y = -50.0f; - p2.y = m_level; - - n.x = (lookat.x-eye.x)/dist; - n.z = (lookat.z-eye.z)/dist; - n.y = 0.0f; - - uv1.x = uv1.y = 0.0f; - uv2.x = uv2.y = 0.0f; - - vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p2.y, p1.z), n, uv1.x,uv2.y); - vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p1.y, p1.z), n, uv1.x,uv1.y); - vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p2.y, p2.z), n, uv2.x,uv2.y); - vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p1.y, p2.z), n, uv2.x,uv1.y); - - device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); - m_engine->AddStatisticTriangle(2); - - m_engine->SetDeepView(deep, 0); - m_engine->SetFocus(m_engine->RetFocus()); - m_engine->UpdateMatProj(); // gives the initial depth of view - - device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); - device->SetRenderState(D3DRENDERSTATE_ZENABLE, true); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); -} - -// Draws the flat surface of the water. - -void CWater::DrawSurf() -{ - LPDIRECT3DDEVICE7 device; - D3DVERTEX2* vertex; // triangles - D3DMATERIAL7 material; - Math::Matrix matrix; - Math::Vector eye, lookat, n, pos, p; - Math::Point uv1, uv2; - bool bUnder; - DWORD flags; - float deep, size, sizez, radius; - int rankview, i, j, u; - - if ( !m_bDraw ) return; - if ( m_type[0] == WATER_NULL ) return; - if ( m_lineUsed == 0 ) return; - - vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); - - eye = m_engine->RetEyePt(); - lookat = m_engine->RetLookatPt(); - - rankview = m_engine->RetRankView(); - bUnder = ( rankview == 1); - - device = m_engine->RetD3DDevice(); -//? device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); -//? device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); -//? device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); - device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); - - matrix.LoadIdentity(); - { - D3DMATRIX mat = MAT_TO_D3DMAT(matrix); - device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); - } - - ZeroMemory( &material, sizeof(D3DMATERIAL7) ); - material.diffuse = m_diffuse; - material.ambient = m_ambient; - m_engine->SetMaterial(material); - - m_engine->SetTexture(m_filename, 0); - m_engine->SetTexture(m_filename, 1); - - if ( m_type[rankview] == WATER_TT ) - { - m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP, m_color); - } - if ( m_type[rankview] == WATER_TO ) - { - m_engine->SetState(D3DSTATENORMAL|D3DSTATEDUALw|D3DSTATEWRAP); - } - if ( m_type[rankview] == WATER_CT ) - { - m_engine->SetState(D3DSTATETTb); - } - if ( m_type[rankview] == WATER_CO ) - { - m_engine->SetState(D3DSTATENORMAL); - } - device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true); - - size = m_size/2.0f; - if ( bUnder ) sizez = -size; - else sizez = size; - - // Draws all the lines. - deep = m_engine->RetDeepView(0)*1.5f; - - for ( i=0 ; i deep+radius ) continue; - - D3DVECTOR pD3D = VEC_TO_D3DVEC(p); - device->ComputeSphereVisibility(&pD3D, &radius, 1, 0, &flags); - - if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue; - - u = 0; - p.x = pos.x-size; - p.z = pos.z-sizez; - p.y = pos.y; - AdjustLevel(p, n, uv1, uv2); - if ( bUnder ) n.y = -n.y; - vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y); - - p.x = pos.x-size; - p.z = pos.z+sizez; - p.y = pos.y; - AdjustLevel(p, n, uv1, uv2); - if ( bUnder ) n.y = -n.y; - vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y); - - for ( j=0 ; jDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); - m_engine->AddStatisticTriangle(u-2); - } - - free(vertex); -} - - -// Indicates if there is water in a given position. - -bool CWater::RetWater(int x, int y) -{ - Math::Vector pos; - float size, offset, level; - int dx, dy; - - x *= m_subdiv; - y *= m_subdiv; - - size = m_size/m_subdiv; - offset = m_brick*m_size/2.0f; - - for ( dy=0 ; dy<=m_subdiv ; dy++ ) - { - for ( dx=0 ; dx<=m_subdiv ; dx++ ) - { - pos.x = (x+dx)*size - offset; - pos.z = (y+dy)*size - offset; - pos.y = 0.0f; - level = m_terrain->RetFloorLevel(pos, true); - if ( level < m_level+m_eddy.y ) return true; - } - } - return false; -} - -// Updates the positions, relative to the ground. - -bool CWater::CreateLine(int x, int y, int len) -{ - float offset; - - m_line[m_lineUsed].x = x; - m_line[m_lineUsed].y = y; - m_line[m_lineUsed].len = len; - - offset = m_brick*m_size/2.0f - m_size/2.0f; - - m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; - m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; - m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; - - m_lineUsed ++; - - return ( m_lineUsed < MAXWATERLINE ); -} - -// Creates all expanses of water. - -bool CWater::Create(WaterType type1, WaterType type2, const char *filename, - D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, - float level, float glint, Math::Vector eddy) -{ - int x, y, len; - - m_type[0] = type1; - m_type[1] = type2; - m_diffuse = diffuse; - m_ambient = ambient; - m_level = level; - m_glint = glint; - m_eddy = eddy; - m_time = 0.0f; - m_lastLava = 0.0f; - strcpy(m_filename, filename); - - VaporFlush(); - - if ( m_filename[0] != 0 ) - { - m_engine->LoadTexture(m_filename, 0); - m_engine->LoadTexture(m_filename, 1); - } - - if ( m_terrain == 0 ) - { - m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); - } - m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic(); - m_size = m_terrain->RetSize(); - - m_brick /= m_subdiv; - m_size *= m_subdiv; - - if ( m_type[0] == WATER_NULL ) return true; - - m_lineUsed = 0; - for ( y=0 ; y= 5 ) - { - if ( !CreateLine(x-len+1, y, len) ) return false; - len = 0; - } - } - else // dry? - { - if ( len != 0 ) - { - if ( !CreateLine(x-len, y, len) ) return false; - len = 0; - } - } - } - if ( len != 0 ) - { - if ( !CreateLine(x-len, y, len) ) return false; - } - } - return true; -} - -// Removes all the water. - -void CWater::Flush() -{ - m_type[0] = WATER_NULL; - m_type[1] = WATER_NULL; - m_level = 0.0f; - m_bLava = false; -} - - -// Changes the level of the water. - -bool CWater::SetLevel(float level) -{ - m_level = level; - - return Create(m_type[0], m_type[1], m_filename, m_diffuse, m_ambient, - m_level, m_glint, m_eddy); -} - -// Returns the current level of water. - -float CWater::RetLevel() -{ - return m_level; -} - -// Returns the current level of water for a given object. - -float CWater::RetLevel(CObject* object) -{ - ObjectType type; - - type = object->RetType(); - - if ( type == OBJECT_HUMAN || - type == OBJECT_TECH ) - { - return m_level-3.0f; - } - - if ( type == OBJECT_MOBILEfa || - type == OBJECT_MOBILEta || - type == OBJECT_MOBILEwa || - type == OBJECT_MOBILEia || - type == OBJECT_MOBILEfc || - type == OBJECT_MOBILEtc || - type == OBJECT_MOBILEwc || - type == OBJECT_MOBILEic || - type == OBJECT_MOBILEfi || - type == OBJECT_MOBILEti || - type == OBJECT_MOBILEwi || - type == OBJECT_MOBILEii || - type == OBJECT_MOBILEfs || - type == OBJECT_MOBILEts || - type == OBJECT_MOBILEws || - type == OBJECT_MOBILEis || - type == OBJECT_MOBILErt || - type == OBJECT_MOBILErc || - type == OBJECT_MOBILErr || - type == OBJECT_MOBILErs || - type == OBJECT_MOBILEsa || - type == OBJECT_MOBILEtg || - type == OBJECT_MOBILEft || - type == OBJECT_MOBILEtt || - type == OBJECT_MOBILEwt || - type == OBJECT_MOBILEit || - type == OBJECT_MOBILEdr ) - { - return m_level-2.0f; - } - - return m_level; -} - - -// Management of the mode of lava/water. - -void CWater::SetLava(bool bLava) -{ - m_bLava = bLava; -} - -bool CWater::RetLava() -{ - return m_bLava; -} - - -// Adjusts the eye of the camera, not to be in the water. - -void CWater::AdjustEye(Math::Vector &eye) -{ - if ( m_bLava ) - { - if ( eye.y < m_level+2.0f ) - { - eye.y = m_level+2.0f; // never under the lava - } - } - else - { - if ( eye.y >= m_level-2.0f && - eye.y <= m_level+2.0f ) // close to the surface? - { - eye.y = m_level+2.0f; // bam, well above - } - } -} - +// * 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/. + +// water.cpp + + +#include +#include +#include + +#include "common/struct.h" +#include "math/geometry.h" +#include "math/conv.h" +#include "old/d3dengine.h" +#include "old/d3dmath.h" +#include "old/d3dutil.h" +#include "common/event.h" +#include "common/misc.h" +#include "common/iman.h" +#include "old/math3d.h" +#include "old/particule.h" +#include "old/terrain.h" +#include "object/object.h" +#include "old/sound.h" +#include "old/water.h" + + + + +// Constructor of the terrain. + +CWater::CWater(CInstanceManager* iMan, CD3DEngine* engine) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_WATER, this); + + m_engine = engine; + m_terrain = 0; + m_particule = 0; + m_sound = 0; + + m_type[0] = WATER_NULL; + m_type[1] = WATER_NULL; + m_level = 0.0f; + m_bDraw = true; + m_bLava = false; + m_color = 0xffffffff; + m_subdiv = 4; + m_filename[0] = 0; +} + +// Destructor of the terrain. + +CWater::~CWater() +{ +} + + +bool CWater::EventProcess(const Event &event) +{ + if ( event.event == EVENT_FRAME ) + { + return EventFrame(event); + } + + if ( event.event == EVENT_KEYDOWN ) + { +#if 0 + if ( event.param == 'S' ) + { + if ( m_subdiv == 1 ) m_subdiv = 2; + else if ( m_subdiv == 2 ) m_subdiv = 4; + else if ( m_subdiv == 4 ) m_subdiv = 8; + else if ( m_subdiv == 8 ) m_subdiv = 1; + SetLevel(m_level); + } + if ( event.param == 'M' ) + { + SetLevel(m_level+1.0f); + } + if ( event.param == 'D' ) + { + SetLevel(m_level-1.0f); + } + if ( event.param == 'H' ) + { + m_bDraw = !m_bDraw; + } + if ( event.param == 'C' ) + { + if ( m_color == 0xffffffff ) m_color = 0xcccccccc; + else if ( m_color == 0xcccccccc ) m_color = 0x88888888; + else if ( m_color == 0x88888888 ) m_color = 0x44444444; + else if ( m_color == 0x44444444 ) m_color = 0x00000000; + else if ( m_color == 0x00000000 ) m_color = 0xffffffff; + } + if ( event.param == 'Q' ) + { + int i; + i = (m_color>>24); + i += 0x44; + i &= 0xff; + i = (i<<24); + m_color &= 0x00ffffff; + m_color |= i; + } + if ( event.param == 'W' ) + { + int i; + i = (m_color>>16); + i += 0x44; + i &= 0xff; + i = (i<<16); + m_color &= 0xff00ffff; + m_color |= i; + } + if ( event.param == 'E' ) + { + int i; + i = (m_color>>8); + i += 0x44; + i &= 0xff; + i = (i<<8); + m_color &= 0xffff00ff; + m_color |= i; + } + if ( event.param == 'R' ) + { + int i; + i = m_color; + i += 0x44; + i &= 0xff; + m_color &= 0xffffff00; + m_color |= i; + } +#endif + } + return true; +} + +// Makes water evolve. + +bool CWater::EventFrame(const Event &event) +{ + if ( m_engine->RetPause() ) return true; + + m_time += event.rTime; + + if ( m_type[0] == WATER_NULL ) return true; + + if ( m_bLava ) + { + LavaFrame(event.rTime); + } + return true; +} + +// Makes evolve the steam jets on the lava. + +void CWater::LavaFrame(float rTime) +{ + Math::Vector eye, lookat, dir, perp, pos; + float distance, shift, level; + int i; + + if ( m_particule == 0 ) + { + m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE); + } + + for ( i=0 ; i= 0.1f ) + { + eye = m_engine->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + distance = Math::Rand()*200.0f; + shift = (Math::Rand()-0.5f)*200.0f; + + dir = Normalize(lookat-eye); + pos = eye + dir*distance; + + perp.x = -dir.z; + perp.y = dir.y; + perp.z = dir.x; + pos = pos + perp*shift; + + level = m_terrain->RetFloorLevel(pos, true); + if ( level < m_level ) + { + pos.y = m_level; + + level = Math::Rand(); + if ( level < 0.8f ) + { + if ( VaporCreate(PARTIFIRE, pos, 0.02f+Math::Rand()*0.06f) ) + { + m_lastLava = m_time; + } + } + else if ( level < 0.9f ) + { + if ( VaporCreate(PARTIFLAME, pos, 0.5f+Math::Rand()*3.0f) ) + { + m_lastLava = m_time; + } + } + else + { + if ( VaporCreate(PARTIVAPOR, pos, 0.2f+Math::Rand()*2.0f) ) + { + m_lastLava = m_time; + } + } + } + } +} + +// Removes all the steam jets. + +void CWater::VaporFlush() +{ + int i; + + for ( i=0 ; iPlay(SOUND_BLUP, pos, 1.0f, 1.0f-Math::Rand()*0.5f); + } + if ( m_vapor[i].type == PARTIFLAME ) + { +//? m_sound->Play(SOUND_SWIM, pos, 1.0f, 1.0f-Math::Rand()*0.5f); + } + if ( m_vapor[i].type == PARTIVAPOR ) + { + m_sound->Play(SOUND_PSHHH, pos, 0.3f, 2.0f); + } + + return true; + } + } + return false; +} + +// Makes evolve a steam jet, + +void CWater::VaporFrame(int i, float rTime) +{ + Math::Vector pos, speed; + Math::Point dim; + int j; + + m_vapor[i].time += rTime; + + if ( m_sound == 0 ) + { + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + } + + if ( m_vapor[i].time <= m_vapor[i].delay ) + { + if ( m_time-m_vapor[i].last >= m_engine->ParticuleAdapt(0.02f) ) + { + m_vapor[i].last = m_time; + + if ( m_vapor[i].type == PARTIFIRE ) + { + for ( j=0 ; j<10 ; j++ ) + { + pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*2.0f; + pos.z += (Math::Rand()-0.5f)*2.0f; + pos.y -= 1.0f; + speed.x = (Math::Rand()-0.5f)*6.0f; + speed.z = (Math::Rand()-0.5f)*6.0f; + speed.y = 8.0f+Math::Rand()*5.0f; + dim.x = Math::Rand()*1.5f+1.5f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 2.0f, 10.0f); + } + } + else if ( m_vapor[i].type == PARTIFLAME ) + { + pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*8.0f; + pos.z += (Math::Rand()-0.5f)*8.0f; + pos.y -= 2.0f; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 4.0f+Math::Rand()*4.0f; + dim.x = Math::Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIFLAME); + } + else + { + pos = m_vapor[i].pos; + pos.x += (Math::Rand()-0.5f)*4.0f; + pos.z += (Math::Rand()-0.5f)*4.0f; + pos.y -= 2.0f; + speed.x = (Math::Rand()-0.5f)*2.0f; + speed.z = (Math::Rand()-0.5f)*2.0f; + speed.y = 8.0f+Math::Rand()*8.0f; + dim.x = Math::Rand()*1.0f+1.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR); + } + } + } + else + { + m_vapor[i].bUsed = false; + } +} + + +// Adjusts the position to normal, to imitate reflections on an expanse of water at rest. + +void CWater::AdjustLevel(Math::Vector &pos, Math::Vector &norm, + Math::Point &uv1, Math::Point &uv2) +{ +#if 0 + float t1, t2; + + uv1.x = (pos.x+10000.0f)/40.0f; + uv1.y = (pos.z+10000.0f)/40.0f; + + t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; + pos.y += sinf(t1)*m_eddy.y; + + t1 = m_time*0.6f + pos.x*0.1f * pos.z*0.2f; + t2 = m_time*0.7f + pos.x*0.3f * pos.z*0.4f; + pos.x += sinf(t1)*m_eddy.x; + pos.z += sinf(t2)*m_eddy.z; + +//? uv2.x = (pos.x+10000.0f)/40.0f+0.3f; +//? uv2.y = (pos.z+10000.0f)/40.0f+0.4f; + uv2.x = (pos.x+10000.0f)/20.0f; + uv2.y = (pos.z+10000.0f)/20.0f; + + t1 = m_time*0.7f + pos.x*5.5f + pos.z*5.6f; + t2 = m_time*0.8f + pos.x*5.7f + pos.z*5.8f; + norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); +#else + float t1, t2; + + t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f; + pos.y += sinf(t1)*m_eddy.y; + + t1 = m_time*1.5f; + uv1.x = (pos.x+10000.0f)/40.0f+sinf(t1)*m_eddy.x*0.02f; + uv1.y = (pos.z+10000.0f)/40.0f-cosf(t1)*m_eddy.z*0.02f; + uv2.x = (pos.x+10010.0f)/20.0f+cosf(-t1)*m_eddy.x*0.02f; + uv2.y = (pos.z+10010.0f)/20.0f-sinf(-t1)*m_eddy.z*0.02f; + + t1 = m_time*0.50f + pos.x*2.1f + pos.z*1.1f; + t2 = m_time*0.75f + pos.x*2.0f + pos.z*1.0f; + norm = Math::Vector(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint); +#endif +} + +// Draw the back surface of the water. +// This surface prevents to see the sky (background) underwater! + +void CWater::DrawBack() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2 vertex[4]; // 2 triangles + D3DMATERIAL7 material; + Math::Matrix matrix; + Math::Vector eye, lookat, n, p, p1, p2; + Math::Point uv1, uv2; + float deep, dist; + + if ( !m_bDraw ) return; + if ( m_type[0] == WATER_NULL ) return; + if ( m_lineUsed == 0 ) return; + + eye = m_engine->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + m_engine->SetTexture("", 0); + + device = m_engine->RetD3DDevice(); + device->SetRenderState(D3DRENDERSTATE_LIGHTING, false); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + m_engine->SetState(D3DSTATENORMAL); + + deep = m_engine->RetDeepView(0); + m_engine->SetDeepView(deep*2.0f, 0); + m_engine->SetFocus(m_engine->RetFocus()); + m_engine->UpdateMatProj(); // twice the depth of view + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + p.x = eye.x; + p.z = eye.z; + dist = Math::DistanceProjected(eye, lookat); + p.x = (lookat.x-eye.x)*deep*1.0f/dist + eye.x; + p.z = (lookat.z-eye.z)*deep*1.0f/dist + eye.z; + + p1.x = (lookat.z-eye.z)*deep*2.0f/dist + p.x; + p1.z = -(lookat.x-eye.x)*deep*2.0f/dist + p.z; + p2.x = -(lookat.z-eye.z)*deep*2.0f/dist + p.x; + p2.z = (lookat.x-eye.x)*deep*2.0f/dist + p.z; + + p1.y = -50.0f; + p2.y = m_level; + + n.x = (lookat.x-eye.x)/dist; + n.z = (lookat.z-eye.z)/dist; + n.y = 0.0f; + + uv1.x = uv1.y = 0.0f; + uv2.x = uv2.y = 0.0f; + + vertex[0] = D3DVERTEX2(Math::Vector(p1.x, p2.y, p1.z), n, uv1.x,uv2.y); + vertex[1] = D3DVERTEX2(Math::Vector(p1.x, p1.y, p1.z), n, uv1.x,uv1.y); + vertex[2] = D3DVERTEX2(Math::Vector(p2.x, p2.y, p2.z), n, uv2.x,uv2.y); + vertex[3] = D3DVERTEX2(Math::Vector(p2.x, p1.y, p2.z), n, uv2.x,uv1.y); + + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + m_engine->SetDeepView(deep, 0); + m_engine->SetFocus(m_engine->RetFocus()); + m_engine->UpdateMatProj(); // gives the initial depth of view + + device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); + device->SetRenderState(D3DRENDERSTATE_ZENABLE, true); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); +} + +// Draws the flat surface of the water. + +void CWater::DrawSurf() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2* vertex; // triangles + D3DMATERIAL7 material; + Math::Matrix matrix; + Math::Vector eye, lookat, n, pos, p; + Math::Point uv1, uv2; + bool bUnder; + DWORD flags; + float deep, size, sizez, radius; + int rankview, i, j, u; + + if ( !m_bDraw ) return; + if ( m_type[0] == WATER_NULL ) return; + if ( m_lineUsed == 0 ) return; + + vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2); + + eye = m_engine->RetEyePt(); + lookat = m_engine->RetLookatPt(); + + rankview = m_engine->RetRankView(); + bUnder = ( rankview == 1); + + device = m_engine->RetD3DDevice(); +//? device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff); +//? device->SetRenderState(D3DRENDERSTATE_LIGHTING, true); +//? device->SetRenderState(D3DRENDERSTATE_ZENABLE, false); + device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false); + + matrix.LoadIdentity(); + { + D3DMATRIX mat = MAT_TO_D3DMAT(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &mat); + } + + ZeroMemory( &material, sizeof(D3DMATERIAL7) ); + material.diffuse = m_diffuse; + material.ambient = m_ambient; + m_engine->SetMaterial(material); + + m_engine->SetTexture(m_filename, 0); + m_engine->SetTexture(m_filename, 1); + + if ( m_type[rankview] == WATER_TT ) + { + m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP, m_color); + } + if ( m_type[rankview] == WATER_TO ) + { + m_engine->SetState(D3DSTATENORMAL|D3DSTATEDUALw|D3DSTATEWRAP); + } + if ( m_type[rankview] == WATER_CT ) + { + m_engine->SetState(D3DSTATETTb); + } + if ( m_type[rankview] == WATER_CO ) + { + m_engine->SetState(D3DSTATENORMAL); + } + device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true); + + size = m_size/2.0f; + if ( bUnder ) sizez = -size; + else sizez = size; + + // Draws all the lines. + deep = m_engine->RetDeepView(0)*1.5f; + + for ( i=0 ; i deep+radius ) continue; + + D3DVECTOR pD3D = VEC_TO_D3DVEC(p); + device->ComputeSphereVisibility(&pD3D, &radius, 1, 0, &flags); + + if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue; + + u = 0; + p.x = pos.x-size; + p.z = pos.z-sizez; + p.y = pos.y; + AdjustLevel(p, n, uv1, uv2); + if ( bUnder ) n.y = -n.y; + vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y); + + p.x = pos.x-size; + p.z = pos.z+sizez; + p.y = pos.y; + AdjustLevel(p, n, uv1, uv2); + if ( bUnder ) n.y = -n.y; + vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y); + + for ( j=0 ; jDrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL); + m_engine->AddStatisticTriangle(u-2); + } + + free(vertex); +} + + +// Indicates if there is water in a given position. + +bool CWater::RetWater(int x, int y) +{ + Math::Vector pos; + float size, offset, level; + int dx, dy; + + x *= m_subdiv; + y *= m_subdiv; + + size = m_size/m_subdiv; + offset = m_brick*m_size/2.0f; + + for ( dy=0 ; dy<=m_subdiv ; dy++ ) + { + for ( dx=0 ; dx<=m_subdiv ; dx++ ) + { + pos.x = (x+dx)*size - offset; + pos.z = (y+dy)*size - offset; + pos.y = 0.0f; + level = m_terrain->RetFloorLevel(pos, true); + if ( level < m_level+m_eddy.y ) return true; + } + } + return false; +} + +// Updates the positions, relative to the ground. + +bool CWater::CreateLine(int x, int y, int len) +{ + float offset; + + m_line[m_lineUsed].x = x; + m_line[m_lineUsed].y = y; + m_line[m_lineUsed].len = len; + + offset = m_brick*m_size/2.0f - m_size/2.0f; + + m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset; + m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset; + m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset; + + m_lineUsed ++; + + return ( m_lineUsed < MAXWATERLINE ); +} + +// Creates all expanses of water. + +bool CWater::Create(WaterType type1, WaterType type2, const char *filename, + D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, + float level, float glint, Math::Vector eddy) +{ + int x, y, len; + + m_type[0] = type1; + m_type[1] = type2; + m_diffuse = diffuse; + m_ambient = ambient; + m_level = level; + m_glint = glint; + m_eddy = eddy; + m_time = 0.0f; + m_lastLava = 0.0f; + strcpy(m_filename, filename); + + VaporFlush(); + + if ( m_filename[0] != 0 ) + { + m_engine->LoadTexture(m_filename, 0); + m_engine->LoadTexture(m_filename, 1); + } + + if ( m_terrain == 0 ) + { + m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); + } + m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic(); + m_size = m_terrain->RetSize(); + + m_brick /= m_subdiv; + m_size *= m_subdiv; + + if ( m_type[0] == WATER_NULL ) return true; + + m_lineUsed = 0; + for ( y=0 ; y= 5 ) + { + if ( !CreateLine(x-len+1, y, len) ) return false; + len = 0; + } + } + else // dry? + { + if ( len != 0 ) + { + if ( !CreateLine(x-len, y, len) ) return false; + len = 0; + } + } + } + if ( len != 0 ) + { + if ( !CreateLine(x-len, y, len) ) return false; + } + } + return true; +} + +// Removes all the water. + +void CWater::Flush() +{ + m_type[0] = WATER_NULL; + m_type[1] = WATER_NULL; + m_level = 0.0f; + m_bLava = false; +} + + +// Changes the level of the water. + +bool CWater::SetLevel(float level) +{ + m_level = level; + + return Create(m_type[0], m_type[1], m_filename, m_diffuse, m_ambient, + m_level, m_glint, m_eddy); +} + +// Returns the current level of water. + +float CWater::RetLevel() +{ + return m_level; +} + +// Returns the current level of water for a given object. + +float CWater::RetLevel(CObject* object) +{ + ObjectType type; + + type = object->RetType(); + + if ( type == OBJECT_HUMAN || + type == OBJECT_TECH ) + { + return m_level-3.0f; + } + + if ( type == OBJECT_MOBILEfa || + type == OBJECT_MOBILEta || + type == OBJECT_MOBILEwa || + type == OBJECT_MOBILEia || + type == OBJECT_MOBILEfc || + type == OBJECT_MOBILEtc || + type == OBJECT_MOBILEwc || + type == OBJECT_MOBILEic || + type == OBJECT_MOBILEfi || + type == OBJECT_MOBILEti || + type == OBJECT_MOBILEwi || + type == OBJECT_MOBILEii || + type == OBJECT_MOBILEfs || + type == OBJECT_MOBILEts || + type == OBJECT_MOBILEws || + type == OBJECT_MOBILEis || + type == OBJECT_MOBILErt || + type == OBJECT_MOBILErc || + type == OBJECT_MOBILErr || + type == OBJECT_MOBILErs || + type == OBJECT_MOBILEsa || + type == OBJECT_MOBILEtg || + type == OBJECT_MOBILEft || + type == OBJECT_MOBILEtt || + type == OBJECT_MOBILEwt || + type == OBJECT_MOBILEit || + type == OBJECT_MOBILEdr ) + { + return m_level-2.0f; + } + + return m_level; +} + + +// Management of the mode of lava/water. + +void CWater::SetLava(bool bLava) +{ + m_bLava = bLava; +} + +bool CWater::RetLava() +{ + return m_bLava; +} + + +// Adjusts the eye of the camera, not to be in the water. + +void CWater::AdjustEye(Math::Vector &eye) +{ + if ( m_bLava ) + { + if ( eye.y < m_level+2.0f ) + { + eye.y = m_level+2.0f; // never under the lava + } + } + else + { + if ( eye.y >= m_level-2.0f && + eye.y <= m_level+2.0f ) // close to the surface? + { + eye.y = m_level+2.0f; // bam, well above + } + } +} + diff --git a/src/old/water.h b/src/old/water.h index b2a596b..8a68dd6 100644 --- a/src/old/water.h +++ b/src/old/water.h @@ -1,130 +1,130 @@ -// * 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/. - -// water.h - -#pragma once - - -#include "common/event.h" -#include "old/d3dengine.h" -#include "old/particule.h" - - -class CInstanceManager; -class CTerrain; -class CSound; - - - -const int MAXWATERLINE = 500; - -struct WaterLine -{ - short x, y; // beginning - short len; // length by x - float px1, px2, pz; -}; - - -const int MAXWATVAPOR = 10; - -struct WaterVapor -{ - bool bUsed; - ParticuleType type; - Math::Vector pos; - float delay; - float time; - float last; -}; - - -enum WaterType -{ - WATER_NULL = 0, // no water - WATER_TT = 1, // transparent texture - WATER_TO = 2, // opaque texture - WATER_CT = 3, // transparent color - WATER_CO = 4, // opaque color -}; - - -class CWater -{ -public: - CWater(CInstanceManager* iMan, CD3DEngine* engine); - ~CWater(); - - void SetD3DDevice(LPDIRECT3DDEVICE7 device); - bool EventProcess(const Event &event); - void Flush(); - bool Create(WaterType type1, WaterType type2, const char *filename, D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, float level, float glint, Math::Vector eddy); - void DrawBack(); - void DrawSurf(); - - bool SetLevel(float level); - float RetLevel(); - float RetLevel(CObject* object); - - void SetLava(bool bLava); - bool RetLava(); - - void AdjustEye(Math::Vector &eye); - -protected: - bool EventFrame(const Event &event); - void LavaFrame(float rTime); - void AdjustLevel(Math::Vector &pos, Math::Vector &norm, Math::Point &uv1, Math::Point &uv2); - bool RetWater(int x, int y); - bool CreateLine(int x, int y, int len); - - void VaporFlush(); - bool VaporCreate(ParticuleType type, Math::Vector pos, float delay); - void VaporFrame(int i, float rTime); - -protected: - CInstanceManager* m_iMan; - CD3DEngine* m_engine; - LPDIRECT3DDEVICE7 m_pD3DDevice; - CTerrain* m_terrain; - CParticule* m_particule; - CSound* m_sound; - - WaterType m_type[2]; - char m_filename[100]; - float m_level; // overall level - float m_glint; // amplitude of reflections - Math::Vector m_eddy; // amplitude of swirls - D3DCOLORVALUE m_diffuse; // diffuse color - D3DCOLORVALUE m_ambient; // ambient color - float m_time; - float m_lastLava; - int m_subdiv; - - int m_brick; // number of brick*mosaics - float m_size; // size of a item in an brick - - int m_lineUsed; - WaterLine m_line[MAXWATERLINE]; - - WaterVapor m_vapor[MAXWATVAPOR]; - - bool m_bDraw; - bool m_bLava; - D3DCOLOR m_color; -}; - +// * 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/. + +// water.h + +#pragma once + + +#include "common/event.h" +#include "old/d3dengine.h" +#include "old/particule.h" + + +class CInstanceManager; +class CTerrain; +class CSound; + + + +const int MAXWATERLINE = 500; + +struct WaterLine +{ + short x, y; // beginning + short len; // length by x + float px1, px2, pz; +}; + + +const int MAXWATVAPOR = 10; + +struct WaterVapor +{ + bool bUsed; + ParticuleType type; + Math::Vector pos; + float delay; + float time; + float last; +}; + + +enum WaterType +{ + WATER_NULL = 0, // no water + WATER_TT = 1, // transparent texture + WATER_TO = 2, // opaque texture + WATER_CT = 3, // transparent color + WATER_CO = 4, // opaque color +}; + + +class CWater +{ +public: + CWater(CInstanceManager* iMan, CD3DEngine* engine); + ~CWater(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + bool EventProcess(const Event &event); + void Flush(); + bool Create(WaterType type1, WaterType type2, const char *filename, D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, float level, float glint, Math::Vector eddy); + void DrawBack(); + void DrawSurf(); + + bool SetLevel(float level); + float RetLevel(); + float RetLevel(CObject* object); + + void SetLava(bool bLava); + bool RetLava(); + + void AdjustEye(Math::Vector &eye); + +protected: + bool EventFrame(const Event &event); + void LavaFrame(float rTime); + void AdjustLevel(Math::Vector &pos, Math::Vector &norm, Math::Point &uv1, Math::Point &uv2); + bool RetWater(int x, int y); + bool CreateLine(int x, int y, int len); + + void VaporFlush(); + bool VaporCreate(ParticuleType type, Math::Vector pos, float delay); + void VaporFrame(int i, float rTime); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + LPDIRECT3DDEVICE7 m_pD3DDevice; + CTerrain* m_terrain; + CParticule* m_particule; + CSound* m_sound; + + WaterType m_type[2]; + char m_filename[100]; + float m_level; // overall level + float m_glint; // amplitude of reflections + Math::Vector m_eddy; // amplitude of swirls + D3DCOLORVALUE m_diffuse; // diffuse color + D3DCOLORVALUE m_ambient; // ambient color + float m_time; + float m_lastLava; + int m_subdiv; + + int m_brick; // number of brick*mosaics + float m_size; // size of a item in an brick + + int m_lineUsed; + WaterLine m_line[MAXWATERLINE]; + + WaterVapor m_vapor[MAXWATVAPOR]; + + bool m_bDraw; + bool m_bLava; + D3DCOLOR m_color; +}; + -- cgit v1.2.3-1-g7c22