From 449cc186d5b8117d74ba22d6173497d00939f5f1 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sat, 28 Apr 2012 17:53:17 +0200 Subject: Source files split into modules --- src/graphics/common/blitz.cpp | 471 ++++ src/graphics/common/blitz.h | 84 + src/graphics/common/camera.cpp | 2109 ++++++++++++++++++ src/graphics/common/camera.h | 271 +++ src/graphics/common/cloud.cpp | 332 +++ src/graphics/common/cloud.h | 90 + src/graphics/common/light.cpp | 503 +++++ src/graphics/common/light.h | 113 + src/graphics/common/mainmovie.cpp | 249 +++ src/graphics/common/mainmovie.h | 80 + src/graphics/common/model.cpp | 3228 +++++++++++++++++++++++++++ src/graphics/common/model.h | 137 ++ src/graphics/common/particule.cpp | 4373 +++++++++++++++++++++++++++++++++++++ src/graphics/common/particule.h | 339 +++ src/graphics/common/planet.cpp | 248 +++ src/graphics/common/planet.h | 79 + src/graphics/common/pyro.cpp | 2486 +++++++++++++++++++++ src/graphics/common/pyro.h | 175 ++ src/graphics/common/terrain.cpp | 2270 +++++++++++++++++++ src/graphics/common/terrain.h | 214 ++ src/graphics/common/text.cpp | 1881 ++++++++++++++++ src/graphics/common/text.h | 113 + src/graphics/common/water.cpp | 835 +++++++ src/graphics/common/water.h | 134 ++ 24 files changed, 20814 insertions(+) create mode 100644 src/graphics/common/blitz.cpp create mode 100644 src/graphics/common/blitz.h create mode 100644 src/graphics/common/camera.cpp create mode 100644 src/graphics/common/camera.h create mode 100644 src/graphics/common/cloud.cpp create mode 100644 src/graphics/common/cloud.h create mode 100644 src/graphics/common/light.cpp create mode 100644 src/graphics/common/light.h create mode 100644 src/graphics/common/mainmovie.cpp create mode 100644 src/graphics/common/mainmovie.h create mode 100644 src/graphics/common/model.cpp create mode 100644 src/graphics/common/model.h create mode 100644 src/graphics/common/particule.cpp create mode 100644 src/graphics/common/particule.h create mode 100644 src/graphics/common/planet.cpp create mode 100644 src/graphics/common/planet.h create mode 100644 src/graphics/common/pyro.cpp create mode 100644 src/graphics/common/pyro.h create mode 100644 src/graphics/common/terrain.cpp create mode 100644 src/graphics/common/terrain.h create mode 100644 src/graphics/common/text.cpp create mode 100644 src/graphics/common/text.h create mode 100644 src/graphics/common/water.cpp create mode 100644 src/graphics/common/water.h (limited to 'src/graphics/common') diff --git a/src/graphics/common/blitz.cpp b/src/graphics/common/blitz.cpp new file mode 100644 index 0000000..cf88fe3 --- /dev/null +++ b/src/graphics/common/blitz.cpp @@ -0,0 +1,471 @@ +// * 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/. + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "d3dutil.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "terrain.h" +#include "math3d.h" +#include "object.h" +#include "camera.h" +#include "auto.h" +#include "autopara.h" +#include "sound.h" +#include "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 = (Rand()-0.5f)*(3200.0f-200.0f); + m_pos.z = (Rand()-0.5f)*(3200.0f-200.0f); +#else + m_pos.x = (Rand()-0.5f)*(3200.0f-2800.0f); + m_pos.z = (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 = Length(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 += (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] += (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+Rand()*m_delay); + } + } + + return TRUE; +} + + +// Draw lightning. + +void CBlitz::Draw() +{ + LPDIRECT3DDEVICE7 device; + D3DVERTEX2 vertex[4]; // 2 triangles + D3DVECTOR corner[4], eye, n, p, p1, p2; + D3DMATRIX matrix; + FPOINT 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); + + D3DUtil_SetIdentityMatrix(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + 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 = 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(D3DVECTOR pos) +{ + CObject *pObj, *pBest, *pObjPara[100]; + D3DVECTOR 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 = Length2d(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 = Length2d(oPos, pPos[i]); + if ( dist <= BLITZPARA ) + { + return pObjPara[i]; + } + } + return pBest; +} + diff --git a/src/graphics/common/blitz.h b/src/graphics/common/blitz.h new file mode 100644 index 0000000..30a34ed --- /dev/null +++ b/src/graphics/common/blitz.h @@ -0,0 +1,84 @@ +// * 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 + +#ifndef _BLITZ_H_ +#define _BLITZ_H_ + + +#include "misc.h" +#include "struct.h" + + +class CInstanceManager; +class CD3DEngine; +class CTerrain; +class CCamera; +class CSound; + + + +#define BLITZPARA 200.0f // radius of lightning protection +#define 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(D3DVECTOR 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; + D3DVECTOR m_pos; + FPOINT m_shift[BLITZMAX]; + float m_width[BLITZMAX]; +}; + + +#endif //_BLITZ_H_ diff --git a/src/graphics/common/camera.cpp b/src/graphics/common/camera.cpp new file mode 100644 index 0000000..e526d6c --- /dev/null +++ b/src/graphics/common/camera.cpp @@ -0,0 +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/. + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "language.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "terrain.h" +#include "water.h" +#include "object.h" +#include "physics.h" +#include "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 = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_actualLookat = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_finalEye = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_finalLookat = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_normEye = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_normLookat = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_focus = 1.0f; + + m_bRightDown = FALSE; + m_rightPosInit = FPOINT(0.5f, 0.5f); + m_rightPosCenter = FPOINT(0.5f, 0.5f); + m_rightPosMove = FPOINT(0.5f, 0.5f); + + m_eyePt = D3DVECTOR(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 = D3DVECTOR(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 = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_effectForce = 0.0f; + m_effectProgress = 0.0f; + m_effectOffset = D3DVECTOR(0.0f, 0.0f, 0.0f); + + m_scriptEye = D3DVECTOR(0.0f, 0.0f, 0.0f); + m_scriptLookat = D3DVECTOR(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(D3DVECTOR eye, D3DVECTOR lookat, float delay) +{ + D3DVECTOR 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 = RotateAngle(eye.x-lookat.x, eye.z-lookat.z)+PI/2.0f; + m_directionV = -RotateAngle(Length2d(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 = -PI*0.05f; + m_fixDist = 50.0f; + m_fixDirectionH = PI*0.25f; + m_fixDirectionV = -PI*0.10f; + m_centeringPhase = CP_NULL; + m_actualEye = m_eyePt; + m_actualLookat = 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; + D3DVECTOR 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 = D3DVECTOR(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 = LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + } + + if ( m_type == CAMERA_BACK && type == CAMERA_EDIT ) // back -> edit ? + { + m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_FREE ) // onboard -> free ? + { + m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_EDIT ) // onboard -> edit ? + { + m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); + } + + if ( m_type == CAMERA_ONBOARD && type == CAMERA_EXPLO ) // onboard -> explo ? + { + m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); + } + + if ( m_type == CAMERA_BACK && type == CAMERA_EXPLO ) // back -> explo ? + { + m_eyePt = 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 = -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 = 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(D3DVECTOR 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 = -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(D3DVECTOR &eye, D3DVECTOR &lookat) +{ + eye = m_eyePt; + lookat = 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 > PI ) + { + angleH = 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 = D3DVECTOR(0.0f, 0.0f, 0.0f); +} + +// Starts a special effect with the camera. + +void CCamera::StartEffect(CameraEffect effect, D3DVECTOR 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 = D3DVECTOR(0.0f, 0.0f, 0.0f); + force = m_effectForce; + + if ( m_effectType == CE_TERRAFORM ) + { + m_effectProgress += event.rTime*0.7f; + m_effectOffset.x = (Rand()-0.5f)*10.0f; + m_effectOffset.y = (Rand()-0.5f)*10.0f; + m_effectOffset.z = (Rand()-0.5f)*10.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == CE_EXPLO ) + { + m_effectProgress += event.rTime*1.0f; + m_effectOffset.x = (Rand()-0.5f)*5.0f; + m_effectOffset.y = (Rand()-0.5f)*5.0f; + m_effectOffset.z = (Rand()-0.5f)*5.0f; + + force *= 1.0f-m_effectProgress; + } + + if ( m_effectType == CE_SHOT ) + { + m_effectProgress += event.rTime*1.0f; + m_effectOffset.x = (Rand()-0.5f)*2.0f; + m_effectOffset.y = (Rand()-0.5f)*2.0f; + m_effectOffset.z = (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*PI)*1.5f; + m_effectOffset.x = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.z = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + } + + if ( m_effectType == CE_VIBRATION ) + { + m_effectProgress += event.rTime*0.1f; + m_effectOffset.y = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.x = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + m_effectOffset.z = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); + } + + if ( m_effectType == CE_PET ) + { + m_effectProgress += event.rTime*5.0f; + m_effectOffset.x = (Rand()-0.5f)*0.2f; + m_effectOffset.y = (Rand()-0.5f)*2.0f; + m_effectOffset.z = (Rand()-0.5f)*0.2f; + } + + dist = Length(m_eyePt, m_effectPos); + dist = 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, D3DVECTOR 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 = Length(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 D3DVECTOR &vEyePt, + const D3DVECTOR &vLookatPt, + float rTime) +{ + D3DVECTOR 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 = Length(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 = Length(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 = D3DVECTOR(0.0f, 1.0f, 0.0f); + SetViewParams(eye, lookat, vUpVec); +} + + +// Avoid the obstacles. + +BOOL CCamera::IsCollision(D3DVECTOR &eye, D3DVECTOR 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(D3DVECTOR &eye, D3DVECTOR lookat) +{ +#if 0 + CObject *pObj; + D3DVECTOR 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 = Min(eye.x, lookat.x); + min.y = Min(eye.y, lookat.y); + min.z = Min(eye.z, lookat.z); + + max.x = Max(eye.x, lookat.x); + max.y = Max(eye.y, lookat.y); + max.z = 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 = Length(oPos, lookat); + if ( dpl < oRadius ) continue; + } + + proj = Projection(eye, lookat, oPos); + dpp = Length(proj, oPos); + if ( dpp > oRadius ) continue; + + del = Length(eye, lookat); + len = Length(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 = Length(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; + D3DVECTOR 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 = Min(m_actualEye.x, m_actualLookat.x); + min.y = Min(m_actualEye.y, m_actualLookat.y); + min.z = Min(m_actualEye.z, m_actualLookat.z); + + max.x = Max(m_actualEye.x, m_actualLookat.x); + max.y = Max(m_actualEye.y, m_actualLookat.y); + max.z = 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 = Length(proj, oPos); + if ( dpp > oRadius ) continue; + + if ( oType == OBJECT_FACTORY ) + { + angle = RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW ! + angle = Direction(angle, pObj->RetAngleY(0)); + if ( Abs(angle) < 30.0f*PI/180.0f ) continue; // in the gate? + } + + del = Length(m_actualEye, m_actualLookat); + if ( oType == OBJECT_FACTORY ) + { + del += oRadius; + } + + len = Length(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(D3DVECTOR &eye, D3DVECTOR lookat) +{ + CObject *pObj; + D3DVECTOR 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 = Length(eye, oPos); + if ( dist < oRadius ) + { + dist = Length(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 = FPOINT(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 = -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(FPOINT 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) +{ + D3DVECTOR 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 = LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); + } + + // Up/Down. + m_eyePt = 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 = LookatPoint(m_eyePt, m_directionH+PI/2.0f, m_directionV, -event.axeX*event.rTime*factor*m_speed); + } + if ( event.axeX > 0.0f ) + { + m_eyePt = LookatPoint(m_eyePt, m_directionH-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 = 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) +{ + D3DVECTOR 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 = 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 = NormAngle(m_fixDirectionH); + + // Up/Down. +//? m_fixDirectionV -= m_mouseDirV*event.rTime*0.5f*m_speed; +//? if ( m_fixDirectionV < -PI*0.40f ) m_fixDirectionV = -PI*0.40f; +//? if ( m_fixDirectionV > PI*0.20f ) m_fixDirectionV = 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 = 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; + D3DVECTOR pos, vLookatPt; + FPOINT 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 = 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 += PI*0.20f; // nearly face + } + else // vehicle? + { + h += PI; // back + } + h = NormAngle(h)+m_remotePan; + v = 0.0f; //? + + h += m_centeringCurrentH; + h += m_addDirectionH*(1.0f-centeringH); + h = 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+PI/2.0f; + m_directionV = v; + } + + return TRUE; +} + +// Moves the point of view. + +BOOL CCamera::EventFrameFix(const Event &event) +{ + D3DVECTOR 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 = 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+PI/2.0f; + m_directionV = v; + } + + return TRUE; +} + +// Moves the point of view. + +BOOL CCamera::EventFrameExplo(const Event &event) +{ + D3DVECTOR 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 = 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) +{ + D3DVECTOR 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(D3DVECTOR(0.0f, 0.0f, 0.0f), + D3DVECTOR(0.0f, 0.0f, 1.0f), + event.rTime); + return TRUE; +} + +// Moves the point of view. + +BOOL CCamera::EventFrameVisit(const Event &event) +{ + D3DVECTOR 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 < -PI*0.40f ) m_visitDirectionV = -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)*(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(D3DVECTOR eye) +{ + m_scriptEye = eye; +} + +void CCamera::SetScriptLookat(D3DVECTOR lookat) +{ + m_scriptLookat = lookat; +} + + +// Specifies the location and direction of view. + +void CCamera::SetViewParams(const D3DVECTOR &eye, const D3DVECTOR &lookat, + const D3DVECTOR &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. + +D3DVECTOR CCamera::ExcludeTerrain(D3DVECTOR eye, D3DVECTOR lookat, + float &angleH, float &angleV) +{ + D3DVECTOR pos; + float dist; + + pos = eye; + if ( m_terrain->MoveOnFloor(pos) ) + { + dist = Length2d(lookat, pos); + pos.y += 2.0f+dist*0.1f; + if ( pos.y > eye.y ) + { + angleV = -RotateAngle(dist, pos.y-lookat.y); + eye = RotateView(lookat, angleH, angleV, dist); + } + } + return eye; +} + +// Adjusts the camera not to enter an object. + +D3DVECTOR CCamera::ExcludeObject(D3DVECTOR eye, D3DVECTOR lookat, + float &angleH, float &angleV) +{ + CObject* pObj; + D3DVECTOR 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 = Length(oPos, eye); + if ( dist < oRad+2.0f ) + { + eye.y = oPos.y+oRad+2.0f; + } + } + } + + return eye; +} + + diff --git a/src/graphics/common/camera.h b/src/graphics/common/camera.h new file mode 100644 index 0000000..f38db1a --- /dev/null +++ b/src/graphics/common/camera.h @@ -0,0 +1,271 @@ +// * 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 + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + + +#include "d3dengine.h" +#include "struct.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(D3DVECTOR eye, D3DVECTOR 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(D3DVECTOR goal, float dist); + void StopVisit(); + + void RetCamera(D3DVECTOR &eye, D3DVECTOR &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, D3DVECTOR pos, float force); + + void FlushOver(); + void SetOverBaseColor(D3DCOLORVALUE color); + void StartOver(OverEffect effect, D3DVECTOR pos, float force); + + void FixCamera(); + void SetScriptEye(D3DVECTOR eye); + void SetScriptLookat(D3DVECTOR lookat); + + void SetEffect(BOOL bEnable); + void SetCameraScroll(BOOL bScroll); + void SetCameraInvertX(BOOL bInvert); + void SetCameraInvertY(BOOL bInvert); + + float RetMotorTurn(); + D3DMouse RetMouseDef(FPOINT 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 D3DVECTOR &vEyePt, const D3DVECTOR &vLookatPt, float rTime); + BOOL IsCollision(D3DVECTOR &eye, D3DVECTOR lookat); + BOOL IsCollisionBack(D3DVECTOR &eye, D3DVECTOR lookat); + BOOL IsCollisionFix(D3DVECTOR &eye, D3DVECTOR lookat); + + D3DVECTOR ExcludeTerrain(D3DVECTOR eye, D3DVECTOR lookat, float &angleH, float &angleV); + D3DVECTOR ExcludeObject(D3DVECTOR eye, D3DVECTOR lookat, float &angleH, float &angleV); + + void SetViewParams(const D3DVECTOR &eye, const D3DVECTOR &lookat, const D3DVECTOR &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 + + D3DVECTOR m_actualEye; // current eye + D3DVECTOR m_actualLookat; // aim current + D3DVECTOR m_finalEye; // final eye + D3DVECTOR m_finalLookat; // aim final + D3DVECTOR m_normEye; // normal eye + D3DVECTOR m_normLookat; // aim normal + float m_focus; + + BOOL m_bRightDown; + FPOINT m_rightPosInit; + FPOINT m_rightPosCenter; + FPOINT m_rightPosMove; + + D3DVECTOR 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 + + D3DVECTOR 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; + + FPOINT 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; + D3DVECTOR m_effectPos; + float m_effectForce; + float m_effectProgress; + D3DVECTOR 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; + + D3DVECTOR m_scriptEye; + D3DVECTOR 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? +}; + + +#endif //_CAMERA_H_ diff --git a/src/graphics/common/cloud.cpp b/src/graphics/common/cloud.cpp new file mode 100644 index 0000000..8d6aeae --- /dev/null +++ b/src/graphics/common/cloud.cpp @@ -0,0 +1,332 @@ +// * 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/. + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "d3dutil.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "terrain.h" +#include "object.h" +#include "cloud.h" + + + +#define 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 = D3DVECTOR(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(D3DVECTOR &pos, D3DVECTOR &eye, float deep, + FPOINT &uv1, FPOINT &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 = Length2d(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; + D3DMATRIX* matView; + D3DMATERIAL7 material; + D3DMATRIX matrix; + D3DVECTOR n, pos, p, eye; + FPOINT 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(); + device->SetTransform(D3DTRANSFORMSTATE_VIEW, matView); + + 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); + + D3DUtil_SetIdentityMatrix(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + size = m_size/2.0f; + eye = m_engine->RetEyePt(); + n = D3DVECTOR(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 "struct.h" +#include "d3dengine.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "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, D3DVECTOR pos) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE; + + m_lightTable[lightRank].light.dvPosition = pos; + return TRUE; +} + +D3DVECTOR CLight::RetLightPos(int lightRank) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return D3DVECTOR(0.0f, 0.0f, 0.0f); + + return m_lightTable[lightRank].light.dvPosition; +} + + +// Management direction of the light. + +BOOL CLight::SetLightDir(int lightRank, D3DVECTOR dir) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE; + + m_lightTable[lightRank].light.dvDirection = dir; + return TRUE; +} + +D3DVECTOR CLight::RetLightDir(int lightRank) +{ + if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return D3DVECTOR(0.0f, 0.0f, 0.0f); + + return 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 = RotateAngle(dir.x, dir.z); + angle += 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/graphics/common/light.h b/src/graphics/common/light.h new file mode 100644 index 0000000..ae2bcfb --- /dev/null +++ b/src/graphics/common/light.h @@ -0,0 +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/. + +// light.h + +#ifndef _LIGHT_H_ +#define _LIGHT_H_ + + +#include "d3dengine.h" + + +class CInstanceManager; +class CD3DEngine; + + +#define D3DMAXLIGHT 100 + + +typedef struct +{ + float starting; + float ending; + float current; + float progress; + float speed; +} +LightProg; + + +typedef struct +{ + 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; +} +Light; + + + +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, D3DVECTOR pos); + D3DVECTOR RetLightPos(int lightRank); + + BOOL SetLightDir(int lightRank, D3DVECTOR dir); + D3DVECTOR 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; +}; + + +#endif //_LIGHT_H_ diff --git a/src/graphics/common/mainmovie.cpp b/src/graphics/common/mainmovie.cpp new file mode 100644 index 0000000..8205d16 --- /dev/null +++ b/src/graphics/common/mainmovie.cpp @@ -0,0 +1,249 @@ +// * 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/. + +// mainmovie.cpp + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "global.h" +#include "event.h" +#include "iman.h" +#include "math3d.h" +#include "camera.h" +#include "object.h" +#include "motion.h" +#include "motionhuman.h" +#include "interface.h" +#include "robotmain.h" +#include "sound.h" +#include "mainmovie.h" + + + + +// Constructor of the application card. + +CMainMovie::CMainMovie(CInstanceManager* iMan) +{ + m_iMan = iMan; + m_iMan->AddInstance(CLASS_SHORT, this); + + m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE); + m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT); + m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); + m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN); + m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA); + m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND); + + Flush(); +} + +// Destructor of the application card. + +CMainMovie::~CMainMovie() +{ +} + + +// Stops the current movie. + +void CMainMovie::Flush() +{ + m_type = MM_NONE; +} + + +// Start of a film. + +BOOL CMainMovie::Start(MainMovieType type, float time) +{ + D3DMATRIX* mat; + D3DVECTOR pos; + CObject* pObj; + CMotion* motion; + + m_type = type; + m_speed = 1.0f/time; + m_progress = 0.0f; + + if ( m_type == MM_SATCOMopen ) + { + pObj = m_main->SearchHuman(); + if ( pObj == 0 ) + { + m_type = MM_NONE; // it's over! + return TRUE; + } + + motion = pObj->RetMotion(); + if ( motion != 0 ) + { + motion->SetAction(MHS_SATCOM, 0.5f); // reads the SatCom + } + + m_camera->RetCamera(m_initialEye, m_initialLookat); + m_camera->SetType(CAMERA_SCRIPT); + m_camera->SetSmooth(CS_HARD); + m_camera->SetScriptEye(m_initialEye); + m_camera->SetScriptLookat(m_initialLookat); + m_camera->FixCamera(); + + mat = pObj->RetWorldMatrix(0); + m_finalLookat[0] = Transform(*mat, D3DVECTOR( 1.6f, 1.0f, 1.2f)); + m_finalEye[0] = Transform(*mat, D3DVECTOR(-1.5f, 5.0f, 3.0f)); + m_finalLookat[1] = Transform(*mat, D3DVECTOR( 1.6f, 1.0f, 1.2f)); + m_finalEye[1] = Transform(*mat, D3DVECTOR( 0.8f, 3.0f, 0.8f)); + } + + if ( m_type == MM_SATCOMclose ) + { + pObj = m_main->SearchHuman(); + if ( pObj != 0 ) + { + motion = pObj->RetMotion(); + if ( motion != 0 ) + { + motion->SetAction(-1); // finishes reading SatCom + } + } + + m_camera->SetType(CAMERA_BACK); + m_type = MM_NONE; // it's already over! + } + + return TRUE; +} + +// Stop a current movie. + +BOOL CMainMovie::Stop() +{ + CObject* pObj; + CMotion* motion; + + if ( m_type == MM_SATCOMopen ) + { + pObj = m_main->SearchHuman(); + if ( pObj != 0 ) + { + motion = pObj->RetMotion(); + if ( motion != 0 ) + { + motion->SetAction(-1); // finishes reading SatCom + } + } + } + + m_type = MM_NONE; + return TRUE; +} + +// Indicates whether a film is in progress. + +BOOL CMainMovie::IsExist() +{ + return (m_type != MM_NONE); +} + + +// Processing an event. + +BOOL CMainMovie::EventProcess(const Event &event) +{ + D3DVECTOR initialEye, initialLookat, finalEye, finalLookat, eye, lookat; + float progress; + + if ( m_type == MM_NONE ) return TRUE; + + m_progress += event.rTime*m_speed; + + if ( m_type == MM_SATCOMopen ) + { + if ( m_progress < 1.0f ) + { + progress = 1.0f-powf(1.0f-m_progress, 3.0f); + + if ( progress < 0.6f ) + { + progress = progress/0.6f; + initialEye = m_initialEye; + initialLookat = m_initialLookat; + finalEye = m_finalEye[0]; + finalLookat = m_finalLookat[0]; + } + else + { + progress = (progress-0.6f)/0.3f; + initialEye = m_finalEye[0]; + initialLookat = m_finalLookat[0]; + finalEye = m_finalEye[1]; + finalLookat = m_finalLookat[1]; + } + if ( progress > 1.0f ) progress = 1.0f; + + eye = (finalEye-initialEye)*progress+initialEye; + lookat = (finalLookat-initialLookat)*progress+initialLookat; + m_camera->SetScriptEye(eye); + m_camera->SetScriptLookat(lookat); +// m_camera->FixCamera(); + } + else + { + m_stopType = m_type; + Flush(); + return FALSE; + } + } + + if ( m_type == MM_SATCOMclose ) + { + if ( m_progress < 1.0f ) + { + } + else + { + m_stopType = m_type; + Flush(); + return FALSE; + } + } + + return TRUE; +} + + +// Returns the type of the current movie. + +MainMovieType CMainMovie::RetType() +{ + return m_type; +} + +// Returns the type of movie stop. + +MainMovieType CMainMovie::RetStopType() +{ + return m_stopType; +} + + diff --git a/src/graphics/common/mainmovie.h b/src/graphics/common/mainmovie.h new file mode 100644 index 0000000..f31b3a9 --- /dev/null +++ b/src/graphics/common/mainmovie.h @@ -0,0 +1,80 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have received a copy of the GNU General Public License +// * along with this program. If not, see http://www.gnu.org/licenses/. + +// mainmovie.h + +#ifndef _MAINMOVIE_H_ +#define _MAINMOVIE_H_ + + +class CInstanceManager; +class CEvent; +class CD3DEngine; +class CInterface; +class CRobotMain; +class CCamera; +class CSound; +class CObject; + + + + +enum MainMovieType +{ + MM_NONE, + MM_SATCOMopen, + MM_SATCOMclose, +}; + + + +class CMainMovie +{ +public: + CMainMovie(CInstanceManager* iMan); + ~CMainMovie(); + + void Flush(); + BOOL Start(MainMovieType type, float time); + BOOL Stop(); + BOOL IsExist(); + BOOL EventProcess(const Event &event); + MainMovieType RetType(); + MainMovieType RetStopType(); + +protected: + +protected: + CInstanceManager* m_iMan; + CEvent* m_event; + CD3DEngine* m_engine; + CInterface* m_interface; + CRobotMain* m_main; + CCamera* m_camera; + CSound* m_sound; + + MainMovieType m_type; + MainMovieType m_stopType; + float m_speed; + float m_progress; + D3DVECTOR m_initialEye; + D3DVECTOR m_initialLookat; + D3DVECTOR m_finalEye[2]; + D3DVECTOR m_finalLookat[2]; +}; + + +#endif //_MAINMOVIE_H_ diff --git a/src/graphics/common/model.cpp b/src/graphics/common/model.cpp new file mode 100644 index 0000000..80ce6b5 --- /dev/null +++ b/src/graphics/common/model.cpp @@ -0,0 +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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "water.h" +#include "robotmain.h" +#include "interface.h" +#include "edit.h" +#include "button.h" +#include "cmdtoken.h" +#include "modfile.h" +#include "model.h" + + + +#define 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 +}; + + +#define MAX_STATES 10 + +static int table_state[MAX_STATES] = +{ + D3DSTATENORMAL, + D3DSTATEPART1, + D3DSTATEPART2, + D3DSTATEPART3, + D3DSTATEPART4, + D3DSTATE2FACE, // #5 + D3DSTATETTw, + D3DSTATETTb, + D3DSTATETTw|D3DSTATE2FACE, // #8 + D3DSTATETTb|D3DSTATE2FACE, // #9 +}; + + +#define 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; + FPOINT 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' ) + { + FPOINT 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(D3DVECTOR(1.0f, 0.0f, 0.0f)); + break; + case EVENT_BUTTON16: // -X ? + MoveSelect(D3DVECTOR(-1.0f, 0.0f, 0.0f)); + break; + case EVENT_BUTTON14: // +Y ? + MoveSelect(D3DVECTOR(0.0f, 1.0f, 0.0f)); + break; + case EVENT_BUTTON17: // -Y ? + MoveSelect(D3DVECTOR(0.0f, -1.0f, 0.0f)); + break; + case EVENT_BUTTON15: // +Z ? + MoveSelect(D3DVECTOR(0.0f, 0.0f, 1.0f)); + break; + case EVENT_BUTTON18: // -Z ? + MoveSelect(D3DVECTOR(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; + D3DVECTOR 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 *= 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(D3DVECTOR &min, D3DVECTOR &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. + +D3DVECTOR CModel::RetSelectCDG() +{ + D3DVECTOR 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. + +D3DVECTOR CModel::RetSelectNormal() +{ + D3DVECTOR 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]; + D3DVECTOR min, max; + FPOINT 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] = RotateAngle(p.x, p.z)/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; + D3DVECTOR 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= Max(n.y, n.z) ) mode = 0; + if ( n.y >= Max(n.x, n.z) ) mode = 1; + if ( n.z >= 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) +{ + D3DVECTOR 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= PI ) + { + m_viewAngleV -= PI; + m_viewAngleH -= 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() +{ + D3DVECTOR eye, lookat, vUpVec; + +//? lookat = RetSelectCDG(); + lookat = D3DVECTOR(0.0f, m_viewHeight, 0.0f); + eye = RotateView(lookat, m_viewAngleH, m_viewAngleV, m_viewDist); + + vUpVec = D3DVECTOR(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 < -PI*0.49f ) m_viewAngleV = -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 > PI*0.49f ) m_viewAngleV = 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 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/graphics/common/model.h b/src/graphics/common/model.h new file mode 100644 index 0000000..35b48b6 --- /dev/null +++ b/src/graphics/common/model.h @@ -0,0 +1,137 @@ +// * 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 + +#ifndef _MODEL_H_ +#define _MODEL_H_ + + +#include "struct.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); + D3DVECTOR RetSelectCDG(); + D3DVECTOR RetSelectNormal(); + void SmoothSelect(); + void PlaneSelect(); + void ColorSelect(); + void StateSelect(); + void MoveSelect(D3DVECTOR move); + void OperSelect(D3DVECTOR move, char oper); + void ReadScript(char *filename); + void BBoxCompute(D3DVECTOR &min, D3DVECTOR &max); + BOOL IsMappingSelectPlausible(D3DMaping D3Dmode); + void MappingSelect(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName); + void MappingSelectSpherical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName); + D3DVECTOR RetMappingCenter(D3DVECTOR pos, D3DVECTOR min); + void MappingSelectCylindrical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName); + void MappingSelectFace(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT 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; + FPOINT m_textureInf; + FPOINT 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; +}; + + +#endif //_MODEL_H_ diff --git a/src/graphics/common/particule.cpp b/src/graphics/common/particule.cpp new file mode 100644 index 0000000..0a8c27d --- /dev/null +++ b/src/graphics/common/particule.cpp @@ -0,0 +1,4373 @@ +// * 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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dmath.h" +#include "d3dtextr.h" +#include "d3dengine.h" +#include "d3dutil.h" +#include "language.h" +#include "iman.h" +#include "math3d.h" +#include "event.h" +#include "object.h" +#include "physics.h" +#include "auto.h" +#include "robotmain.h" +#include "terrain.h" +#include "sound.h" +#include "water.h" +#include "particule.h" + + + +#define FOG_HSUP 10.0f +#define 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 = Length(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(D3DVECTOR pos, D3DVECTOR speed, + D3DTriangle *triangle, + ParticuleType type, + float duration, float mass, + float windSensitivity, int sheet) +{ + D3DVECTOR 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, D3DVECTOR pos) +{ + if ( !CheckChannel(channel) ) return; + m_particule[channel].pos = pos; +} + +void CParticule::SetDimension(int channel, FPOINT 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, D3DVECTOR pos, FPOINT 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, D3DVECTOR &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; + D3DVECTOR eye, pos, speed, wind; + FPOINT 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 = Rand()*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 = Rand()*6.0f+6.0f; + dim.y = dim.x; + duration = 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 = Rand()*6.0f+6.0f; + dim.y = dim.x; + duration = 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, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(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 = Rand()*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, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(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 = Rand()*4.0f+2.0f; + dim.y = dim.x; + duration = 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 = Rand()*4.0f+2.0f; + dim.y = dim.x; + duration = 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 = Rand()*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*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*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*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*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; + + D3DVECTOR pos, speed; + FPOINT dim; + + pos = m_particule[i].pos; +//? speed = -m_particule[i].speed*0.5f; + speed = D3DVECTOR(0.0f, 0.0f, 0.0f); + dim.x = 1.0f*(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*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*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*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*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*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+Rand()*2.0f; + m_particule[i].pos.x = m_particule[i].speed.x + (Rand()-0.5f)*m_particule[i].mass; + m_particule[i].pos.y = m_particule[i].speed.y + (Rand()-0.5f)*m_particule[i].mass; + m_particule[i].pos.z = m_particule[i].speed.z + (Rand()-0.5f)*m_particule[i].mass; + m_particule[i].dim.x = 0.5f+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*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*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*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*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, D3DVECTOR pos, float progress) +{ + D3DVECTOR 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] = Length(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 + D3DVECTOR corner[4], p1, p2, p, n, eye; + D3DMATRIX matrix; + FPOINT 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, &matrix); + + 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 = 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; + D3DMATRIX matrix; + D3DVECTOR 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 = -RotateAngle(Length2d(pos, eye), pos.y-eye.y); + angle.y = RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particule[i].angle; + + MatRotateXZY(matrix, angle); + matrix._41 = pos.x; + matrix._42 = pos.y; + matrix._43 = pos.z; + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + 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 + D3DMATRIX matrix; + D3DVECTOR corner[4], eye, pos, n, angle; + FPOINT 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 = D3DVECTOR(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 = -RotateAngle(Length2d(pos, eye), pos.y-eye.y); + angle.y = RotateAngle(pos.z-eye.z, pos.x-eye.x); + angle.z = m_particule[i].angle; + + MatRotateXZY(matrix, angle); + matrix._41 = pos.x; + matrix._42 = pos.y; + matrix._43 = pos.z; + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + n = D3DVECTOR(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 + D3DMATRIX matrix; + D3DVECTOR corner[4], pos, n, angle, eye; + FPOINT 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 = PI/2.0f; + angle.y = 0.0f; + angle.z = m_particule[i].angle; + +#if 0 + if ( m_engine->RetRankView() == 1 ) // underwater? + { + angle.x = -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 = -PI/2.0f; + } +#endif + + MatRotateXZY(matrix, angle); + matrix._41 = pos.x; + matrix._42 = pos.y; + matrix._43 = pos.z; + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + n = D3DVECTOR(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 + D3DMATRIX matrix; + D3DVECTOR corner[4], pos, n, angle, eye; + FPOINT 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 = 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 = -PI/2.0f; + } + + MatRotateXZY(matrix, angle); + matrix._41 = pos.x; + matrix._42 = pos.y; + matrix._43 = pos.z; + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + n = D3DVECTOR(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 + D3DMATRIX matrix; + D3DVECTOR corner[4], eye, pos, goal, n, angle, proj; + FPOINT 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 = RotateAngle(FPOINT(pos.x,pos.z), FPOINT(goal.x,goal.z), FPOINT(eye.x,eye.z)); + bLeft = (a < PI); + + proj = Projection(pos, goal, eye); + angle.x = -RotateAngle(Length2d(proj, eye), proj.y-eye.y); + angle.y = RotateAngle(pos.z-goal.z, pos.x-goal.x)+PI/2.0f; + angle.z = -RotateAngle(Length2d(pos, goal), pos.y-goal.y); + if ( bLeft ) angle.x = -angle.x; + + MatRotateZXY(matrix, angle); + matrix._41 = pos.x; + matrix._42 = pos.y; + matrix._43 = pos.z; + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + n = D3DVECTOR(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 = Length(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 = (Rand()-0.5f)*vario1; + corner[1].z = (Rand()-0.5f)*vario1; + corner[2].z = (Rand()-0.5f)*vario1; + corner[3].z = (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 ) + { + Swap(texInf.x, texSup.x); + } + if ( r%4 < 2 ) + { + Swap(texInf.y, texSup.y); + } +#else + texInf.x = Mod(texInf.x+0.25f, 1.0f); + texSup.x = 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 + D3DMATRIX matrix, rot; + D3DVECTOR angle, v0, v1; + FPOINT 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)); + + D3DUtil_SetIdentityMatrix(matrix); + matrix._11 = zoom; + matrix._22 = zoom; + matrix._33 = zoom; + matrix._41 = m_particule[i].pos.x; + matrix._42 = m_particule[i].pos.y; + matrix._43 = 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; + MatRotateZXY(rot, angle); + matrix = rot*matrix; + } + + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + 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 = PI/numRings; + deltaSegAngle = 2.0f*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 + D3DMATRIX matrix, rot; + D3DVECTOR angle, v0, v1; + FPOINT 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)); + + D3DUtil_SetIdentityMatrix(matrix); + matrix._11 = zoom; + matrix._22 = zoom; + matrix._33 = zoom; + matrix._41 = m_particule[i].pos.x; + matrix._42 = m_particule[i].pos.y; + matrix._43 = m_particule[i].pos.z; + + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + 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*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) +{ + D3DVECTOR pos[4], center; + D3DVERTEX2 vertex[4]; // 2 triangles + D3DVECTOR n; + FPOINT ts, ti; + float dist, dp; + + dist = Length2d(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 = D3DVECTOR(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; + D3DMATRIX 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); + D3DUtil_SetIdentityMatrix(matrix); + m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + 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(D3DVECTOR old, D3DVECTOR pos, + ParticuleType type, CObject *father) +{ + CObject *pObj, *pBest; + D3DVECTOR 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 ) Swap(box1.x, box2.x); // box1 < box2 + if ( box1.y > box2.y ) Swap(box1.y, box2.y); + if ( box1.z > box2.z ) 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 = Length(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 = Length(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 = Projection(old, pos, oPos); + dist = Length(p, oPos)-oRadius; + if ( dist < min ) + { + pBest = pObj; + } + } + } + + return pBest; +} + +// Seeks if an object collided with a ray. + +CObject* CParticule::SearchObjectRay(D3DVECTOR pos, D3DVECTOR goal, + ParticuleType type, CObject *father) +{ + CObject* pObj; + D3DVECTOR 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 ) Swap(box1.x, box2.x); // box1 < box2 + if ( box1.y > box2.y ) Swap(box1.y, box2.y); + if ( box1.z > box2.z ) 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 = Projection(pos, goal, oPos); + dist = Length(p, oPos); + if ( dist < min ) return pObj; + } + + return 0; +} + + +// Sounded one. + +void CParticule::Play(Sound sound, D3DVECTOR 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(D3DVECTOR 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 = Length2d(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, + D3DVECTOR dl, D3DVECTOR ur) +{ + HDC hDC; + HDC hDCImage; + HBITMAP hb; + PBITMAPINFO info; + HBRUSH hBrush; + HPEN hPen; + HGDIOBJ old; + RECT rect; + COLORREF color; + FPOINT 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/graphics/common/particule.h b/src/graphics/common/particule.h new file mode 100644 index 0000000..67abad3 --- /dev/null +++ b/src/graphics/common/particule.h @@ -0,0 +1,339 @@ +// * 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 + +#ifndef _PARTICULE_H_ +#define _PARTICULE_H_ + + +#include "d3dengine.h" +#include "sound.h" + + +class CInstanceManager; +class CRobotMain; +class CTerrain; +class CWater; +class CObject; + + +#define MAXPARTICULE 500 +#define MAXPARTITYPE 5 +#define MAXTRACK 100 +#define MAXTRACKLEN 10 +#define MAXPARTIFOG 100 +#define MAXWHEELTRACE 1000 + +#define SH_WORLD 0 // particle in the world in the interface +#define SH_FRONT 1 // particle in the world on the interface +#define SH_INTERFACE 2 // particle in the interface +#define 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, +}; + +typedef struct +{ + 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 + D3DVECTOR pos; // absolute position (relative if object links) + D3DVECTOR goal; // goal position (if bRay) + D3DVECTOR speed; // speed of displacement + float windSensitivity; + short bounce; // number of rebounds + FPOINT dim; // dimensions of the rectangle + float zoom; // zoom (0..1) + float angle; // angle of rotation + float intensity; // intensity + FPOINT texSup; // coordinated upper texture + FPOINT 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 +} +Particule; + +typedef struct +{ + 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 + D3DVECTOR pos[MAXTRACKLEN]; + float len[MAXTRACKLEN]; +} +Track; + +typedef struct +{ + ParticuleType type; // type PARTI* + D3DVECTOR pos[4]; // rectangle positions + float startTime; // beginning of life +} +WheelTrace; + + + +class CParticule +{ +public: + CParticule(CInstanceManager* iMan, CD3DEngine* engine); + ~CParticule(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + + void FlushParticule(); + void FlushParticule(int sheet); + int CreateParticule(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateFrag(D3DVECTOR pos, D3DVECTOR speed, D3DTriangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreatePart(D3DVECTOR pos, D3DVECTOR speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0); + int CreateRay(D3DVECTOR pos, D3DVECTOR goal, ParticuleType type, FPOINT dim, float duration=1.0f, int sheet=0); + int CreateTrack(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f); + void CreateWheelTrace(const D3DVECTOR &p1, const D3DVECTOR &p2, const D3DVECTOR &p3, const D3DVECTOR &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, D3DVECTOR pos); + void SetDimension(int channel, FPOINT dim); + void SetZoom(int channel, float zoom); + void SetAngle(int channel, float angle); + void SetIntensity(int channel, float intensity); + void SetParam(int channel, D3DVECTOR pos, FPOINT dim, float zoom, float angle, float intensity); + void SetPhase(int channel, ParticulePhase phase, float duration); + BOOL GetPosition(int channel, D3DVECTOR &pos); + + D3DCOLORVALUE RetFogColor(D3DVECTOR pos); + + void SetFrameUpdate(int sheet, BOOL bUpdate); + void FrameParticule(float rTime); + void DrawParticule(int sheet); + + BOOL WriteWheelTrace(char *filename, int width, int height, D3DVECTOR dl, D3DVECTOR 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(D3DVECTOR old, D3DVECTOR pos, ParticuleType type, CObject *father); + CObject* SearchObjectRay(D3DVECTOR pos, D3DVECTOR goal, ParticuleType type, CObject *father); + void Play(Sound sound, D3DVECTOR pos, float amplitude); + BOOL TrackMove(int i, D3DVECTOR 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; +}; + + +#endif //_PARTICULE_H_ diff --git a/src/graphics/common/planet.cpp b/src/graphics/common/planet.cpp new file mode 100644 index 0000000..925b2e9 --- /dev/null +++ b/src/graphics/common/planet.cpp @@ -0,0 +1,248 @@ +// * 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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "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 + D3DVECTOR n; + FPOINT 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 = D3DVECTOR(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 = Mod(a, PI*2.0f)-0.5f; + + a = eyeDirV + m_planet[m_mode][i].angle.y; + p1.y = 0.4f+(Mod(a+PI, PI*2.0f)-PI)*(2.0f/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(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1); + + device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + } +} + + +// Creates a new planet. + +BOOL CPlanet::Create(int mode, FPOINT start, float dim, float speed, + float dir, char *name, FPOINT uv1, FPOINT 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/graphics/common/planet.h b/src/graphics/common/planet.h new file mode 100644 index 0000000..9a6ba52 --- /dev/null +++ b/src/graphics/common/planet.h @@ -0,0 +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/. + +// planet.h + +#ifndef _PLANET_H_ +#define _PLANET_H_ + + +#include "struct.h" + + +class CInstanceManager; +class CD3DEngine; + + + +#define MAXPLANET 10 + +typedef struct +{ + char bUsed; // TRUE -> planet exists + FPOINT start; // initial position in degrees + FPOINT 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 + FPOINT uv1, uv2; // texture mapping + char bTGA; // texture .TGA +} +Planet; + + + + +class CPlanet +{ +public: + CPlanet(CInstanceManager* iMan, CD3DEngine* engine); + ~CPlanet(); + + void Flush(); + BOOL EventProcess(const Event &event); + BOOL Create(int mode, FPOINT start, float dim, float speed, float dir, char *name, FPOINT uv1, FPOINT 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; +}; + + +#endif //_PLANET_H_ diff --git a/src/graphics/common/pyro.cpp b/src/graphics/common/pyro.cpp new file mode 100644 index 0000000..3588585 --- /dev/null +++ b/src/graphics/common/pyro.cpp @@ -0,0 +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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "D3DEngine.h" +#include "D3DMath.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "robotmain.h" +#include "terrain.h" +#include "camera.h" +#include "particule.h" +#include "light.h" +#include "object.h" +#include "motion.h" +#include "motionhuman.h" +#include "displaytext.h" +#include "sound.h" +#include "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) +{ + D3DMATRIX* mat; + CObject* power; + CMotion* motion; + D3DVECTOR min, max, pos, speed; + FPOINT 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 = Length(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 = 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 = Transform(*mat, D3DVECTOR(-15.0f, 7.0f, 0.0f)); + m_pos = m_posPower; + } + if ( oType == OBJECT_ENERGY ) + { + m_bPower = TRUE; + mat = pObj->RetWorldMatrix(0); + m_posPower = Transform(*mat, D3DVECTOR(-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, 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, 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 = D3DVECTOR(-3.0f, 2.0f, 0.0f); + mat = pObj->RetWorldMatrix(0); + m_pos = 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, 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, D3DVECTOR(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 += (Rand()-0.5f)*3.0f; + pos.z += (Rand()-0.5f)*3.0f; + pos.y += (Rand()-0.5f)*2.0f; + speed.x = (Rand()-0.5f)*24.0f; + speed.z = (Rand()-0.5f)*24.0f; + speed.y = 10.0f+Rand()*10.0f; + dim.x = 1.0f; + dim.y = dim.x; + channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN3, 2.0f+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+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 = D3DVECTOR(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]; + D3DMATRIX* mat; + D3DVECTOR 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 = Length(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 = Length(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 = Transform(*mat, offset); + if ( m_type == PT_EGG ) + { + speed.x = (Rand()-0.5f)*10.0f; + speed.z = (Rand()-0.5f)*10.0f; + speed.y = Rand()*15.0f; + mass = Rand()*20.0f+20.0f; + } + else if ( m_type == PT_SPIDER ) + { + speed.x = (Rand()-0.5f)*10.0f; + speed.z = (Rand()-0.5f)*10.0f; + speed.y = Rand()*20.0f; + mass = Rand()*10.0f+15.0f; + } + else + { + speed.x = (Rand()-0.5f)*30.0f; + speed.z = (Rand()-0.5f)*30.0f; + speed.y = Rand()*30.0f; + mass = Rand()*10.0f+15.0f; + } + if ( oType == OBJECT_STONE ) speed *= 0.5f; + if ( oType == OBJECT_URANIUM ) speed *= 0.4f; + duration = 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; + D3DVECTOR pos, speed, angle; + FPOINT 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 += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + speed.x = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = Rand()*m_crashSphereRadius[i]*1.0f; + dim.x = 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 += (Rand()-0.5f)*m_size*0.3f; + pos.z += (Rand()-0.5f)*m_size*0.3f; + speed.x = (Rand()-0.5f)*m_size*0.1f; + speed.z = (Rand()-0.5f)*m_size*0.1f; + speed.y = Rand()*m_size*0.2f; + dim.x = 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 += (Rand()-0.5f)*m_size*0.2f; + pos.z += (Rand()-0.5f)*m_size*0.2f; + pos.y += (Rand()-0.5f)*m_size*0.5f; + speed.x = (Rand()-0.5f)*5.0f; + speed.z = (Rand()-0.5f)*5.0f; + speed.y = Rand()*1.0f; + dim.x = 1.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIBLOOD, Rand()*3.0f+3.0f, 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 += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + pos.z += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f; + speed.x = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.z = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f; + speed.y = 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 += (Rand()-0.5f)*m_size*0.3f; + pos.z += (Rand()-0.5f)*m_size*0.3f; + speed.x = (Rand()-0.5f)*m_size*0.1f; + speed.z = (Rand()-0.5f)*m_size*0.1f; + speed.y = 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 += (Rand()-0.5f)*4.0f; + pos.z += (Rand()-0.5f)*4.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 10.0f+Rand()*10.0f; + dim.x = 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 = (Rand()-0.5f)*m_size*1.0f; + speed.z = (Rand()-0.5f)*m_size*1.0f; + speed.y = Rand()*m_size*0.50f; + dim.x = 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 = Rand()*m_size/3.0f+m_size/3.0f; + dim.y = dim.x; + pos = m_pos; + pos.x += (Rand()-0.5f)*m_size*0.5f; + pos.z += (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 = (Rand()-0.5f)*m_size*2.0f; + speed.z = (Rand()-0.5f)*m_size*2.0f; + speed.y = Rand()*m_size*1.0f; + dim.x = 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 = (Rand()-0.5f)*m_size*1.0f; + speed.z = (Rand()-0.5f)*m_size*1.0f; + speed.y = 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 += (Rand()-0.5f)*4.0f; + pos.z += (Rand()-0.5f)*4.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 4.0f+Rand()*4.0f; + dim.x = 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 += (Rand()-0.5f)*3.0f; + pos.z += (Rand()-0.5f)*3.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 5.0f+Rand()*5.0f; + dim.x = 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 += (Rand()-0.5f)*1.0f; + pos.z += (Rand()-0.5f)*1.0f; + speed.x = (Rand()-0.5f)*2.0f; + speed.z = (Rand()-0.5f)*2.0f; + speed.y = 2.0f+Rand()*2.0f; + dim.x = (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 += (Rand()-0.5f)*1.0f; + pos.z += (Rand()-0.5f)*1.0f; + speed.x = (Rand()-0.5f)*2.0f; + speed.z = (Rand()-0.5f)*2.0f; + speed.y = 2.0f+Rand()*2.0f; + dim.x = (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 = (Rand()-0.5f)*6.0f; + speed.z = (Rand()-0.5f)*6.0f; + speed.y = Rand()*12.0f; + dim.x = (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), + Rand()*2.5f+2.5f, + 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 += (Rand()-0.5f)*5.0f; + pos.z += (Rand()-0.5f)*5.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 5.0f+Rand()*5.0f; + dim.x = Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f); + + pos = m_pos; + speed.x = (Rand()-0.5f)*20.0f; + speed.z = (Rand()-0.5f)*20.0f; + speed.y = Rand()*10.0f; + speed *= 0.5f+m_progress*0.5f; + dim.x = 0.6f; + dim.y = dim.x; + pos.y += dim.y; + duration = 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 += (Rand()-0.5f)*factor; + pos.z += (Rand()-0.5f)*factor; + speed.x = (Rand()-0.5f)*2.0f; + speed.z = (Rand()-0.5f)*2.0f; + speed.y = 4.0f+Rand()*4.0f; + dim.x = (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 += (Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; + pos.z += (Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 0.0f; + dim.x = (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 += (Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; + pos.z += (Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = (Rand()*5.0f*m_progress+3.0f)*factor; + dim.x = (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 += (Rand()-0.5f)*5.0f*factor; + pos.z += (Rand()-0.5f)*5.0f*factor; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = (6.0f+Rand()*6.0f+m_progress*6.0f)*factor; + dim.x = (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 = (Rand()-0.5f)*m_progress*1.0f; + speed.z = (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 = (Rand()-0.5f)*10.0f; + speed.z = (Rand()-0.5f)*10.0f; + speed.y = 8.0f+Rand()*8.0f; + dim.x = 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 += (Rand()-0.5f)*10.0f; + pos.z += (Rand()-0.5f)*10.0f; + speed.x = 0.0f; + speed.z = 0.0f; + speed.y = 1.0f+Rand()*1.0f; + dim.x = 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; + D3DVECTOR 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(D3DVECTOR 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 = 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() +{ + D3DVECTOR 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 = Length(min, max); // weight according to size! + + speed.y = 10.0f+Rand()*20.0f; + speed.x = (Rand()-0.5f)*20.0f; + speed.z = (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() +{ + D3DVECTOR 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+Rand()*4.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (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+Rand()*1.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.2f; + angle.y = 0.0f; + angle.z = (Rand()-0.5f)*0.2f; + } + else if ( m_burnType == OBJECT_NUCLEAR ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_PARA ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_SAFE ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (Rand()-0.5f)*0.4f; + } + else if ( m_burnType == OBJECT_HUSTON ) + { + pos.x = 0.0f; + pos.y = -(10.0f+Rand()*10.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.4f; + angle.y = 0.0f; + angle.z = (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+Rand()*1.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (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 = (Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (Rand()-0.5f)*0.2f; + } + else + { + pos.x = 0.0f; + pos.y = -(2.0f+Rand()*2.0f); + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*0.8f; + angle.y = 0.0f; + angle.z = (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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = -90.0f*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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = -90.0f*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 = (Rand()-0.5f)*0.5f; + angle.y = (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 = (Rand()-0.5f)*0.4f; + angle.y = (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 = (Rand()-0.5f)*0.2f; + angle.y = (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 = (Rand()-0.5f)*0.4f; + angle.y = (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 = (Rand()-0.5f)*0.4f; + angle.y = (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*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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = 40.0f*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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = 50.0f*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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = -25.0f*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 = (Rand()-0.5f)*0.2f; + angle.y = (Rand()-0.5f)*0.2f; + angle.z = -25.0f*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 = -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 = 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 = Rand()*0.5f; + pos.z = 0.0f; + angle.x = (Rand()-0.5f)*PI/2.0f; + angle.y = (Rand()-0.5f)*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 = (Rand()-0.5f)*20.0f*PI/180.0f; + angle.y = (Rand()-0.5f)*10.0f*PI/180.0f; + angle.z = (Rand()-0.5f)*30.0f*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 = (Rand()-0.5f)*20.0f*PI/180.0f; + angle.y = (Rand()-0.5f)*10.0f*PI/180.0f; + angle.z = (Rand()-0.5f)*30.0f*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 = (Rand()-0.5f)*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 = (Rand()-0.5f)*PI/4.0f; + angle.z = (Rand()-0.5f)*PI/4.0f; + BurnAddPart(6+i, pos, angle); // leg + } + } +} + +// Adds a part move. + +void CPyro::BurnAddPart(int part, D3DVECTOR pos, D3DVECTOR 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; + D3DVECTOR 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() +{ + D3DVECTOR 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; + D3DVECTOR 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 = Length(oPos, iPos); + if ( distance <= shieldRadius ) return pObj; + } + + if ( oType == OBJECT_BASE ) + { + distance = Length(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 = Length(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 = Length(oPos, iPos); + if ( distance <= iRadius+oRadius ) + { + return pObj; + } + } + } + return 0; +} + +// Fall of an object's freight. + +void CPyro::FallProgress(float rTime) +{ + CObject* pObj; + D3DVECTOR 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, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(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() +{ + D3DVECTOR 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/graphics/common/pyro.h b/src/graphics/common/pyro.h new file mode 100644 index 0000000..5eac0c9 --- /dev/null +++ b/src/graphics/common/pyro.h @@ -0,0 +1,175 @@ +// * 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 + +#ifndef _PYRO_H_ +#define _PYRO_H_ + + +#include "d3dengine.h" +#include "object.h" +#include "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 +}; + + +typedef struct +{ + int part; + D3DVECTOR initialPos; + D3DVECTOR finalPos; + D3DVECTOR initialAngle; + D3DVECTOR finalAngle; +} +PyroBurnPart; + +typedef struct +{ + float progress; + float intensity; + D3DCOLORVALUE color; +} +PyroLightOper; + + + +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(D3DVECTOR 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, D3DVECTOR pos, D3DVECTOR 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; + + D3DVECTOR m_pos; // center of the effect + D3DVECTOR 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 + D3DVECTOR m_crashSpherePos[50]; + float m_crashSphereRadius[50]; +}; + + +#endif //_PYRO_H_ diff --git a/src/graphics/common/terrain.cpp b/src/graphics/common/terrain.cpp new file mode 100644 index 0000000..31b1cc9 --- /dev/null +++ b/src/graphics/common/terrain.cpp @@ -0,0 +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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "d3dutil.h" +#include "language.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "modfile.h" +#include "water.h" +#include "terrain.h" + + +#define 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 = D3DVECTOR(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 D3DVECTOR &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+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(D3DVECTOR 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; + D3DVECTOR* 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 = (D3DVECTOR*)malloc(sizeof(D3DVECTOR)*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 ) + { + D3DVECTOR 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(D3DVECTOR &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; + D3DVECTOR 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 = D3DVECTOR(0.0f, 0.0f, 0.0f); + + if ( x-step >= 0 && y+step <= m_mosaic*m_brick+1 ) + { + s += ComputeNormal(b,a,o); + s += ComputeNormal(c,b,o); + } + + if ( x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1 ) + { + s += ComputeNormal(d,c,o); + } + + if ( x+step <= m_mosaic*m_brick+1 && y-step >= 0 ) + { + s += ComputeNormal(e,d,o); + s += ComputeNormal(f,e,o); + } + + if ( x-step >= 0 && y-step >= 0 ) + { + s += ComputeNormal(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) +{ + D3DMATRIX transform; + D3DVERTEX2 o, p1, p2; + D3DObjLevel6* buffer; + FPOINT 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); + } + } + } + + D3DUtil_SetIdentityMatrix(transform); + transform._41 = o.x; + transform._43 = 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 ( Abs(hc-h[i]) >= slope ) + { + return FALSE; + } + } + return TRUE; + } + + if ( slope < 0.0f ) + { + for ( i=0 ; i<4 ; i++ ) + { + if ( Abs(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, + D3DVECTOR center, float radius) +{ + TerrainMaterial *tm; + D3DVECTOR 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(D3DVECTOR speed) +{ + m_wind = speed; +} + +D3DVECTOR CTerrain::RetWind() +{ + return m_wind; +} + + +// Gives the exact slope of the terrain of a place given. + +float CTerrain::RetFineSlope(const D3DVECTOR &pos) +{ + D3DVECTOR n; + + if ( !GetNormal(n, pos) ) return 0.0f; + return Abs(RotateAngle(Length(n.x, n.z), n.y)-PI/2.0f); +} + +// Gives the approximate slope of the terrain of a specific location. + +float CTerrain::RetCoarseSlope(const D3DVECTOR &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 = Min(level[0], level[1], level[2], level[3]); + max = 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(D3DVECTOR &n, const D3DVECTOR &p) +{ + D3DVECTOR 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 ( Abs(p.z-p2.z) < Abs(p.x-p2.x) ) + { + n = ComputeNormal(p1,p2,p3); + } + else + { + n = ComputeNormal(p2,p4,p3); + } + return TRUE; +} + +// Returns the height of the ground. + +float CTerrain::RetFloorLevel(const D3DVECTOR &p, BOOL bBrut, BOOL bWater) +{ + D3DVECTOR 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 ( Abs(p.z-p2.z) < Abs(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 D3DVECTOR &p, BOOL bBrut, BOOL bWater) +{ + D3DVECTOR 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 ( Abs(p.z-p2.z) < Abs(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(D3DVECTOR &p, BOOL bBrut, BOOL bWater) +{ + D3DVECTOR 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 ( Abs(p.z-p2.z) < Abs(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(D3DVECTOR &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(D3DVECTOR 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(D3DVECTOR 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 = Length2d(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(D3DVECTOR &p) +{ + D3DVECTOR 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 = Length2d(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 D3DVECTOR &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(D3DVECTOR pos) +{ + D3DVECTOR 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 ( Length(p.x, p.y) > 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(D3DVECTOR center, float max) +{ + D3DVECTOR pos; + FPOINT 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*PI*radius); + if ( nb < 8 ) nb = 8; + for ( i=0 ; i 1.0f ) return radius; + + angle += 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(D3DVECTOR 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(D3DVECTOR 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/graphics/common/terrain.h b/src/graphics/common/terrain.h new file mode 100644 index 0000000..4fc4ace --- /dev/null +++ b/src/graphics/common/terrain.h @@ -0,0 +1,214 @@ +// * 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 + +#ifndef _TERRAIN_H_ +#define _TERRAIN_H_ + + +#include "d3dengine.h" + + +class CInstanceManager; +class CD3DEngine; +class CWater; + + + +#define FLATLIMIT (5.0f*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, +}; + + +#define MAXBUILDINGLEVEL 100 + +typedef struct +{ + D3DVECTOR center; + float factor; + float min; + float max; + float level; + float height; + float bboxMinX; + float bboxMaxX; + float bboxMinZ; + float bboxMaxZ; +} +BuildingLevel; + + +#define MAXMATTERRAIN 100 + +typedef struct +{ + short id; + char texName[20]; + float u,v; + float hardness; + char mat[4]; // up, right, down, left +} +TerrainMaterial; + +typedef struct +{ + short id; + char mat[4]; // up, right, down, left +} +DotLevel; + + +#define MAXFLYINGLIMIT 10 + +typedef struct +{ + D3DVECTOR center; + float extRadius; + float intRadius; + float maxHeight; +} +FlyingLimit; + + + +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, D3DVECTOR 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 D3DVECTOR &p1, const D3DVECTOR &p2, float height); + + void SetWind(D3DVECTOR speed); + D3DVECTOR RetWind(); + + float RetFineSlope(const D3DVECTOR &pos); + float RetCoarseSlope(const D3DVECTOR &pos); + BOOL GetNormal(D3DVECTOR &n, const D3DVECTOR &p); + float RetFloorLevel(const D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE); + float RetFloorHeight(const D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE); + BOOL MoveOnFloor(D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE); + BOOL ValidPosition(D3DVECTOR &p, float marging); + TerrainRes RetResource(const D3DVECTOR &p); + void LimitPos(D3DVECTOR &pos); + + void FlushBuildingLevel(); + BOOL AddBuildingLevel(D3DVECTOR center, float min, float max, float height, float factor); + BOOL UpdateBuildingLevel(D3DVECTOR center); + BOOL DeleteBuildingLevel(D3DVECTOR center); + float RetBuildingFactor(const D3DVECTOR &p); + float RetHardness(const D3DVECTOR &p); + + int RetMosaic(); + int RetBrick(); + float RetSize(); + float RetScaleRelief(); + + void GroundFlat(D3DVECTOR pos); + float RetFlatZoneRadius(D3DVECTOR center, float max); + + void SetFlyingMaxHeight(float height); + float RetFlyingMaxHeight(); + void FlushFlyingLimit(); + BOOL AddFlyingLimit(D3DVECTOR center, float extRadius, float intRadius, float maxHeight); + float RetFlyingLimit(D3DVECTOR pos, BOOL bNoLimit); + +protected: + BOOL ReliefAddDot(D3DVECTOR pos, float scaleRelief); + void AdjustRelief(); + D3DVECTOR 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, FPOINT &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(D3DVECTOR &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; + D3DVECTOR m_wind; // wind speed + + float m_flyingMaxHeight; + int m_flyingLimitTotal; + FlyingLimit m_flyingLimit[MAXFLYINGLIMIT]; +}; + + +#endif //_TERRAIN_H_ diff --git a/src/graphics/common/text.cpp b/src/graphics/common/text.cpp new file mode 100644 index 0000000..88cfe0a --- /dev/null +++ b/src/graphics/common/text.cpp @@ -0,0 +1,1881 @@ +// * 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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "language.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "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, FPOINT 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, FPOINT 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, FPOINT 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, FPOINT 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, FPOINT pos, + int justif, float size, float stretch, + FPOINT &start, FPOINT &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, FPOINT pos, int justif, + float size, float stretch, + FPOINT &start, FPOINT &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, FPOINT pos, int justif, + float size, float stretch, FontType font, + FPOINT &start, FPOINT &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, FPOINT pos, int justif, + float size, float stretch, FontType font, + FPOINT &start, FPOINT &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-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-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-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, FPOINT 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(FPOINT pos, float size, float width, int color) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + FPOINT p1, p2; + POINT dim; + D3DVECTOR 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 = D3DVECTOR(0.0f, 0.0f, -1.0f); // normal + + vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); + + if ( color == COLOR_LINK ) + { + m_engine->SetState(D3DSTATETTw); + } +} + +// Displays a character. + +void CText::DrawChar(int character, FPOINT pos, float size, + float stretch, FontType font) +{ + D3DVERTEX2 vertex[4]; // 2 triangles + FPOINT p1, p2; + D3DVECTOR n; + float width, height, u1, u2, v1, v2, dp; + short* pt; + + dp = 0.5f/256.0f; + n = D3DVECTOR(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(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + 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(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + 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(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2); + vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1); + + m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL); + m_engine->AddStatisticTriangle(2); +} + diff --git a/src/graphics/common/text.h b/src/graphics/common/text.h new file mode 100644 index 0000000..4407039 --- /dev/null +++ b/src/graphics/common/text.h @@ -0,0 +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/. + +// text.h + +#ifndef _TEXT_H_ +#define _TEXT_H_ + + +#include "d3dengine.h" + + +class CInstanceManager; + + + +#define SMALLFONT 10.0f +#define BIGFONT 15.0f + +#define 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, +}; + +#define FONT_MASK 0x03 +#define TITLE_MASK 0x0c +#define COLOR_MASK 0x70 +#define IMAGE_MASK 0x80 + + + +class CText +{ +public: + CText(CInstanceManager *iMan, CD3DEngine* engine); + ~CText(); + + void SetD3DDevice(LPDIRECT3DDEVICE7 device); + + void DrawText(char *string, char *format, int len, FPOINT pos, float width, int justif, float size, float stretch, int eol); + void DrawText(char *string, char *format, FPOINT pos, float width, int justif, float size, float stretch, int eol); + void DrawText(char *string, int len, FPOINT pos, float width, int justif, float size, float stretch, FontType font, int eol); + void DrawText(char *string, FPOINT pos, float width, int justif, float size, float stretch, FontType font, int eol); + void DimText(char *string, char *format, int len, FPOINT pos, int justif, float size, float stretch, FPOINT &start, FPOINT &end); + void DimText(char *string, char *format, FPOINT pos, int justif, float size, float stretch, FPOINT &start, FPOINT &end); + void DimText(char *string, int len, FPOINT pos, int justif, float size, float stretch, FontType font, FPOINT &start, FPOINT &end); + void DimText(char *string, FPOINT pos, int justif, float size, float stretch, FontType font, FPOINT &start, FPOINT &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, FPOINT pos, float width, float size, float stretch, int eol); + void DrawString(char *string, int len, FPOINT pos, float width, float size, float stretch, FontType font, int eol); + void DrawColor(FPOINT pos, float size, float width, int color); + void DrawChar(int character, FPOINT pos, float size, float stretch, FontType font); + +protected: + CInstanceManager* m_iMan; + CD3DEngine* m_engine; + LPDIRECT3DDEVICE7 m_pD3DDevice; + +}; + + +#endif //_TEXT_H_ diff --git a/src/graphics/common/water.cpp b/src/graphics/common/water.cpp new file mode 100644 index 0000000..59963cc --- /dev/null +++ b/src/graphics/common/water.cpp @@ -0,0 +1,835 @@ +// * 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 + +#define STRICT +#define D3D_OVERLOADS + +#include +#include +#include + +#include "struct.h" +#include "d3dengine.h" +#include "d3dmath.h" +#include "d3dutil.h" +#include "event.h" +#include "misc.h" +#include "iman.h" +#include "math3d.h" +#include "particule.h" +#include "terrain.h" +#include "object.h" +#include "sound.h" +#include "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) +{ + D3DVECTOR 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 = Rand()*200.0f; + shift = (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 = Rand(); + if ( level < 0.8f ) + { + if ( VaporCreate(PARTIFIRE, pos, 0.02f+Rand()*0.06f) ) + { + m_lastLava = m_time; + } + } + else if ( level < 0.9f ) + { + if ( VaporCreate(PARTIFLAME, pos, 0.5f+Rand()*3.0f) ) + { + m_lastLava = m_time; + } + } + else + { + if ( VaporCreate(PARTIVAPOR, pos, 0.2f+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-Rand()*0.5f); + } + if ( m_vapor[i].type == PARTIFLAME ) + { +//? m_sound->Play(SOUND_SWIM, pos, 1.0f, 1.0f-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) +{ + D3DVECTOR pos, speed; + FPOINT 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 += (Rand()-0.5f)*2.0f; + pos.z += (Rand()-0.5f)*2.0f; + pos.y -= 1.0f; + speed.x = (Rand()-0.5f)*6.0f; + speed.z = (Rand()-0.5f)*6.0f; + speed.y = 8.0f+Rand()*5.0f; + dim.x = 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 += (Rand()-0.5f)*8.0f; + pos.z += (Rand()-0.5f)*8.0f; + pos.y -= 2.0f; + speed.x = (Rand()-0.5f)*2.0f; + speed.z = (Rand()-0.5f)*2.0f; + speed.y = 4.0f+Rand()*4.0f; + dim.x = Rand()*2.0f+2.0f; + dim.y = dim.x; + m_particule->CreateParticule(pos, speed, dim, PARTIFLAME); + } + else + { + pos = m_vapor[i].pos; + pos.x += (Rand()-0.5f)*4.0f; + pos.z += (Rand()-0.5f)*4.0f; + pos.y -= 2.0f; + speed.x = (Rand()-0.5f)*2.0f; + speed.z = (Rand()-0.5f)*2.0f; + speed.y = 8.0f+Rand()*8.0f; + dim.x = 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(D3DVECTOR &pos, D3DVECTOR &norm, + FPOINT &uv1, FPOINT &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 = D3DVECTOR(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 = D3DVECTOR(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; + D3DMATRIX matrix; + D3DVECTOR eye, lookat, n, p, p1, p2; + FPOINT 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 + + D3DUtil_SetIdentityMatrix(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + p.x = eye.x; + p.z = eye.z; + dist = Length2d(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(D3DVECTOR(p1.x, p2.y, p1.z), n, uv1.x,uv2.y); + vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, p1.z), n, uv1.x,uv1.y); + vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, p2.z), n, uv2.x,uv2.y); + vertex[3] = D3DVERTEX2(D3DVECTOR(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; + D3DMATRIX matrix; + D3DVECTOR eye, lookat, n, pos, p; + FPOINT 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); + + D3DUtil_SetIdentityMatrix(matrix); + device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix); + + 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; + device->ComputeSphereVisibility(&p, &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) +{ + D3DVECTOR 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, D3DVECTOR 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(D3DVECTOR &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/graphics/common/water.h b/src/graphics/common/water.h new file mode 100644 index 0000000..dc9384d --- /dev/null +++ b/src/graphics/common/water.h @@ -0,0 +1,134 @@ +// * 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 + +#ifndef _WATER_H_ +#define _WATER_H_ + + +#include "d3dengine.h" +#include "particule.h" + + +class CInstanceManager; +class CTerrain; +class CSound; + + + +#define MAXWATERLINE 500 + +typedef struct +{ + short x, y; // beginning + short len; // length by x + float px1, px2, pz; +} +WaterLine; + + +#define MAXWATVAPOR 10 + +typedef struct +{ + BOOL bUsed; + ParticuleType type; + D3DVECTOR pos; + float delay; + float time; + float last; +} +WaterVapor; + + +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, D3DVECTOR eddy); + void DrawBack(); + void DrawSurf(); + + BOOL SetLevel(float level); + float RetLevel(); + float RetLevel(CObject* object); + + void SetLava(BOOL bLava); + BOOL RetLava(); + + void AdjustEye(D3DVECTOR &eye); + +protected: + BOOL EventFrame(const Event &event); + void LavaFrame(float rTime); + void AdjustLevel(D3DVECTOR &pos, D3DVECTOR &norm, FPOINT &uv1, FPOINT &uv2); + BOOL RetWater(int x, int y); + BOOL CreateLine(int x, int y, int len); + + void VaporFlush(); + BOOL VaporCreate(ParticuleType type, D3DVECTOR 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 + D3DVECTOR 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; +}; + + +#endif //_WATER_H_ -- cgit v1.2.3-1-g7c22