1730 lines
48 KiB
C++
1730 lines
48 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2016, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
|
*
|
|
* 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://gnu.org/licenses
|
|
*/
|
|
|
|
|
|
#include "graphics/engine/camera.h"
|
|
|
|
#include "app/app.h"
|
|
#include "app/input.h"
|
|
|
|
#include "common/event.h"
|
|
|
|
#include "graphics/engine/engine.h"
|
|
#include "graphics/engine/terrain.h"
|
|
#include "graphics/engine/water.h"
|
|
|
|
#include "level/robotmain.h"
|
|
|
|
#include "math/const.h"
|
|
#include "math/geometry.h"
|
|
|
|
#include "object/object.h"
|
|
#include "object/object_manager.h"
|
|
|
|
#include "object/interface/carrier_object.h"
|
|
#include "object/interface/controllable_object.h"
|
|
#include "object/interface/movable_object.h"
|
|
#include "object/interface/powered_object.h"
|
|
#include "object/interface/transportable_object.h"
|
|
|
|
#include "physics/physics.h"
|
|
|
|
|
|
// Graphics module namespace
|
|
namespace Gfx
|
|
{
|
|
|
|
const float MOUSE_EDGE_MARGIN = 0.01f;
|
|
|
|
//! Changes the level of transparency of an object and objects transported (battery & cargo)
|
|
void SetTransparency(CObject* obj, float value)
|
|
{
|
|
obj->SetTransparency(value);
|
|
|
|
if (obj->Implements(ObjectInterfaceType::Carrier))
|
|
{
|
|
CObject* cargo = dynamic_cast<CCarrierObject*>(obj)->GetCargo();
|
|
if (cargo != nullptr)
|
|
cargo->SetTransparency(value);
|
|
}
|
|
|
|
if (obj->Implements(ObjectInterfaceType::Powered))
|
|
{
|
|
CObject* power = dynamic_cast<CPoweredObject*>(obj)->GetPower();
|
|
if (power != nullptr)
|
|
power->SetTransparency(value);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CCamera::CCamera()
|
|
{
|
|
m_engine = CEngine::GetInstancePointer();
|
|
m_water = m_engine->GetWater();
|
|
|
|
m_main = CRobotMain::GetInstancePointer();
|
|
m_terrain = m_main->GetTerrain();
|
|
|
|
m_input = CInput::GetInstancePointer();
|
|
|
|
m_type = CAM_TYPE_FREE;
|
|
m_smooth = CAM_SMOOTH_NORM;
|
|
m_cameraObj = nullptr;
|
|
|
|
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_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_transparency = 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 = CAM_TYPE_NULL;
|
|
m_visitDirectionV = 0.0f;
|
|
|
|
m_editHeight = 40.0f;
|
|
|
|
m_remotePan = 0.0f;
|
|
|
|
m_centeringPhase = CAM_PHASE_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 = CAM_EFFECT_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_overType = CAM_OVER_EFFECT_NULL;
|
|
m_overForce = 0.0f;
|
|
m_overTime = 0.0f;
|
|
m_overMode = 0;
|
|
m_overFadeIn = 0.0f;
|
|
m_overFadeOut = 0.0f;
|
|
|
|
m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
|
|
m_effect = true;
|
|
m_blood = true;
|
|
m_oldCameraScroll = false;
|
|
m_cameraInvertX = false;
|
|
m_cameraInvertY = false;
|
|
}
|
|
|
|
CCamera::~CCamera()
|
|
{
|
|
}
|
|
|
|
void CCamera::SetEffect(bool enable)
|
|
{
|
|
m_effect = enable;
|
|
}
|
|
|
|
bool CCamera::GetEffect()
|
|
{
|
|
return m_effect;
|
|
}
|
|
|
|
void CCamera::SetBlood(bool enable)
|
|
{
|
|
m_blood = enable;
|
|
}
|
|
|
|
bool CCamera::GetBlood()
|
|
{
|
|
return m_blood;
|
|
}
|
|
|
|
void CCamera::SetOldCameraScroll(bool scroll)
|
|
{
|
|
m_oldCameraScroll = scroll;
|
|
}
|
|
|
|
bool CCamera::GetOldCameraScroll()
|
|
{
|
|
return m_oldCameraScroll;
|
|
}
|
|
|
|
void CCamera::SetCameraInvertX(bool invert)
|
|
{
|
|
m_cameraInvertX = invert;
|
|
}
|
|
|
|
bool CCamera::GetCameraInvertX()
|
|
{
|
|
return m_cameraInvertX;
|
|
}
|
|
|
|
void CCamera::SetCameraInvertY(bool invert)
|
|
{
|
|
m_cameraInvertY = invert;
|
|
}
|
|
|
|
bool CCamera::GetCameraInvertY()
|
|
{
|
|
return m_cameraInvertY;
|
|
}
|
|
|
|
void CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay)
|
|
{
|
|
m_initDelay = delay;
|
|
|
|
eye.y += m_terrain->GetFloorLevel(eye, true);
|
|
lookat.y += m_terrain->GetFloorLevel(lookat, true);
|
|
|
|
m_type = CAM_TYPE_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 = CAM_PHASE_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;
|
|
|
|
FlushEffect();
|
|
FlushOver();
|
|
SetType(CAM_TYPE_FREE);
|
|
}
|
|
|
|
|
|
void CCamera::SetControllingObject(CObject* object)
|
|
{
|
|
m_cameraObj = object;
|
|
}
|
|
|
|
CObject* CCamera::GetControllingObject()
|
|
{
|
|
return m_cameraObj;
|
|
}
|
|
|
|
void CCamera::SetType(CameraType type)
|
|
{
|
|
m_remotePan = 0.0f;
|
|
|
|
if ( (m_type == CAM_TYPE_BACK) && m_transparency )
|
|
{
|
|
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
|
{
|
|
if (IsObjectBeingTransported(obj))
|
|
continue;
|
|
|
|
SetTransparency(obj, 0.0f); // opaque object
|
|
}
|
|
}
|
|
m_transparency = false;
|
|
|
|
if (type == CAM_TYPE_INFO ||
|
|
type == CAM_TYPE_VISIT) // xx -> info ?
|
|
{
|
|
m_normEye = m_engine->GetEyePt();
|
|
m_normLookat = m_engine->GetLookatPt();
|
|
|
|
m_engine->SetFocus(1.00f); // normal
|
|
m_type = type;
|
|
return;
|
|
}
|
|
|
|
if (m_type == CAM_TYPE_INFO ||
|
|
m_type == CAM_TYPE_VISIT) // info -> xx ?
|
|
{
|
|
m_engine->SetFocus(m_focus); // gives initial focus
|
|
m_type = type;
|
|
|
|
Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f);
|
|
SetViewParams(m_normEye, m_normLookat, upVec);
|
|
return;
|
|
}
|
|
|
|
if ( m_type == CAM_TYPE_BACK && type == CAM_TYPE_FREE ) // back -> free ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
|
|
|
|
if ( m_type == CAM_TYPE_BACK && type == CAM_TYPE_EDIT ) // back -> edit ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f);
|
|
|
|
if ( m_type == CAM_TYPE_ONBOARD && type == CAM_TYPE_FREE ) // onboard -> free ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
|
|
|
|
if ( m_type == CAM_TYPE_ONBOARD && type == CAM_TYPE_EDIT ) // onboard -> edit ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
|
|
|
|
if ( m_type == CAM_TYPE_ONBOARD && type == CAM_TYPE_EXPLO ) // onboard -> explo ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
|
|
|
|
if ( m_type == CAM_TYPE_BACK && type == CAM_TYPE_EXPLO ) // back -> explo ?
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f);
|
|
|
|
if ( type == CAM_TYPE_FIX ||
|
|
type == CAM_TYPE_PLANE )
|
|
AbortCentering(); // Special stops framing
|
|
|
|
m_fixDist = 50.0f;
|
|
if ( type == CAM_TYPE_PLANE )
|
|
m_fixDist = 60.0f;
|
|
|
|
if ( type == CAM_TYPE_BACK )
|
|
{
|
|
AbortCentering(); // Special stops framing
|
|
m_addDirectionH = 0.0f;
|
|
m_addDirectionV = -Math::PI*0.05f;
|
|
|
|
ObjectType oType;
|
|
if ( m_cameraObj == nullptr ) oType = OBJECT_NULL;
|
|
else oType = m_cameraObj->GetType();
|
|
|
|
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;
|
|
if ( oType == OBJECT_MOTHER ) m_backDist = 55.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 != CAM_TYPE_ONBOARD && m_cameraObj != 0 )
|
|
// m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right
|
|
|
|
if ( type == CAM_TYPE_ONBOARD )
|
|
m_focus = 1.50f; // Wide
|
|
else
|
|
m_focus = 1.00f; // normal
|
|
m_engine->SetFocus(m_focus);
|
|
|
|
m_type = type;
|
|
|
|
SetSmooth(CAM_SMOOTH_NORM);
|
|
}
|
|
|
|
CameraType CCamera::GetType()
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
void CCamera::SetSmooth(CameraSmooth type)
|
|
{
|
|
m_smooth = type;
|
|
}
|
|
|
|
CameraSmooth CCamera::GetSmooth()
|
|
{
|
|
return m_smooth;
|
|
}
|
|
|
|
void CCamera::SetDist(float dist)
|
|
{
|
|
m_fixDist = dist;
|
|
}
|
|
|
|
float CCamera::GetDist()
|
|
{
|
|
return m_fixDist;
|
|
}
|
|
|
|
void CCamera::SetFixDirectionH(float angle)
|
|
{
|
|
m_fixDirectionH = angle;
|
|
}
|
|
|
|
float CCamera::GetFixDirectionH()
|
|
{
|
|
return m_fixDirectionH;
|
|
}
|
|
|
|
void CCamera::SetFixDirectionV(float angle)
|
|
{
|
|
m_fixDirectionV = angle;
|
|
}
|
|
|
|
float CCamera::GetFixDirectionV()
|
|
{
|
|
return m_fixDirectionV;
|
|
}
|
|
|
|
void CCamera::SetRemotePan(float value)
|
|
{
|
|
m_remotePan = value;
|
|
}
|
|
|
|
float CCamera::GetRemotePan()
|
|
{
|
|
return m_remotePan;
|
|
}
|
|
|
|
void CCamera::SetRemoteZoom(float value)
|
|
{
|
|
value = Math::Norm(value);
|
|
|
|
if ( m_type == CAM_TYPE_BACK )
|
|
m_backDist = m_backMin + (200.0f - m_backMin) * value;
|
|
|
|
if ( m_type == CAM_TYPE_FIX ||
|
|
m_type == CAM_TYPE_PLANE )
|
|
m_fixDist = 10.0f + (200.0f - 10.0f) * value;
|
|
}
|
|
|
|
float CCamera::GetRemoteZoom()
|
|
{
|
|
if ( m_type == CAM_TYPE_BACK )
|
|
return (m_backDist - m_backMin) / (200.0f - m_backMin);
|
|
|
|
if ( m_type == CAM_TYPE_FIX ||
|
|
m_type == CAM_TYPE_PLANE )
|
|
return (m_fixDist - 10.0f) / (200.0f - 10.0f);
|
|
|
|
return 0.0f;
|
|
}
|
|
|
|
void CCamera::StartVisit(Math::Vector goal, float dist)
|
|
{
|
|
m_visitType = m_type;
|
|
SetType(CAM_TYPE_VISIT);
|
|
m_visitGoal = goal;
|
|
m_visitDist = dist;
|
|
m_visitTime = 0.0f;
|
|
m_visitDirectionV = -Math::PI*0.10f;
|
|
}
|
|
|
|
void CCamera::StopVisit()
|
|
{
|
|
SetType(m_visitType); // presents the initial type
|
|
}
|
|
|
|
void CCamera::GetCamera(Math::Vector &eye, Math::Vector &lookat)
|
|
{
|
|
eye = m_eyePt;
|
|
lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
|
}
|
|
|
|
bool CCamera::StartCentering(CObject *object, float angleH, float angleV,
|
|
float dist, float time)
|
|
{
|
|
if (m_type != CAM_TYPE_BACK)
|
|
return false;
|
|
if (object != m_cameraObj)
|
|
return false;
|
|
|
|
if (m_centeringPhase != CAM_PHASE_NULL)
|
|
return false;
|
|
|
|
if (m_addDirectionH > Math::PI)
|
|
angleH = Math::PI * 2.0f - angleH;
|
|
|
|
m_centeringPhase = CAM_PHASE_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;
|
|
}
|
|
|
|
bool CCamera::StopCentering(CObject *object, float time)
|
|
{
|
|
if (m_type != CAM_TYPE_BACK)
|
|
return false;
|
|
if (object != m_cameraObj)
|
|
return false;
|
|
|
|
if (m_centeringPhase != CAM_PHASE_START &&
|
|
m_centeringPhase != CAM_PHASE_WAIT)
|
|
return false;
|
|
|
|
m_centeringPhase = CAM_PHASE_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;
|
|
}
|
|
|
|
void CCamera::AbortCentering()
|
|
{
|
|
if (m_type == CAM_TYPE_INFO ||
|
|
m_type == CAM_TYPE_VISIT )
|
|
return;
|
|
|
|
if (m_centeringPhase == CAM_PHASE_NULL)
|
|
return;
|
|
|
|
m_centeringPhase = CAM_PHASE_NULL;
|
|
|
|
if ( m_centeringAngleH != 99.9f )
|
|
m_addDirectionH = m_centeringCurrentH;
|
|
|
|
if (m_centeringAngleV != 99.9f)
|
|
m_addDirectionV = m_centeringCurrentV;
|
|
}
|
|
|
|
void CCamera::FlushEffect()
|
|
{
|
|
m_effectType = CAM_EFFECT_NULL;
|
|
m_effectForce = 0.0f;
|
|
m_effectProgress = 0.0f;
|
|
m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
|
|
CApplication::GetInstancePointer()->StopForceFeedbackEffect();
|
|
}
|
|
|
|
void CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force)
|
|
{
|
|
if ( !m_effect ) return;
|
|
|
|
m_effectType = effect;
|
|
m_effectPos = pos;
|
|
m_effectForce = force;
|
|
m_effectProgress = 0.0f;
|
|
}
|
|
|
|
void CCamera::EffectFrame(const Event &event)
|
|
{
|
|
if (m_type == CAM_TYPE_INFO ||
|
|
m_type == CAM_TYPE_VISIT)
|
|
return;
|
|
|
|
if (m_effectType == CAM_EFFECT_NULL)
|
|
return;
|
|
|
|
m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f);
|
|
|
|
float force = m_effectForce;
|
|
|
|
if ( m_effectType == CAM_EFFECT_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 == CAM_EFFECT_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 == CAM_EFFECT_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 == CAM_EFFECT_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 == CAM_EFFECT_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 == CAM_EFFECT_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;
|
|
}
|
|
|
|
float dist = Math::Distance(m_eyePt, m_effectPos);
|
|
dist = Math::Norm((dist - 100.f) / 100.0f);
|
|
|
|
force *= 1.0f-dist;
|
|
m_effectOffset *= force;
|
|
|
|
float forceFeedback = force;
|
|
if (m_effectType == CAM_EFFECT_VIBRATION)
|
|
{
|
|
forceFeedback *= 0.5f;
|
|
}
|
|
if (m_effectType == CAM_EFFECT_PET)
|
|
{
|
|
forceFeedback *= 0.75f;
|
|
}
|
|
if (m_effectType == CAM_EFFECT_EXPLO)
|
|
{
|
|
forceFeedback *= 3.0f;
|
|
}
|
|
if (forceFeedback > 1.0f) forceFeedback = 1.0f;
|
|
if (forceFeedback >= 0.1f)
|
|
{
|
|
CApplication::GetInstancePointer()->PlayForceFeedbackEffect(forceFeedback);
|
|
}
|
|
|
|
if (m_effectProgress >= 1.0f)
|
|
FlushEffect();
|
|
}
|
|
|
|
void CCamera::FlushOver()
|
|
{
|
|
m_overType = CAM_OVER_EFFECT_NULL;
|
|
m_overColorBase = Color(0.0f, 0.0f, 0.0f, 0.0f); // black
|
|
m_engine->SetOverColor(); // nothing
|
|
}
|
|
|
|
void CCamera::SetOverBaseColor(Color color)
|
|
{
|
|
m_overColorBase = color;
|
|
}
|
|
|
|
void CCamera::StartOver(CameraOverEffect effect, Math::Vector pos, float force)
|
|
{
|
|
m_overType = effect;
|
|
m_overTime = 0.0f;
|
|
|
|
float decay;
|
|
if (m_overType == CAM_OVER_EFFECT_LIGHTNING)
|
|
decay = 400.0f;
|
|
else
|
|
decay = 100.0f;
|
|
|
|
float 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 == CAM_OVER_EFFECT_BLOOD)
|
|
{
|
|
m_overColor = Color(0.8f, 0.1f, 0.1f); // red
|
|
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
|
|
|
m_overFadeIn = 0.4f;
|
|
m_overFadeOut = 0.8f;
|
|
m_overForce = 1.0f;
|
|
}
|
|
|
|
if ( m_overType == CAM_OVER_EFFECT_FADEIN_WHITE )
|
|
{
|
|
m_overColor = Color(1.0f, 1.0f, 1.0f); // white
|
|
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
|
|
|
m_overFadeIn = 0.0f;
|
|
m_overFadeOut = 20.0f;
|
|
m_overForce = 1.0f;
|
|
}
|
|
|
|
if ( m_overType == CAM_OVER_EFFECT_FADEOUT_WHITE )
|
|
{
|
|
m_overColor = Color(1.0f, 1.0f, 1.0f); // white
|
|
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
|
|
|
m_overFadeIn = 6.0f;
|
|
m_overFadeOut = 100000.0f;
|
|
m_overForce = 1.0f;
|
|
}
|
|
|
|
if ( m_overType == CAM_OVER_EFFECT_FADEOUT_BLACK )
|
|
{
|
|
m_overColor = m_engine->GetFogColor(1); // fog color underwater
|
|
m_overMode = ENG_RSTATE_TTEXTURE_WHITE;
|
|
|
|
m_overFadeIn = 4.0f;
|
|
m_overFadeOut = 100000.0f;
|
|
m_overForce = 1.0f;
|
|
}
|
|
|
|
if ( m_overType == CAM_OVER_EFFECT_LIGHTNING )
|
|
{
|
|
m_overColor = Color(0.9f, 1.0f, 1.0f); // white-cyan
|
|
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
|
|
|
m_overFadeIn = 0.0f;
|
|
m_overFadeOut = 1.0f;
|
|
}
|
|
}
|
|
|
|
void CCamera::OverFrame(const Event &event)
|
|
{
|
|
if (m_type == CAM_TYPE_INFO ||
|
|
m_type == CAM_TYPE_VISIT)
|
|
return;
|
|
|
|
if (m_overType == CAM_OVER_EFFECT_NULL)
|
|
return;
|
|
|
|
m_overTime += event.rTime;
|
|
|
|
if (m_overType == CAM_OVER_EFFECT_LIGHTNING)
|
|
{
|
|
Color color;
|
|
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 = Color(0.0f, 0.0f, 0.0f);
|
|
}
|
|
color.a = 0.0f;
|
|
m_engine->SetOverColor(color, m_overMode);
|
|
}
|
|
else
|
|
{
|
|
if ( (m_overFadeIn > 0.0f) && (m_overTime < m_overFadeIn) )
|
|
{
|
|
float intensity = m_overTime / m_overFadeIn;
|
|
intensity *= m_overForce;
|
|
|
|
Color color;
|
|
if (m_overMode == ENG_RSTATE_TCOLOR_WHITE)
|
|
{
|
|
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(color, m_overMode);
|
|
}
|
|
else if ( (m_overFadeOut > 0.0f) && (m_overTime - m_overFadeIn < m_overFadeOut) )
|
|
{
|
|
float intensity = 1.0f - (m_overTime - m_overFadeIn) / m_overFadeOut;
|
|
intensity *= m_overForce;
|
|
|
|
Color color;
|
|
if (m_overMode == ENG_RSTATE_TCOLOR_WHITE)
|
|
{
|
|
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(color, m_overMode);
|
|
}
|
|
}
|
|
|
|
if ( m_overTime >= m_overFadeIn+m_overFadeOut )
|
|
{
|
|
FlushOver();
|
|
return;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void CCamera::SetViewTime(const Math::Vector &eyePt,
|
|
const Math::Vector &lookatPt,
|
|
float rTime)
|
|
{
|
|
Math::Vector eye, lookat;
|
|
|
|
if (m_type == CAM_TYPE_INFO)
|
|
{
|
|
eye = eyePt;
|
|
lookat = lookatPt;
|
|
}
|
|
else
|
|
{
|
|
if (m_initDelay > 0.0f)
|
|
{
|
|
m_initDelay -= rTime;
|
|
if (m_initDelay < 0.0f)
|
|
m_initDelay = 0.0f;
|
|
rTime /= 1.0f+m_initDelay;
|
|
}
|
|
|
|
eye = eyePt;
|
|
lookat = lookatPt;
|
|
if ( !IsCollision(eye, lookat) )
|
|
{
|
|
m_finalEye = eye;
|
|
m_finalLookat = lookat;
|
|
}
|
|
|
|
float prog = 0.0f;
|
|
float dist = Math::Distance(m_finalEye, m_actualEye);
|
|
|
|
if (m_smooth == CAM_SMOOTH_NONE) prog = dist;
|
|
if (m_smooth == CAM_SMOOTH_NORM) prog = dist * rTime * 3.0f;
|
|
if (m_smooth == CAM_SMOOTH_HARD) prog = dist * rTime * 4.0f;
|
|
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 == CAM_SMOOTH_NONE ) prog = dist;
|
|
if ( m_smooth == CAM_SMOOTH_NORM ) prog = dist * rTime * 6.0f;
|
|
if ( m_smooth == CAM_SMOOTH_HARD ) prog = dist * 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);
|
|
|
|
float h = m_terrain->GetFloorLevel(eye);
|
|
if (eye.y < h + 4.0f)
|
|
eye.y = h + 4.0f;
|
|
|
|
lookat = m_effectOffset+m_actualLookat;
|
|
}
|
|
|
|
Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f);
|
|
SetViewParams(eye, lookat, upVec);
|
|
}
|
|
|
|
bool CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat)
|
|
{
|
|
if (m_type == CAM_TYPE_BACK ) return IsCollisionBack(eye, lookat);
|
|
if (m_type == CAM_TYPE_FIX ) return IsCollisionFix (eye, lookat);
|
|
if (m_type == CAM_TYPE_PLANE) return IsCollisionFix (eye, lookat);
|
|
return false;
|
|
}
|
|
|
|
bool CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat)
|
|
{
|
|
ObjectType iType;
|
|
if (m_cameraObj == nullptr)
|
|
iType = OBJECT_NULL;
|
|
else
|
|
iType = m_cameraObj->GetType();
|
|
|
|
Math::Vector min;
|
|
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);
|
|
|
|
Math::Vector max;
|
|
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_transparency = false;
|
|
|
|
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
|
{
|
|
if (IsObjectBeingTransported(obj))
|
|
continue;
|
|
|
|
SetTransparency(obj, 0.0f); // opaque object
|
|
|
|
if (obj == 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;
|
|
|
|
ObjectType oType = obj->GetType();
|
|
if ( oType == OBJECT_HUMAN ||
|
|
oType == OBJECT_TECH ||
|
|
oType == OBJECT_TOTO ||
|
|
oType == OBJECT_ANT ||
|
|
oType == OBJECT_SPIDER ||
|
|
oType == OBJECT_BEE ||
|
|
oType == OBJECT_WORM ) continue;
|
|
|
|
Math::Sphere objSphere = obj->GetCameraCollisionSphere();
|
|
Math::Vector oPos = objSphere.pos;
|
|
float oRadius = objSphere.radius;
|
|
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;
|
|
|
|
Math::Vector proj = Projection(m_actualEye, m_actualLookat, oPos);
|
|
float dpp = Math::Distance(proj, oPos);
|
|
if ( dpp > oRadius ) continue;
|
|
|
|
if ( oType == OBJECT_FACTORY )
|
|
{
|
|
float angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW !
|
|
angle = Math::Direction(angle, obj->GetRotationY());
|
|
if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate?
|
|
}
|
|
|
|
float del = Math::Distance(m_actualEye, m_actualLookat);
|
|
if (oType == OBJECT_FACTORY)
|
|
del += oRadius;
|
|
|
|
float len = Math::Distance(m_actualEye, proj);
|
|
if (len > del) continue;
|
|
|
|
SetTransparency(obj, 1.0f); // transparent object
|
|
m_transparency = true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat)
|
|
{
|
|
for (CObject* obj : CObjectManager::GetInstancePointer()->GetAllObjects())
|
|
{
|
|
if (obj == m_cameraObj) continue;
|
|
|
|
ObjectType type = obj->GetType();
|
|
if ( type == OBJECT_TOTO ||
|
|
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;
|
|
|
|
Math::Sphere objSphere = obj->GetCameraCollisionSphere();
|
|
Math::Vector objPos = objSphere.pos;
|
|
float objRadius = objSphere.radius;
|
|
if (objRadius == 0.0f) continue;
|
|
|
|
float dist = Math::Distance(eye, objPos);
|
|
if (dist < objRadius)
|
|
{
|
|
dist = Math::Distance(eye, lookat);
|
|
Math::Vector proj = Projection(eye, lookat, objPos);
|
|
eye = (lookat - eye) * objRadius / dist + proj;
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CCamera::EventProcess(const Event &event)
|
|
{
|
|
switch (event.type)
|
|
{
|
|
case EVENT_FRAME:
|
|
EventFrame(event);
|
|
break;
|
|
|
|
case EVENT_MOUSE_BUTTON_DOWN:
|
|
case EVENT_MOUSE_BUTTON_UP:
|
|
EventMouseButton(event);
|
|
break;
|
|
|
|
case EVENT_MOUSE_MOVE:
|
|
EventMouseMove(event);
|
|
break;
|
|
|
|
case EVENT_MOUSE_WHEEL:
|
|
EventMouseWheel(event);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventMouseMove(const Event &event)
|
|
{
|
|
if (m_engine->GetMouseType() == ENG_MOUSE_SCROLLR ||
|
|
m_engine->GetMouseType() == ENG_MOUSE_SCROLLL ||
|
|
m_engine->GetMouseType() == ENG_MOUSE_SCROLLU ||
|
|
m_engine->GetMouseType() == ENG_MOUSE_SCROLLD ||
|
|
m_engine->GetMouseType() == ENG_MOUSE_MOVE )
|
|
{
|
|
m_engine->SetMouseType(ENG_MOUSE_NORM);
|
|
}
|
|
|
|
if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0)
|
|
{
|
|
Math::Point newDelta = event.mousePos - m_mousePos;
|
|
if (m_cameraInvertX)
|
|
newDelta.x = -newDelta.x;
|
|
if (m_cameraInvertY)
|
|
newDelta.y = -newDelta.y;
|
|
m_mouseDelta += newDelta;
|
|
|
|
m_engine->SetMouseType(ENG_MOUSE_MOVE);
|
|
}
|
|
|
|
m_mouseDeltaEdge.LoadZero();
|
|
if (m_oldCameraScroll)
|
|
{
|
|
if (event.mousePos.x < MOUSE_EDGE_MARGIN)
|
|
m_mouseDeltaEdge.x = event.mousePos.x / MOUSE_EDGE_MARGIN - 1.0f;
|
|
if (event.mousePos.x > 1.0f - MOUSE_EDGE_MARGIN)
|
|
m_mouseDeltaEdge.x = 1.0f - (1.0f - event.mousePos.x) / MOUSE_EDGE_MARGIN;
|
|
if (event.mousePos.y < MOUSE_EDGE_MARGIN)
|
|
m_mouseDeltaEdge.y = event.mousePos.y / MOUSE_EDGE_MARGIN - 1.0f;
|
|
if (event.mousePos.y > 1.0f - MOUSE_EDGE_MARGIN)
|
|
m_mouseDeltaEdge.y = 1.0f - (1.0f - event.mousePos.y) / MOUSE_EDGE_MARGIN;
|
|
|
|
if (m_type == CAM_TYPE_FREE ||
|
|
m_type == CAM_TYPE_EDIT ||
|
|
m_type == CAM_TYPE_BACK ||
|
|
m_type == CAM_TYPE_FIX ||
|
|
m_type == CAM_TYPE_PLANE ||
|
|
m_type == CAM_TYPE_EXPLO )
|
|
{
|
|
if (m_mouseDeltaEdge.x > 0.0f)
|
|
m_engine->SetMouseType(ENG_MOUSE_SCROLLR);
|
|
if (m_mouseDeltaEdge.x < 0.0f)
|
|
m_engine->SetMouseType(ENG_MOUSE_SCROLLL);
|
|
}
|
|
if (m_type == CAM_TYPE_FREE ||
|
|
m_type == CAM_TYPE_EDIT )
|
|
{
|
|
if (m_mouseDeltaEdge.y > 0.0f)
|
|
m_engine->SetMouseType(ENG_MOUSE_SCROLLU);
|
|
if (m_mouseDeltaEdge.y < 0.0f)
|
|
m_engine->SetMouseType(ENG_MOUSE_SCROLLD);
|
|
}
|
|
|
|
m_mouseDeltaEdge.x /= 2*Math::PI;
|
|
m_mouseDeltaEdge.y /= Math::PI;
|
|
}
|
|
|
|
m_mousePos = event.mousePos;
|
|
return true;
|
|
}
|
|
|
|
void CCamera::EventMouseWheel(const Event &event)
|
|
{
|
|
auto dir = event.GetData<MouseWheelEventData>()->y;
|
|
|
|
if (m_type == CAM_TYPE_BACK)
|
|
{
|
|
m_backDist -= 8.0f*dir;
|
|
if (m_backDist < m_backMin)
|
|
m_backDist = m_backMin;
|
|
if (m_backDist > 200.0f)
|
|
m_backDist = 200.0f;
|
|
}
|
|
|
|
if ( m_type == CAM_TYPE_FIX ||
|
|
m_type == CAM_TYPE_PLANE )
|
|
{
|
|
m_fixDist -= 8.0f*dir;
|
|
if (m_fixDist < 10.0f)
|
|
m_fixDist = 10.0f;
|
|
if (m_fixDist > 200.0f)
|
|
m_fixDist = 200.0f;
|
|
}
|
|
|
|
if ( m_type == CAM_TYPE_VISIT )
|
|
{
|
|
m_visitDist -= 8.0f*dir;
|
|
if (m_visitDist < 20.0f)
|
|
m_visitDist = 20.0f;
|
|
if (m_visitDist > 200.0f)
|
|
m_visitDist = 200.0f;
|
|
}
|
|
}
|
|
|
|
void CCamera::EventMouseButton(const Event &event)
|
|
{
|
|
if (event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_RIGHT || event.GetData<MouseButtonEventData>()->button == MOUSE_BUTTON_MIDDLE)
|
|
{
|
|
if ((event.mouseButtonsState & MOUSE_BUTTON_RIGHT) != 0 || (event.mouseButtonsState & MOUSE_BUTTON_MIDDLE) != 0)
|
|
{
|
|
m_engine->SetMouseType(ENG_MOUSE_MOVE);
|
|
}
|
|
else
|
|
{
|
|
m_engine->SetMouseType(ENG_MOUSE_NORM);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CCamera::EventFrame(const Event &event)
|
|
{
|
|
Math::Point newDelta = m_mouseDeltaEdge * m_speed * event.rTime;
|
|
if (m_cameraInvertX)
|
|
newDelta.x = -newDelta.x;
|
|
if (m_cameraInvertY)
|
|
newDelta.y = -newDelta.y;
|
|
m_mouseDelta += newDelta;
|
|
|
|
EffectFrame(event);
|
|
OverFrame(event);
|
|
|
|
if (m_type == CAM_TYPE_FREE)
|
|
return EventFrameFree(event);
|
|
|
|
if (m_type == CAM_TYPE_EDIT)
|
|
return EventFrameEdit(event);
|
|
|
|
if (m_type == CAM_TYPE_DIALOG)
|
|
return EventFrameDialog(event);
|
|
|
|
if (m_type == CAM_TYPE_BACK)
|
|
return EventFrameBack(event);
|
|
|
|
if (m_type == CAM_TYPE_FIX ||
|
|
m_type == CAM_TYPE_PLANE)
|
|
return EventFrameFix(event);
|
|
|
|
if (m_type == CAM_TYPE_EXPLO)
|
|
return EventFrameExplo(event);
|
|
|
|
if (m_type == CAM_TYPE_ONBOARD)
|
|
return EventFrameOnBoard(event);
|
|
|
|
if (m_type == CAM_TYPE_SCRIPT)
|
|
return EventFrameScript(event);
|
|
|
|
if (m_type == CAM_TYPE_INFO)
|
|
return EventFrameInfo(event);
|
|
|
|
if (m_type == CAM_TYPE_VISIT)
|
|
return EventFrameVisit(event);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameFree(const Event &event)
|
|
{
|
|
Math::Vector cameraInput = event.cameraInput;
|
|
if (m_cameraObj == nullptr)
|
|
{
|
|
cameraInput = Math::Clamp(cameraInput + event.motionInput, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f));
|
|
}
|
|
|
|
float factor = m_heightEye * 0.5f + 30.0f;
|
|
|
|
m_directionH -= m_mouseDelta.x * 2*Math::PI;
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDelta.y * factor * m_speed);
|
|
m_mouseDelta.LoadZero();
|
|
|
|
// Up/Down
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, cameraInput.y * event.rTime * factor * m_speed);
|
|
|
|
// Left/Right
|
|
if ( event.kmodState & KEY_MOD(CTRL) )
|
|
{
|
|
if ( cameraInput.x < 0.0f )
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -cameraInput.x * event.rTime * factor * m_speed);
|
|
if ( cameraInput.x > 0.0f )
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, cameraInput.x * event.rTime * factor * m_speed);
|
|
}
|
|
else
|
|
{
|
|
m_directionH -= cameraInput.x * event.rTime * 0.7f * m_speed;
|
|
}
|
|
|
|
// PageUp/PageDown
|
|
if ( m_input->GetKeyState(INPUT_SLOT_AWAY) )
|
|
{
|
|
if (m_heightEye < 500.0f)
|
|
m_heightEye += event.rTime * factor * m_speed;
|
|
}
|
|
if ( m_input->GetKeyState(INPUT_SLOT_NEAR) )
|
|
{
|
|
if (m_heightEye > -2.0f)
|
|
m_heightEye -= event.rTime * factor * m_speed;
|
|
}
|
|
|
|
|
|
if ( m_input->GetKeyState(INPUT_SLOT_CAMERA_UP) )
|
|
{
|
|
m_heightLookat += event.rTime * factor * m_speed;
|
|
}
|
|
if ( m_input->GetKeyState(INPUT_SLOT_CAMERA_DOWN) )
|
|
{
|
|
m_heightLookat -= event.rTime * factor * m_speed;
|
|
}
|
|
|
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
|
|
|
if (m_terrain->AdjustToFloor(m_eyePt, true))
|
|
{
|
|
m_eyePt.y += m_heightEye;
|
|
|
|
Math::Vector pos = m_eyePt;
|
|
if (m_terrain->AdjustToFloor(pos, true))
|
|
{
|
|
pos.y -= 2.0f;
|
|
if (m_eyePt.y < pos.y)
|
|
m_eyePt.y = pos.y;
|
|
}
|
|
|
|
}
|
|
|
|
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
|
|
|
if (m_terrain->AdjustToFloor(lookatPt, true))
|
|
lookatPt.y += m_heightLookat;
|
|
|
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameEdit(const Event &event)
|
|
{
|
|
float factor = m_editHeight * 0.5f + 30.0f;
|
|
|
|
m_directionH -= m_mouseDelta.x * 0.7f * 2*Math::PI;
|
|
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDelta.y * factor * m_speed);
|
|
|
|
m_fixDirectionH += m_mouseDelta.x * 2*Math::PI;
|
|
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
|
|
|
|
m_mouseDelta.LoadZero();
|
|
|
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
|
|
|
if (m_terrain->AdjustToFloor(m_eyePt, false))
|
|
{
|
|
m_eyePt.y += m_editHeight;
|
|
|
|
Math::Vector pos = m_eyePt;
|
|
if (m_terrain->AdjustToFloor(pos, false))
|
|
{
|
|
pos.y += 2.0f;
|
|
if (m_eyePt.y < pos.y)
|
|
m_eyePt.y = pos.y;
|
|
}
|
|
|
|
}
|
|
|
|
Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
|
|
|
|
if ( m_terrain->AdjustToFloor(lookatPt, true))
|
|
lookatPt.y += m_heightLookat;
|
|
|
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameDialog(const Event &event)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameBack(const Event &event)
|
|
{
|
|
ObjectType type;
|
|
if (m_cameraObj == nullptr)
|
|
type = OBJECT_NULL;
|
|
else
|
|
type = m_cameraObj->GetType();
|
|
|
|
// +/-.
|
|
if (m_input->GetKeyState(INPUT_SLOT_NEAR))
|
|
{
|
|
m_backDist -= event.rTime * 30.0f * m_speed;
|
|
if (m_backDist < m_backMin) m_backDist = m_backMin;
|
|
}
|
|
if (m_input->GetKeyState(INPUT_SLOT_AWAY))
|
|
{
|
|
m_backDist += event.rTime * 30.0f * m_speed;
|
|
if (m_backDist > 200.0f) m_backDist = 200.0f;
|
|
}
|
|
|
|
m_addDirectionH -= m_mouseDelta.x * 2*Math::PI;
|
|
m_addDirectionH = Math::NormAngle(m_addDirectionH);
|
|
if (m_mouseDelta.Length() > 0)
|
|
AbortCentering(); // special stops framing
|
|
m_mouseDelta.LoadZero();
|
|
|
|
// Increase the special framework
|
|
float centeringH = 0.0f;
|
|
float centeringV = 0.0f;
|
|
float centeringD = 0.0f;
|
|
|
|
if (m_centeringPhase == CAM_PHASE_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 = CAM_PHASE_WAIT;
|
|
}
|
|
|
|
if (m_centeringPhase == CAM_PHASE_WAIT)
|
|
{
|
|
centeringH = 1.0f;
|
|
centeringV = 1.0f;
|
|
centeringD = 1.0f;
|
|
}
|
|
|
|
if (m_centeringPhase == CAM_PHASE_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 = CAM_PHASE_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 != nullptr)
|
|
{
|
|
Math::Vector lookatPt = m_cameraObj->GetPosition();
|
|
if (type == OBJECT_BASE ) lookatPt.y += 40.0f;
|
|
else if (type == OBJECT_HUMAN) lookatPt.y += 1.0f;
|
|
else if (type == OBJECT_TECH ) lookatPt.y += 1.0f;
|
|
else lookatPt.y += 4.0f;
|
|
|
|
float h = -m_cameraObj->GetRotationY(); // 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;
|
|
float 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);
|
|
|
|
float d = m_backDist;
|
|
d += m_centeringDist * centeringD;
|
|
|
|
m_centeringCurrentH = m_centeringAngleH * centeringH;
|
|
m_centeringCurrentV = m_centeringAngleV * centeringV;
|
|
|
|
m_eyePt = RotateView(lookatPt, h, v, d);
|
|
|
|
bool ground = true;
|
|
if (m_cameraObj->Implements(ObjectInterfaceType::Movable))
|
|
ground = dynamic_cast<CMovableObject*>(m_cameraObj)->GetPhysics()->GetLand();
|
|
if ( ground ) // ground?
|
|
{
|
|
Math::Vector pos = lookatPt + (lookatPt - m_eyePt);
|
|
float floor = m_terrain->GetHeightToFloor(pos) - 4.0f;
|
|
if (floor > 0.0f)
|
|
m_eyePt.y += floor; // shows the descent in front
|
|
}
|
|
|
|
m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v);
|
|
m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v);
|
|
|
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
|
|
|
m_directionH = h + Math::PI / 2.0f;
|
|
m_directionV = v;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameFix(const Event &event)
|
|
{
|
|
// +/-.
|
|
if (m_input->GetKeyState(INPUT_SLOT_NEAR))
|
|
{
|
|
m_fixDist -= event.rTime * 30.0f * m_speed;
|
|
if (m_fixDist < 10.0f) m_fixDist = 10.0f;
|
|
}
|
|
if (m_input->GetKeyState(INPUT_SLOT_AWAY))
|
|
{
|
|
m_fixDist += event.rTime * 30.0f * m_speed;
|
|
if (m_fixDist > 200.0f) m_fixDist = 200.0f;
|
|
}
|
|
|
|
m_fixDirectionH -= m_mouseDelta.x * 2*Math::PI;
|
|
if (m_mouseDelta.Length() > 0)
|
|
AbortCentering(); // special stops framing
|
|
m_mouseDelta.LoadZero();
|
|
|
|
// Left/Right
|
|
m_fixDirectionH += event.cameraInput.x * event.rTime * 0.7f * m_speed;
|
|
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
|
|
|
|
// Up/Down
|
|
m_fixDirectionV -= event.cameraInput.y * event.rTime * 0.7f * m_speed;
|
|
m_fixDirectionV = Math::Min(Math::Max(m_fixDirectionV, -0.5*Math::PI), 0.25*Math::PI);
|
|
|
|
if (m_cameraObj != nullptr)
|
|
{
|
|
Math::Vector lookatPt = m_cameraObj->GetPosition();
|
|
|
|
float h = m_fixDirectionH + m_remotePan;
|
|
float v = m_fixDirectionV;
|
|
|
|
float d = m_fixDist;
|
|
m_eyePt = RotateView(lookatPt, h, v, d);
|
|
if (m_type == CAM_TYPE_PLANE) m_eyePt.y += m_fixDist / 2.0f;
|
|
m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v);
|
|
m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v);
|
|
|
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
|
|
|
m_directionH = h + Math::PI / 2.0f;
|
|
m_directionV = v;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameExplo(const Event &event)
|
|
{
|
|
m_directionH -= m_mouseDelta.x * 2*Math::PI;
|
|
m_mouseDelta.LoadZero();
|
|
|
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
|
|
|
if ( m_terrain->AdjustToFloor(m_eyePt, false) )
|
|
{
|
|
m_eyePt.y += m_heightEye;
|
|
|
|
Math::Vector pos = m_eyePt;
|
|
if ( m_terrain->AdjustToFloor(pos, false) )
|
|
{
|
|
pos.y += 2.0f;
|
|
if ( m_eyePt.y < pos.y )
|
|
m_eyePt.y = pos.y;
|
|
}
|
|
|
|
}
|
|
|
|
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
|
|
|
if (m_terrain->AdjustToFloor(lookatPt, true))
|
|
lookatPt.y += m_heightLookat;
|
|
|
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCamera::EventFrameOnBoard(const Event &event)
|
|
{
|
|
if (m_cameraObj != nullptr)
|
|
{
|
|
assert(m_cameraObj->Implements(ObjectInterfaceType::Controllable));
|
|
Math::Vector lookatPt, upVec;
|
|
dynamic_cast<CControllableObject*>(m_cameraObj)->AdjustCamera(m_eyePt, m_directionH, m_directionV, lookatPt, upVec, m_type);
|
|
Math::Vector eye = m_effectOffset * 0.3f + m_eyePt;
|
|
Math::Vector lookat = m_effectOffset * 0.3f + lookatPt;
|
|
|
|
SetViewParams(eye, lookat, upVec);
|
|
m_actualEye = eye;
|
|
m_actualLookat = lookat;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool CCamera::EventFrameVisit(const Event &event)
|
|
{
|
|
m_visitTime += event.rTime;
|
|
|
|
// +/-.
|
|
if (m_input->GetKeyState(INPUT_SLOT_NEAR))
|
|
{
|
|
m_visitDist -= event.rTime * 50.0f * m_speed;
|
|
if (m_visitDist < 20.0f) m_visitDist = 20.0f;
|
|
}
|
|
if (m_input->GetKeyState(INPUT_SLOT_AWAY))
|
|
{
|
|
m_visitDist += event.rTime * 50.0f * m_speed;
|
|
if (m_visitDist > 200.0f) m_visitDist = 200.0f;
|
|
}
|
|
|
|
// PageUp/Down.
|
|
if (m_input->GetKeyState(INPUT_SLOT_CAMERA_UP))
|
|
{
|
|
m_visitDirectionV -= event.rTime * 1.0f * m_speed;
|
|
if (m_visitDirectionV < -Math::PI * 0.40f) m_visitDirectionV = -Math::PI * 0.40f;
|
|
}
|
|
if (m_input->GetKeyState(INPUT_SLOT_CAMERA_DOWN))
|
|
{
|
|
m_visitDirectionV += event.rTime * 1.0f * m_speed;
|
|
if (m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f;
|
|
}
|
|
|
|
m_visitDist -= m_mouseDelta.y * 100.0f * m_speed;
|
|
m_mouseDelta.LoadZero();
|
|
if (m_visitDist < 20.0f) m_visitDist = 20.0f;
|
|
if (m_visitDist > 200.0f) m_visitDist = 200.0f;
|
|
|
|
float angleH = (m_visitTime / 10.0f) * (Math::PI * 2.0f);
|
|
float angleV = m_visitDirectionV;
|
|
Math::Vector 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat,
|
|
const Math::Vector &up)
|
|
{
|
|
m_engine->SetViewParams(eye, lookat, up, m_eyeDistance);
|
|
|
|
bool under = (eye.y < m_water->GetLevel()); // Is it underwater?
|
|
if (m_type == CAM_TYPE_INFO)
|
|
under = false;
|
|
|
|
m_engine->SetRankView(under ? 1 : 0);
|
|
}
|
|
|
|
Math::Vector CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat,
|
|
float &angleH, float &angleV)
|
|
{
|
|
Math::Vector pos = eye;
|
|
if (m_terrain->AdjustToFloor(pos))
|
|
{
|
|
float 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;
|
|
}
|
|
|
|
Math::Vector CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat,
|
|
float &angleH, float &angleV)
|
|
{
|
|
return eye;
|
|
|
|
// TODO: check the commented out code:
|
|
/*
|
|
for (int i = 0; i < 1000000; i++)
|
|
{
|
|
CObject* obj = static_cast<CObject*>( iMan->SearchInstance(CLASS_OBJECT, i) );
|
|
if (obj == nullptr)
|
|
break;
|
|
|
|
int j = 0;
|
|
Math::Vector oPos;
|
|
float oRad;
|
|
while (obj->GetCrashSphere(j++, oPos, oRad))
|
|
{
|
|
float dist = Math::Distance(oPos, eye);
|
|
if (dist < oRad + 2.0f)
|
|
eye.y = oPos.y + oRad + 2.0f;
|
|
}
|
|
}
|
|
|
|
return eye;*/
|
|
}
|
|
|
|
void CCamera::SetCameraSpeed(float speed)
|
|
{
|
|
m_speed = speed;
|
|
}
|
|
|
|
}
|