// * This file is part of the COLOBOT source code // * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch // * // * This program is free software: you can redistribute it and/or modify // * it under the terms of the GNU General Public License as published by // * the Free Software Foundation, either version 3 of the License, or // * (at your option) any later version. // * // * This program is distributed in the hope that it will be useful, // * but WITHOUT ANY WARRANTY; without even the implied warranty of // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * GNU General Public License for more details. // * // * You should have received a copy of the GNU General Public License // * along with this program. If not, see http://www.gnu.org/licenses/. #include #include #include #include "common/struct.h" #include "math/const.h" #include "math/geometry.h" #include "old/d3dengine.h" #include "old/d3dmath.h" #include "common/language.h" #include "common/event.h" #include "common/misc.h" #include "common/iman.h" #include "old/math3d.h" #include "old/terrain.h" #include "old/water.h" #include "object/object.h" #include "physics/physics.h" #include "old/camera.h" // Object's constructor. CCamera::CCamera(CInstanceManager* iMan) { m_iMan = iMan; m_iMan->AddInstance(CLASS_CAMERA, this); m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE); m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN); m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER); m_type = CAMERA_FREE; m_smooth = CS_NORM; m_cameraObj = 0; m_eyeDistance = 10.0f; m_initDelay = 0.0f; m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f); m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f); m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_normEye = Math::Vector(0.0f, 0.0f, 0.0f); m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_focus = 1.0f; m_bRightDown = false; m_rightPosInit = Math::Point(0.5f, 0.5f); m_rightPosCenter = Math::Point(0.5f, 0.5f); m_rightPosMove = Math::Point(0.5f, 0.5f); m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f); m_directionH = 0.0f; m_directionV = 0.0f; m_heightEye = 20.0f; m_heightLookat = 0.0f; m_speed = 2.0f; m_backDist = 0.0f; m_backMin = 0.0f; m_addDirectionH = 0.0f; m_addDirectionV = 0.0f; m_bTransparency = false; m_fixDist = 0.0f; m_fixDirectionH = 0.0f; m_fixDirectionV = 0.0f; m_visitGoal = Math::Vector(0.0f, 0.0f, 0.0f); m_visitDist = 0.0f; m_visitTime = 0.0f; m_visitType = CAMERA_NULL; m_visitDirectionH = 0.0f; m_visitDirectionV = 0.0f; m_editHeight = 40.0f; m_remotePan = 0.0f; m_remoteZoom = 0.0f; m_mouseDirH = 0.0f; m_mouseDirV = 0.0f; m_mouseMarging = 0.01f; m_motorTurn = 0.0f; m_centeringPhase = CP_NULL; m_centeringAngleH = 0.0f; m_centeringAngleV = 0.0f; m_centeringDist = 0.0f; m_centeringCurrentH = 0.0f; m_centeringCurrentV = 0.0f; m_centeringTime = 0.0f; m_centeringProgress = 0.0f; m_effectType = CE_NULL; m_effectPos = Math::Vector(0.0f, 0.0f, 0.0f); m_effectForce = 0.0f; m_effectProgress = 0.0f; m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f); m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f); m_bEffect = true; m_bCameraScroll = true; m_bCameraInvertX = false; m_bCameraInvertY = false; } // Object's constructor. CCamera::~CCamera() { } void CCamera::SetEffect(bool bEnable) { m_bEffect = bEnable; } void CCamera::SetCameraScroll(bool bScroll) { m_bCameraScroll = bScroll; } void CCamera::SetCameraInvertX(bool bInvert) { m_bCameraInvertX = bInvert; } void CCamera::SetCameraInvertY(bool bInvert) { m_bCameraInvertY = bInvert; } // Returns an additional force to turn. float CCamera::RetMotorTurn() { if ( m_type == CAMERA_BACK ) return m_motorTurn; return 0.0f; } // Initializes the camera. void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay) { Math::Vector vUpVec; m_initDelay = delay; eye.y += m_terrain->RetFloorLevel(eye, true); lookat.y += m_terrain->RetFloorLevel(lookat, true); m_type = CAMERA_FREE; m_eyePt = eye; m_directionH = Math::RotateAngle(eye.x-lookat.x, eye.z-lookat.z)+Math::PI/2.0f; m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y-lookat.y); m_eyeDistance = 10.0f; m_heightLookat = 10.0f; m_backDist = 30.0f; m_backMin = 10.0f; m_addDirectionH = 0.0f; m_addDirectionV = -Math::PI*0.05f; m_fixDist = 50.0f; m_fixDirectionH = Math::PI*0.25f; m_fixDirectionV = -Math::PI*0.10f; m_centeringPhase = CP_NULL; m_actualEye = m_eyePt; m_actualLookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); m_finalEye = m_actualEye; m_finalLookat = m_actualLookat; m_scriptEye = m_actualEye; m_scriptLookat = m_actualLookat; m_focus = 1.00f; m_remotePan = 0.0f; m_remoteZoom = 0.0f; FlushEffect(); FlushOver(); SetType(CAMERA_FREE); } // Gives the object controlling the camera. void CCamera::SetObject(CObject* object) { m_cameraObj = object; } CObject* CCamera::RetObject() { return m_cameraObj; } // Changes the level of transparency of an object and objects // transported (battery & cargo). void SetTransparency(CObject* pObj, float value) { CObject* pFret; pObj->SetTransparency(value); pFret = pObj->RetFret(); if ( pFret != 0 ) { pFret->SetTransparency(value); } pFret = pObj->RetPower(); if ( pFret != 0 ) { pFret->SetTransparency(value); } } // Change the type of camera. void CCamera::SetType(CameraType type) { CObject* pObj; ObjectType oType; Math::Vector vUpVec; int i; m_remotePan = 0.0f; m_remoteZoom = 0.0f; if ( m_type == CAMERA_BACK && m_bTransparency ) { for ( i=0 ; i<1000000 ; i++ ) { pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); if ( pObj == 0 ) break; if ( pObj->RetTruck() ) continue; // battery or cargo? SetTransparency(pObj, 0.0f); // opaque object } } m_bTransparency = false; if ( type == CAMERA_INFO || type == CAMERA_VISIT ) // xx -> info ? { m_normEye = m_engine->RetEyePt(); m_normLookat = m_engine->RetLookatPt(); m_engine->SetFocus(1.00f); // normal m_type = type; return; } if ( m_type == CAMERA_INFO || m_type == CAMERA_VISIT ) // info -> xx ? { m_engine->SetFocus(m_focus); // gives initial focus m_type = type; vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); SetViewParams(m_normEye, m_normLookat, vUpVec); return; } if ( m_type == CAMERA_BACK && type == CAMERA_FREE ) // back -> free ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); } if ( m_type == CAMERA_BACK && type == CAMERA_EDIT ) // back -> edit ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f); } if ( m_type == CAMERA_ONBOARD && type == CAMERA_FREE ) // onboard -> free ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); } if ( m_type == CAMERA_ONBOARD && type == CAMERA_EDIT ) // onboard -> edit ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f); } if ( m_type == CAMERA_ONBOARD && type == CAMERA_EXPLO ) // onboard -> explo ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f); } if ( m_type == CAMERA_BACK && type == CAMERA_EXPLO ) // back -> explo ? { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f); } if ( type == CAMERA_FIX || type == CAMERA_PLANE ) { AbortCentering(); // Special stops framing } m_fixDist = 50.0f; if ( type == CAMERA_PLANE ) { m_fixDist = 60.0f; } if ( type == CAMERA_BACK ) { AbortCentering(); // Special stops framing m_addDirectionH = 0.0f; m_addDirectionV = -Math::PI*0.05f; if ( m_cameraObj == 0 ) oType = OBJECT_NULL; else oType = m_cameraObj->RetType(); m_backDist = 30.0f; if ( oType == OBJECT_BASE ) m_backDist = 200.0f; if ( oType == OBJECT_HUMAN ) m_backDist = 20.0f; if ( oType == OBJECT_TECH ) m_backDist = 20.0f; if ( oType == OBJECT_FACTORY ) m_backDist = 50.0f; if ( oType == OBJECT_RESEARCH ) m_backDist = 40.0f; if ( oType == OBJECT_DERRICK ) m_backDist = 40.0f; if ( oType == OBJECT_REPAIR ) m_backDist = 35.0f; if ( oType == OBJECT_DESTROYER) m_backDist = 35.0f; if ( oType == OBJECT_TOWER ) m_backDist = 45.0f; if ( oType == OBJECT_NUCLEAR ) m_backDist = 70.0f; if ( oType == OBJECT_PARA ) m_backDist = 180.0f; if ( oType == OBJECT_SAFE ) m_backDist = 50.0f; if ( oType == OBJECT_HUSTON ) m_backDist = 120.0f; m_backMin = m_backDist/3.0f; if ( oType == OBJECT_HUMAN ) m_backMin = 10.0f; if ( oType == OBJECT_TECH ) m_backMin = 10.0f; if ( oType == OBJECT_FACTORY ) m_backMin = 30.0f; if ( oType == OBJECT_RESEARCH ) m_backMin = 20.0f; if ( oType == OBJECT_NUCLEAR ) m_backMin = 32.0f; if ( oType == OBJECT_PARA ) m_backMin = 40.0f; if ( oType == OBJECT_SAFE ) m_backMin = 25.0f; if ( oType == OBJECT_HUSTON ) m_backMin = 80.0f; } if ( type != CAMERA_ONBOARD && m_cameraObj != 0 ) { m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right } if ( type == CAMERA_ONBOARD ) { m_focus = 1.50f; // Wide } else { m_focus = 1.00f; // normal } m_engine->SetFocus(m_focus); m_type = type; SetSmooth(CS_NORM); } CameraType CCamera::RetType() { return m_type; } // Management of the smoothing mode. void CCamera::SetSmooth(CameraSmooth type) { m_smooth = type; } CameraSmooth CCamera::RetSmoth() { return m_smooth; } // Management of the setback distance. void CCamera::SetDist(float dist) { m_fixDist = dist; } float CCamera::RetDist() { return m_fixDist; } // Manage angle mode CAMERA_FIX. void CCamera::SetFixDirection(float angle) { m_fixDirectionH = angle; } float CCamera::RetFixDirection() { return m_fixDirectionH; } // Managing the triggering mode of the camera panning. void CCamera::SetRemotePan(float value) { m_remotePan = value; } float CCamera::RetRemotePan() { return m_remotePan; } // Management of the remote zoom (0 .. 1) of the camera. void CCamera::SetRemoteZoom(float value) { value = Math::Norm(value); if ( m_type == CAMERA_BACK ) { m_backDist = m_backMin+(200.0f-m_backMin)*value; } if ( m_type == CAMERA_FIX || m_type == CAMERA_PLANE ) { m_fixDist = 10.0f+(200.0f-10.0f)*value; } } float CCamera::RetRemoteZoom() { if ( m_type == CAMERA_BACK ) { return (m_backDist-m_backMin)/(200.0f-m_backMin); } if ( m_type == CAMERA_FIX || m_type == CAMERA_PLANE ) { return (m_fixDist-10.0f)/(200.0f-10.0f); } return 0.0f; } // Start with a tour round the camera. void CCamera::StartVisit(Math::Vector goal, float dist) { m_visitType = m_type; SetType(CAMERA_VISIT); m_visitGoal = goal; m_visitDist = dist; m_visitTime = 0.0f; m_visitDirectionH = 0.0f; m_visitDirectionV = -Math::PI*0.10f; } // Circular end of a visit with the camera. void CCamera::StopVisit() { SetType(m_visitType); // presents the initial type } // Returns the point of view of the camera. void CCamera::RetCamera(Math::Vector &eye, Math::Vector &lookat) { eye = m_eyePt; lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f); } // Specifies a special movement of camera to frame action. bool CCamera::StartCentering(CObject *object, float angleH, float angleV, float dist, float time) { if ( m_type != CAMERA_BACK ) return false; if ( object != m_cameraObj ) return false; if ( m_centeringPhase != CP_NULL ) return false; if ( m_addDirectionH > Math::PI ) { angleH = Math::PI*2.0f-angleH; } m_centeringPhase = CP_START; m_centeringAngleH = angleH; m_centeringAngleV = angleV; m_centeringDist = dist; m_centeringCurrentH = 0.0f; m_centeringCurrentV = 0.0f; m_centeringTime = time; m_centeringProgress = 0.0f; return true; } // Ends a special movement of camera to frame action. bool CCamera::StopCentering(CObject *object, float time) { if ( m_type != CAMERA_BACK ) return false; if ( object != m_cameraObj ) return false; if ( m_centeringPhase != CP_START && m_centeringPhase != CP_WAIT ) return false; m_centeringPhase = CP_STOP; if ( m_centeringAngleH != 99.9f ) { m_centeringAngleH = m_centeringCurrentH; } if ( m_centeringAngleV != 99.9f ) { m_centeringAngleV = m_centeringCurrentV; } m_centeringTime = time; m_centeringProgress = 0.0f; return true; } // Stop framing special in the current position. void CCamera::AbortCentering() { if ( m_type == CAMERA_INFO || m_type == CAMERA_VISIT ) return; if ( m_centeringPhase == CP_NULL ) return; m_centeringPhase = CP_NULL; if ( m_centeringAngleH != 99.9f ) { m_addDirectionH = m_centeringCurrentH; } if ( m_centeringAngleV != 99.9f ) { m_addDirectionV = m_centeringCurrentV; } } // Removes the special effect with the camera void CCamera::FlushEffect() { m_effectType = CE_NULL; m_effectForce = 0.0f; m_effectProgress = 0.0f; m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); } // Starts a special effect with the camera. void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force) { if ( !m_bEffect ) return; m_effectType = effect; m_effectPos = pos; m_effectForce = force; m_effectProgress = 0.0f; } // Advances the effect of the camera. void CCamera::EffectFrame(const Event &event) { float dist, force; if ( m_type == CAMERA_INFO || m_type == CAMERA_VISIT ) return; if ( m_effectType == CE_NULL ) return; m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f); force = m_effectForce; if ( m_effectType == CE_TERRAFORM ) { m_effectProgress += event.rTime*0.7f; m_effectOffset.x = (Math::Rand()-0.5f)*10.0f; m_effectOffset.y = (Math::Rand()-0.5f)*10.0f; m_effectOffset.z = (Math::Rand()-0.5f)*10.0f; force *= 1.0f-m_effectProgress; } if ( m_effectType == CE_EXPLO ) { m_effectProgress += event.rTime*1.0f; m_effectOffset.x = (Math::Rand()-0.5f)*5.0f; m_effectOffset.y = (Math::Rand()-0.5f)*5.0f; m_effectOffset.z = (Math::Rand()-0.5f)*5.0f; force *= 1.0f-m_effectProgress; } if ( m_effectType == CE_SHOT ) { m_effectProgress += event.rTime*1.0f; m_effectOffset.x = (Math::Rand()-0.5f)*2.0f; m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; m_effectOffset.z = (Math::Rand()-0.5f)*2.0f; force *= 1.0f-m_effectProgress; } if ( m_effectType == CE_CRASH ) { m_effectProgress += event.rTime*5.0f; m_effectOffset.y = sinf(m_effectProgress*Math::PI)*1.5f; m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); } if ( m_effectType == CE_VIBRATION ) { m_effectProgress += event.rTime*0.1f; m_effectOffset.y = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); m_effectOffset.x = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); m_effectOffset.z = (Math::Rand()-0.5f)*1.0f*(1.0f-m_effectProgress); } if ( m_effectType == CE_PET ) { m_effectProgress += event.rTime*5.0f; m_effectOffset.x = (Math::Rand()-0.5f)*0.2f; m_effectOffset.y = (Math::Rand()-0.5f)*2.0f; m_effectOffset.z = (Math::Rand()-0.5f)*0.2f; } dist = Math::Distance(m_eyePt, m_effectPos); dist = Math::Norm((dist-100.f)/100.0f); force *= 1.0f-dist; #if _TEEN force *= 2.0f; #endif m_effectOffset *= force; if ( m_effectProgress >= 1.0f ) { FlushEffect(); } } // Removes the effect of superposition in the foreground. void CCamera::FlushOver() { m_overType = OE_NULL; m_overColorBase.r = 0.0f; // black m_overColorBase.g = 0.0f; m_overColorBase.b = 0.0f; m_overColorBase.a = 0.0f; m_engine->SetOverColor(); // nothing } // Specifies the base color. void CCamera::SetOverBaseColor(D3DCOLORVALUE color) { m_overColorBase = color; } // Starts a layering effect in the foreground. void CCamera::StartOver(OverEffect effect, Math::Vector pos, float force) { D3DCOLOR color; float dist, decay; m_overType = effect; m_overTime = 0.0f; if ( m_overType == OE_BLITZ ) decay = 400.0f; else decay = 100.0f; dist = Math::Distance(m_eyePt, pos); dist = (dist-decay)/decay; if ( dist < 0.0f ) dist = 0.0f; if ( dist > 1.0f ) dist = 1.0f; m_overForce = force * (1.0f-dist); if ( m_overType == OE_BLOOD ) { m_overColor.r = 0.8f; m_overColor.g = 0.1f; m_overColor.b = 0.1f; // red m_overMode = D3DSTATETCb; m_overFadeIn = 0.4f; m_overFadeOut = 0.8f; m_overForce = 1.0f; } if ( m_overType == OE_FADEINw ) { m_overColor.r = 1.0f; m_overColor.g = 1.0f; m_overColor.b = 1.0f; // white m_overMode = D3DSTATETCb; m_overFadeIn = 0.0f; m_overFadeOut =20.0f; m_overForce = 1.0f; } if ( m_overType == OE_FADEOUTw ) { m_overColor.r = 1.0f; m_overColor.g = 1.0f; m_overColor.b = 1.0f; // white m_overMode = D3DSTATETCb; m_overFadeIn = 6.0f; m_overFadeOut = 100000.0f; m_overForce = 1.0f; } if ( m_overType == OE_FADEOUTb ) { color = m_engine->RetFogColor(1); // fog color underwater m_overColor = RetColor(color); m_overMode = D3DSTATETCw; m_overFadeIn = 4.0f; m_overFadeOut = 100000.0f; m_overForce = 1.0f; } if ( m_overType == OE_BLITZ ) { m_overColor.r = 0.9f; m_overColor.g = 1.0f; m_overColor.b = 1.0f; // white-cyan m_overMode = D3DSTATETCb; m_overFadeIn = 0.0f; m_overFadeOut = 1.0f; } } // Advanced overlay effect in the foreground. void CCamera::OverFrame(const Event &event) { D3DCOLORVALUE color; float intensity; if ( m_type == CAMERA_INFO || m_type == CAMERA_VISIT ) return; if ( m_overType == OE_NULL ) { return; } m_overTime += event.rTime; if ( m_overType == OE_BLITZ ) { if ( rand()%2 == 0 ) { color.r = m_overColor.r*m_overForce; color.g = m_overColor.g*m_overForce; color.b = m_overColor.b*m_overForce; } else { color.r = 0.0f; color.g = 0.0f; color.b = 0.0f; } color.a = 0.0f; m_engine->SetOverColor(RetColor(color), m_overMode); } else { if ( m_overFadeIn > 0.0f && m_overTime < m_overFadeIn ) { intensity = m_overTime/m_overFadeIn; intensity *= m_overForce; if ( m_overMode == D3DSTATETCw ) { color.r = 1.0f-(1.0f-m_overColor.r)*intensity; color.g = 1.0f-(1.0f-m_overColor.g)*intensity; color.b = 1.0f-(1.0f-m_overColor.b)*intensity; } else { color.r = m_overColor.r*intensity; color.g = m_overColor.g*intensity; color.b = m_overColor.b*intensity; color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); } color.a = 0.0f; m_engine->SetOverColor(RetColor(color), m_overMode); } else if ( m_overFadeOut > 0.0f && m_overTime-m_overFadeIn < m_overFadeOut ) { intensity = 1.0f-(m_overTime-m_overFadeIn)/m_overFadeOut; intensity *= m_overForce; if ( m_overMode == D3DSTATETCw ) { color.r = 1.0f-(1.0f-m_overColor.r)*intensity; color.g = 1.0f-(1.0f-m_overColor.g)*intensity; color.b = 1.0f-(1.0f-m_overColor.b)*intensity; } else { color.r = m_overColor.r*intensity; color.g = m_overColor.g*intensity; color.b = m_overColor.b*intensity; color.r = 1.0f-(1.0f-color.r)*(1.0f-m_overColorBase.r); color.g = 1.0f-(1.0f-color.g)*(1.0f-m_overColorBase.g); color.b = 1.0f-(1.0f-color.b)*(1.0f-m_overColorBase.b); } color.a = 0.0f; m_engine->SetOverColor(RetColor(color), m_overMode); } } if ( m_overTime >= m_overFadeIn+m_overFadeOut ) { FlushOver(); return; } } // Sets the soft movement of the camera. void CCamera::FixCamera() { m_initDelay = 0.0f; m_actualEye = m_finalEye = m_scriptEye; m_actualLookat = m_finalLookat = m_scriptLookat; SetViewTime(m_scriptEye, m_scriptLookat, 0.0f); } // Specifies the location and direction of view to the 3D engine. void CCamera::SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime) { Math::Vector vUpVec, eye, lookat; float prog, dist, h; if ( m_type == CAMERA_INFO ) { eye = vEyePt; lookat = vLookatPt; } else { if ( m_initDelay > 0.0f ) { m_initDelay -= rTime; if ( m_initDelay < 0.0f ) m_initDelay = 0.0f; rTime /= 1.0f+m_initDelay; } eye = vEyePt; lookat = vLookatPt; if ( !IsCollision(eye, lookat) ) { m_finalEye = eye; m_finalLookat = lookat; } dist = Math::Distance(m_finalEye, m_actualEye); if ( m_smooth == CS_NONE ) prog = dist; if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*0.5f; if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*0.05f; if ( dist == 0.0f ) { m_actualEye = m_finalEye; } else { if ( prog > dist ) prog = dist; m_actualEye = (m_finalEye-m_actualEye)/dist*prog + m_actualEye; } dist = Math::Distance(m_finalLookat, m_actualLookat); if ( m_smooth == CS_NONE ) prog = dist; if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*2.0f; if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f; if ( m_smooth == CS_SPEC ) prog = powf(dist, 1.0f)*rTime*4.0f; if ( dist == 0.0f ) { m_actualLookat = m_finalLookat; } else { if ( prog > dist ) prog = dist; m_actualLookat = (m_finalLookat-m_actualLookat)/dist*prog + m_actualLookat; } eye = m_effectOffset+m_actualEye; m_water->AdjustEye(eye); h = m_terrain->RetFloorLevel(eye); if ( eye.y < h+4.0f ) { eye.y = h+4.0f; } lookat = m_effectOffset+m_actualLookat; } vUpVec = Math::Vector(0.0f, 1.0f, 0.0f); SetViewParams(eye, lookat, vUpVec); } // Avoid the obstacles. bool CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat) { if ( m_type == CAMERA_BACK ) return IsCollisionBack(eye, lookat); if ( m_type == CAMERA_FIX ) return IsCollisionFix(eye, lookat); if ( m_type == CAMERA_PLANE ) return IsCollisionFix(eye, lookat); return false; } // Avoid the obstacles. bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat) { #if 0 CObject *pObj; Math::Vector oPos, min, max, proj; ObjectType oType, iType; float oRadius, dpp, dpl, del, dist, len, prox; int i; if ( m_cameraObj == 0 ) { iType = OBJECT_NULL; } else { iType = m_cameraObj->RetType(); } min.x = Math::Min(eye.x, lookat.x); min.y = Math::Min(eye.y, lookat.y); min.z = Math::Min(eye.z, lookat.z); max.x = Math::Max(eye.x, lookat.x); max.y = Math::Max(eye.y, lookat.y); max.z = Math::Max(eye.z, lookat.z); prox = 8.0f; // maximum proximity of the vehicle for ( i=0 ; i<1000000 ; i++ ) { pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); if ( pObj == 0 ) break; if ( pObj == m_cameraObj ) continue; oType = pObj->RetType(); if ( oType == OBJECT_TOTO || oType == OBJECT_FIX || oType == OBJECT_FRET || oType == OBJECT_STONE || oType == OBJECT_URANIUM || oType == OBJECT_METAL || oType == OBJECT_POWER || oType == OBJECT_ATOMIC || oType == OBJECT_BULLET || oType == OBJECT_BBOX || oType == OBJECT_TNT || oType == OBJECT_BOMB || oType == OBJECT_WAYPOINTb || oType == OBJECT_WAYPOINTr || oType == OBJECT_WAYPOINTg || oType == OBJECT_WAYPOINTy || oType == OBJECT_WAYPOINTv || oType == OBJECT_FLAGb || oType == OBJECT_FLAGr || oType == OBJECT_FLAGg || oType == OBJECT_FLAGy || oType == OBJECT_FLAGv || oType == OBJECT_ANT || oType == OBJECT_SPIDER || oType == OBJECT_BEE || oType == OBJECT_WORM ) continue; pObj->GetGlobalSphere(oPos, oRadius); if ( oRadius <= 0.0f ) continue; if ( oPos.x+oRadius < min.x || oPos.y+oRadius < min.y || oPos.z+oRadius < min.z || oPos.x-oRadius > max.x || oPos.y-oRadius > max.y || oPos.z-oRadius > max.z ) continue; if ( iType == OBJECT_FACTORY ) { dpl = Math::Distance(oPos, lookat); if ( dpl < oRadius ) continue; } proj = Projection(eye, lookat, oPos); dpp = Math::Distance(proj, oPos); if ( dpp > oRadius ) continue; del = Math::Distance(eye, lookat); len = Math::Distance(eye, proj); if ( len > del ) continue; dist = sqrtf(oRadius*oRadius + dpp*dpp)-3.0f; if ( dist < 0.0f ) dist = 0.0f; proj = (lookat-eye)*dist/del + proj; len = Math::Distance(eye, proj); if ( len < del-prox ) { eye = proj; eye.y += len/5.0f; return false; } else { eye = (eye-lookat)*prox/del + lookat; eye.y += (del-prox)/5.0f; return false; } } return false; #else CObject *pObj; Math::Vector oPos, min, max, proj; ObjectType oType, iType; float oRadius, dpp, del, len, angle; int i; if ( m_cameraObj == 0 ) { iType = OBJECT_NULL; } else { iType = m_cameraObj->RetType(); } min.x = Math::Min(m_actualEye.x, m_actualLookat.x); min.y = Math::Min(m_actualEye.y, m_actualLookat.y); min.z = Math::Min(m_actualEye.z, m_actualLookat.z); max.x = Math::Max(m_actualEye.x, m_actualLookat.x); max.y = Math::Max(m_actualEye.y, m_actualLookat.y); max.z = Math::Max(m_actualEye.z, m_actualLookat.z); m_bTransparency = false; for ( i=0 ; i<1000000 ; i++ ) { pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); if ( pObj == 0 ) break; if ( pObj->RetTruck() ) continue; // battery or cargo? SetTransparency(pObj, 0.0f); // opaque object if ( pObj == m_cameraObj ) continue; if ( iType == OBJECT_BASE || // building? iType == OBJECT_DERRICK || iType == OBJECT_FACTORY || iType == OBJECT_STATION || iType == OBJECT_CONVERT || iType == OBJECT_REPAIR || iType == OBJECT_DESTROYER|| iType == OBJECT_TOWER || iType == OBJECT_RESEARCH || iType == OBJECT_RADAR || iType == OBJECT_ENERGY || iType == OBJECT_LABO || iType == OBJECT_NUCLEAR || iType == OBJECT_PARA || iType == OBJECT_SAFE || iType == OBJECT_HUSTON ) continue; oType = pObj->RetType(); if ( oType == OBJECT_HUMAN || oType == OBJECT_TECH || oType == OBJECT_TOTO || oType == OBJECT_FIX || oType == OBJECT_FRET || oType == OBJECT_ANT || oType == OBJECT_SPIDER || oType == OBJECT_BEE || oType == OBJECT_WORM ) continue; pObj->GetGlobalSphere(oPos, oRadius); if ( oRadius <= 2.0f ) continue; // ignores small objects if ( oPos.x+oRadius < min.x || oPos.y+oRadius < min.y || oPos.z+oRadius < min.z || oPos.x-oRadius > max.x || oPos.y-oRadius > max.y || oPos.z-oRadius > max.z ) continue; proj = Projection(m_actualEye, m_actualLookat, oPos); dpp = Math::Distance(proj, oPos); if ( dpp > oRadius ) continue; if ( oType == OBJECT_FACTORY ) { angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW ! angle = Math::Direction(angle, pObj->RetAngleY(0)); if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate? } del = Math::Distance(m_actualEye, m_actualLookat); if ( oType == OBJECT_FACTORY ) { del += oRadius; } len = Math::Distance(m_actualEye, proj); if ( len > del ) continue; SetTransparency(pObj, 1.0f); // transparent object m_bTransparency = true; } return false; #endif } // Avoid the obstacles. bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat) { CObject *pObj; Math::Vector oPos, proj; ObjectType type; float oRadius, dist; int i; for ( i=0 ; i<1000000 ; i++ ) { pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); if ( pObj == 0 ) break; if ( pObj == m_cameraObj ) continue; type = pObj->RetType(); if ( type == OBJECT_TOTO || type == OBJECT_FRET || type == OBJECT_STONE || type == OBJECT_URANIUM || type == OBJECT_METAL || type == OBJECT_POWER || type == OBJECT_ATOMIC || type == OBJECT_BULLET || type == OBJECT_BBOX || type == OBJECT_KEYa || type == OBJECT_KEYb || type == OBJECT_KEYc || type == OBJECT_KEYd || type == OBJECT_ANT || type == OBJECT_SPIDER || type == OBJECT_BEE || type == OBJECT_WORM ) continue; pObj->GetGlobalSphere(oPos, oRadius); if ( oRadius == 0.0f ) continue; dist = Math::Distance(eye, oPos); if ( dist < oRadius ) { dist = Math::Distance(eye, lookat); proj = Projection(eye, lookat, oPos); eye = (lookat-eye)*oRadius/dist + proj; return false; } } return false; } // Management of an event. bool CCamera::EventProcess(const Event &event) { switch( event.event ) { case EVENT_FRAME: EventFrame(event); break; #if 0 case EVENT_RBUTTONDOWN: m_bRightDown = true; m_rightPosInit = event.pos; m_rightPosCenter = Math::Point(0.5f, 0.5f); m_engine->MoveMousePos(m_rightPosCenter); //? m_engine->SetMouseHide(true); // cache la souris break; case EVENT_RBUTTONUP: m_bRightDown = false; m_engine->MoveMousePos(m_rightPosInit); //? m_engine->SetMouseHide(false); // remontre la souris m_addDirectionH = 0.0f; m_addDirectionV = -Math::PI*0.05f; break; #endif case EVENT_MOUSEMOVE: EventMouseMove(event); break; case EVENT_KEYDOWN: if ( event.param == VK_WHEELUP ) EventMouseWheel(+1); if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1); break; } return true; } // Changed the camera according to the mouse moved. bool CCamera::EventMouseMove(const Event &event) { m_mousePos = event.pos; return true; } // Mouse wheel operated. void CCamera::EventMouseWheel(int dir) { if ( m_type == CAMERA_BACK ) { if ( dir > 0 ) { m_backDist -= 8.0f; if ( m_backDist < m_backMin ) m_backDist = m_backMin; } if ( dir < 0 ) { m_backDist += 8.0f; if ( m_backDist > 200.0f ) m_backDist = 200.0f; } } if ( m_type == CAMERA_FIX || m_type == CAMERA_PLANE ) { if ( dir > 0 ) { m_fixDist -= 8.0f; if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; } if ( dir < 0 ) { m_fixDist += 8.0f; if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; } } if ( m_type == CAMERA_VISIT ) { if ( dir > 0 ) { m_visitDist -= 8.0f; if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; } if ( dir < 0 ) { m_visitDist += 8.0f; if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; } } } // Changed the camera according to the time elapsed. bool CCamera::EventFrame(const Event &event) { EffectFrame(event); OverFrame(event); if ( m_type == CAMERA_FREE ) { return EventFrameFree(event); } if ( m_type == CAMERA_EDIT ) { return EventFrameEdit(event); } if ( m_type == CAMERA_DIALOG ) { return EventFrameDialog(event); } if ( m_type == CAMERA_BACK ) { return EventFrameBack(event); } if ( m_type == CAMERA_FIX || m_type == CAMERA_PLANE ) { return EventFrameFix(event); } if ( m_type == CAMERA_EXPLO ) { return EventFrameExplo(event); } if ( m_type == CAMERA_ONBOARD ) { return EventFrameOnBoard(event); } if ( m_type == CAMERA_SCRIPT ) { return EventFrameScript(event); } if ( m_type == CAMERA_INFO ) { return EventFrameInfo(event); } if ( m_type == CAMERA_VISIT ) { return EventFrameVisit(event); } return true; } // Returns the default sprite to use for the mouse. D3DMouse CCamera::RetMouseDef(Math::Point pos) { D3DMouse type; type = D3DMOUSENORM; m_mousePos = pos; if ( m_type == CAMERA_INFO ) return type; if ( m_bRightDown ) // the right button pressed? { m_rightPosMove.x = pos.x - m_rightPosCenter.x; m_rightPosMove.y = pos.y - m_rightPosCenter.y; type = D3DMOUSEMOVE; } else { if ( !m_bCameraScroll ) return type; m_mouseDirH = 0.0f; m_mouseDirV = 0.0f; if ( pos.x < m_mouseMarging ) { m_mouseDirH = pos.x/m_mouseMarging - 1.0f; } if ( pos.x > 1.0f-m_mouseMarging ) { m_mouseDirH = 1.0f - (1.0f-pos.x)/m_mouseMarging; } if ( pos.y < m_mouseMarging ) { m_mouseDirV = pos.y/m_mouseMarging - 1.0f; } if ( pos.y > 1.0f-m_mouseMarging ) { m_mouseDirV = 1.0f - (1.0f-pos.y)/m_mouseMarging; } if ( m_type == CAMERA_FREE || m_type == CAMERA_EDIT || m_type == CAMERA_BACK || m_type == CAMERA_FIX || m_type == CAMERA_PLANE || m_type == CAMERA_EXPLO ) { if ( m_mouseDirH > 0.0f ) { type = D3DMOUSESCROLLR; } if ( m_mouseDirH < 0.0f ) { type = D3DMOUSESCROLLL; } } if ( m_type == CAMERA_FREE || m_type == CAMERA_EDIT ) { if ( m_mouseDirV > 0.0f ) { type = D3DMOUSESCROLLU; } if ( m_mouseDirV < 0.0f ) { type = D3DMOUSESCROLLD; } } if ( m_bCameraInvertX ) { m_mouseDirH = -m_mouseDirH; } } return type; } // Moves the point of view. bool CCamera::EventFrameFree(const Event &event) { Math::Vector pos, vLookatPt; float factor; factor = m_heightEye*0.5f+30.0f; if ( m_mouseDirH != 0.0f ) { m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; } if ( m_mouseDirV != 0.0f ) { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); } // Up/Down. m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, event.axeY*event.rTime*factor*m_speed); // Left/Right. if ( event.keyState & KS_CONTROL ) { if ( event.axeX < 0.0f ) { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH+Math::PI/2.0f, m_directionV, -event.axeX*event.rTime*factor*m_speed); } if ( event.axeX > 0.0f ) { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH-Math::PI/2.0f, m_directionV, event.axeX*event.rTime*factor*m_speed); } } else { m_directionH -= event.axeX*event.rTime*0.7f*m_speed; } // PageUp/PageDown. if ( event.keyState & KS_NUMMINUS ) { if ( m_heightEye < 500.0f ) { m_heightEye += event.rTime*factor*m_speed; } } if ( event.keyState & KS_NUMPLUS ) { if ( m_heightEye > -2.0f ) { m_heightEye -= event.rTime*factor*m_speed; } } m_terrain->ValidPosition(m_eyePt, 10.0f); if ( m_terrain->MoveOnFloor(m_eyePt, true) ) { m_eyePt.y += m_heightEye; pos = m_eyePt; if ( m_terrain->MoveOnFloor(pos, true) ) { pos.y -= 2.0f; if ( m_eyePt.y < pos.y ) { m_eyePt.y = pos.y; } } } vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); if ( m_terrain->MoveOnFloor(vLookatPt, true) ) { vLookatPt.y += m_heightLookat; } SetViewTime(m_eyePt, vLookatPt, event.rTime); return true; } // Moves the point of view. bool CCamera::EventFrameEdit(const Event &event) { Math::Vector pos, vLookatPt; float factor; factor = m_editHeight*0.5f+30.0f; if ( m_mouseDirH != 0.0f ) { m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; } if ( m_mouseDirV != 0.0f ) { m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed); } if ( m_bCameraScroll ) { // Left/Right. m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; m_fixDirectionH = Math::NormAngle(m_fixDirectionH); // Up/Down. //? m_fixDirectionV -= m_mouseDirV*event.rTime*0.5f*m_speed; //? if ( m_fixDirectionV < -Math::PI*0.40f ) m_fixDirectionV = -Math::PI*0.40f; //? if ( m_fixDirectionV > Math::PI*0.20f ) m_fixDirectionV = Math::PI*0.20f; } m_terrain->ValidPosition(m_eyePt, 10.0f); if ( m_terrain->MoveOnFloor(m_eyePt, false) ) { m_eyePt.y += m_editHeight; pos = m_eyePt; if ( m_terrain->MoveOnFloor(pos, false) ) { pos.y += 2.0f; if ( m_eyePt.y < pos.y ) { m_eyePt.y = pos.y; } } } vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); if ( m_terrain->MoveOnFloor(vLookatPt, true) ) { vLookatPt.y += m_heightLookat; } SetViewTime(m_eyePt, vLookatPt, event.rTime); return true; } // Moves the point of view. bool CCamera::EventFrameDialog(const Event &event) { return true; } // Moves the point of view. bool CCamera::EventFrameBack(const Event &event) { CPhysics* physics; ObjectType type; Math::Vector pos, vLookatPt; Math::Point mouse; float centeringH, centeringV, centeringD, h, v, d, floor; if ( m_cameraObj == 0 ) { type = OBJECT_NULL; } else { type = m_cameraObj->RetType(); } // +/-. if ( event.keyState & KS_NUMPLUS ) { m_backDist -= event.rTime*30.0f*m_speed; if ( m_backDist < m_backMin ) m_backDist = m_backMin; } if ( event.keyState & KS_NUMMINUS ) { m_backDist += event.rTime*30.0f*m_speed; if ( m_backDist > 200.0f ) m_backDist = 200.0f; } m_motorTurn = 0.0f; if ( m_bRightDown ) { m_addDirectionH = m_rightPosMove.x*6.0f; m_addDirectionV = -m_rightPosMove.y*2.0f; } else { if ( m_bCameraScroll ) { #if 1 // Left/Right. m_addDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; m_addDirectionH = Math::NormAngle(m_addDirectionH); // Up/Down. //? m_backDist -= m_mouseDirV*event.rTime*30.0f*m_speed; //? if ( m_backDist < 10.0f ) m_backDist = 10.0f; //? if ( m_backDist > 200.0f ) m_backDist = 200.0f; #else if ( m_mousePos.y >= 0.18f && m_mousePos.y <= 0.93f ) { //? m_addDirectionH = -(m_mousePos.x-0.5f)*4.0f; m_addDirectionV = (m_mousePos.y-0.5f)*2.0f; //? if ( m_bCameraInvertX ) m_addDirectionH = -m_addDirectionH; if ( m_bCameraInvertY ) m_addDirectionV = -m_addDirectionV; if ( m_mousePos.x < 0.5f ) m_motorTurn = -1.0f; if ( m_mousePos.x > 0.5f ) m_motorTurn = 1.0f; mouse = m_mousePos; mouse.x = 0.5f; m_engine->MoveMousePos(mouse); } else { m_addDirectionH = 0.0f; m_addDirectionV = 0.0f; } #endif } } if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) { AbortCentering(); // special stops framing } // Increase the special framework. centeringH = 0.0f; centeringV = 0.0f; centeringD = 0.0f; if ( m_centeringPhase == CP_START ) { m_centeringProgress += event.rTime/m_centeringTime; if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; centeringH = m_centeringProgress; centeringV = m_centeringProgress; centeringD = m_centeringProgress; if ( m_centeringProgress >= 1.0f ) { m_centeringPhase = CP_WAIT; } } if ( m_centeringPhase == CP_WAIT ) { centeringH = 1.0f; centeringV = 1.0f; centeringD = 1.0f; } if ( m_centeringPhase == CP_STOP ) { m_centeringProgress += event.rTime/m_centeringTime; if ( m_centeringProgress > 1.0f ) m_centeringProgress = 1.0f; centeringH = 1.0f-m_centeringProgress; centeringV = 1.0f-m_centeringProgress; centeringD = 1.0f-m_centeringProgress; if ( m_centeringProgress >= 1.0f ) { m_centeringPhase = CP_NULL; } } if ( m_centeringAngleH == 99.9f ) centeringH = 0.0f; if ( m_centeringAngleV == 99.9f ) centeringV = 0.0f; if ( m_centeringDist == 0.0f ) centeringD = 0.0f; if ( m_cameraObj != 0 ) { vLookatPt = m_cameraObj->RetPosition(0); if ( type == OBJECT_BASE ) vLookatPt.y += 40.0f; else if ( type == OBJECT_HUMAN ) vLookatPt.y += 1.0f; else if ( type == OBJECT_TECH ) vLookatPt.y += 1.0f; else vLookatPt.y += 4.0f; h = -m_cameraObj->RetAngleY(0); // angle vehicle / building if ( type == OBJECT_DERRICK || type == OBJECT_FACTORY || type == OBJECT_REPAIR || type == OBJECT_DESTROYER|| type == OBJECT_STATION || type == OBJECT_CONVERT || type == OBJECT_TOWER || type == OBJECT_RESEARCH || type == OBJECT_RADAR || type == OBJECT_INFO || type == OBJECT_ENERGY || type == OBJECT_LABO || type == OBJECT_NUCLEAR || type == OBJECT_PARA || type == OBJECT_SAFE || type == OBJECT_HUSTON || type == OBJECT_START || type == OBJECT_END ) // building? { h += Math::PI*0.20f; // nearly face } else // vehicle? { h += Math::PI; // back } h = Math::NormAngle(h)+m_remotePan; v = 0.0f; //? h += m_centeringCurrentH; h += m_addDirectionH*(1.0f-centeringH); h = Math::NormAngle(h); if ( type == OBJECT_MOBILEdr ) // designer? { v -= 0.3f; // Camera top } v += m_centeringCurrentV; v += m_addDirectionV*(1.0f-centeringV); d = m_backDist; d += m_centeringDist*centeringD; m_centeringCurrentH = m_centeringAngleH*centeringH; m_centeringCurrentV = m_centeringAngleV*centeringV; m_eyePt = RotateView(vLookatPt, h, v, d); physics = m_cameraObj->RetPhysics(); if ( physics != 0 && physics->RetLand() ) // ground? { pos = vLookatPt+(vLookatPt-m_eyePt); floor = m_terrain->RetFloorHeight(pos)-4.0f; if ( floor > 0.0f ) { m_eyePt.y += floor; // shows the descent in front } } m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); SetViewTime(m_eyePt, vLookatPt, event.rTime); m_directionH = h+Math::PI/2.0f; m_directionV = v; } return true; } // Moves the point of view. bool CCamera::EventFrameFix(const Event &event) { Math::Vector pos, vLookatPt; float h, v, d; // +/-. if ( event.keyState & KS_NUMPLUS ) { m_fixDist -= event.rTime*30.0f*m_speed; if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; } if ( event.keyState & KS_NUMMINUS ) { m_fixDist += event.rTime*30.0f*m_speed; if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; } if ( m_bCameraScroll ) { // Left/Right. m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed; m_fixDirectionH = Math::NormAngle(m_fixDirectionH); // Up/Down. //? m_fixDist -= m_mouseDirV*event.rTime*30.0f*m_speed; //? if ( m_fixDist < 10.0f ) m_fixDist = 10.0f; //? if ( m_fixDist > 200.0f ) m_fixDist = 200.0f; } if ( m_mouseDirH != 0 || m_mouseDirV != 0 ) { AbortCentering(); // special stops framing } if ( m_cameraObj != 0 ) { vLookatPt = m_cameraObj->RetPosition(0); h = m_fixDirectionH+m_remotePan; v = m_fixDirectionV; d = m_fixDist; //- if ( m_type == CAMERA_PLANE ) d += 20.0f; m_eyePt = RotateView(vLookatPt, h, v, d); //- if ( m_type == CAMERA_PLANE ) m_eyePt.y += 50.0f; if ( m_type == CAMERA_PLANE ) m_eyePt.y += m_fixDist/2.0f; m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v); m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v); SetViewTime(m_eyePt, vLookatPt, event.rTime); m_directionH = h+Math::PI/2.0f; m_directionV = v; } return true; } // Moves the point of view. bool CCamera::EventFrameExplo(const Event &event) { Math::Vector pos, vLookatPt; float factor; factor = m_heightEye*0.5f+30.0f; if ( m_mouseDirH != 0.0f ) { m_directionH -= m_mouseDirH*event.rTime*0.7f*m_speed; } m_terrain->ValidPosition(m_eyePt, 10.0f); if ( m_terrain->MoveOnFloor(m_eyePt, false) ) { m_eyePt.y += m_heightEye; pos = m_eyePt; if ( m_terrain->MoveOnFloor(pos, false) ) { pos.y += 2.0f; if ( m_eyePt.y < pos.y ) { m_eyePt.y = pos.y; } } } vLookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f ); if ( m_terrain->MoveOnFloor(vLookatPt, true) ) { vLookatPt.y += m_heightLookat; } SetViewTime(m_eyePt, vLookatPt, event.rTime); return true; } // Moves the point of view. bool CCamera::EventFrameOnBoard(const Event &event) { Math::Vector vLookatPt, vUpVec, eye, lookat, pos; if ( m_cameraObj != 0 ) { m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV, vLookatPt, vUpVec, m_type); eye = m_effectOffset*0.3f+m_eyePt; lookat = m_effectOffset*0.3f+vLookatPt; SetViewParams(eye, lookat, vUpVec); m_actualEye = eye; m_actualLookat = lookat; } return true; } // Moves the point of view. bool CCamera::EventFrameInfo(const Event &event) { SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f), event.rTime); return true; } // Moves the point of view. bool CCamera::EventFrameVisit(const Event &event) { Math::Vector eye; float angleH, angleV; m_visitTime += event.rTime; // +/-. if ( event.keyState & KS_NUMPLUS ) { m_visitDist -= event.rTime*50.0f*m_speed; if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; } if ( event.keyState & KS_NUMMINUS ) { m_visitDist += event.rTime*50.0f*m_speed; if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; } // PageUp/Down. if ( event.keyState & KS_PAGEUP ) { m_visitDirectionV -= event.rTime*1.0f*m_speed; if ( m_visitDirectionV < -Math::PI*0.40f ) m_visitDirectionV = -Math::PI*0.40f; } if ( event.keyState & KS_PAGEDOWN ) { m_visitDirectionV += event.rTime*1.0f*m_speed; if ( m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f; } if ( m_bCameraScroll ) { m_visitDist -= m_mouseDirV*event.rTime*30.0f*m_speed; if ( m_visitDist < 20.0f ) m_visitDist = 20.0f; if ( m_visitDist > 200.0f ) m_visitDist = 200.0f; } angleH = (m_visitTime/10.0f)*(Math::PI*2.0f); angleV = m_visitDirectionV; eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist); eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV); eye = ExcludeObject(eye, m_visitGoal, angleH, angleV); SetViewTime(eye, m_visitGoal, event.rTime); return true; } // Moves the point of view. bool CCamera::EventFrameScript(const Event &event) { SetViewTime(m_scriptEye+m_effectOffset, m_scriptLookat+m_effectOffset, event.rTime); return true; } void CCamera::SetScriptEye(Math::Vector eye) { m_scriptEye = eye; } void CCamera::SetScriptLookat(Math::Vector lookat) { m_scriptLookat = lookat; } // Specifies the location and direction of view. void CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up) { bool bUnder; m_engine->SetViewParams(eye, lookat, up, m_eyeDistance); bUnder = (eye.y < m_water->RetLevel()); // Is it underwater? if ( m_type == CAMERA_INFO ) bUnder = false; m_engine->SetRankView(bUnder?1:0); } // Adjusts the camera not to enter the field. Math::Vector CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV) { Math::Vector pos; float dist; pos = eye; if ( m_terrain->MoveOnFloor(pos) ) { dist = Math::DistanceProjected(lookat, pos); pos.y += 2.0f+dist*0.1f; if ( pos.y > eye.y ) { angleV = -Math::RotateAngle(dist, pos.y-lookat.y); eye = RotateView(lookat, angleH, angleV, dist); } } return eye; } // Adjusts the camera not to enter an object. Math::Vector CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV) { CObject* pObj; Math::Vector oPos; float oRad, dist; int i, j; return eye; //? for ( i=0 ; i<1000000 ; i++ ) { pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i); if ( pObj == 0 ) break; j = 0; while ( pObj->GetCrashSphere(j++, oPos, oRad) ) { dist = Math::Distance(oPos, eye); if ( dist < oRad+2.0f ) { eye.y = oPos.y+oRad+2.0f; } } } return eye; }