colobot/src/graphics/engine/camera.cpp

1685 lines
46 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsiteс.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 "graphics/engine/engine.h"
#include "graphics/engine/terrain.h"
#include "graphics/engine/water.h"
#include "math/const.h"
#include "math/geometry.h"
#include "object/object.h"
#include "object/object_manager.h"
#include "object/robotmain.h"
#include "object/interface/carrier_object.h"
#include "object/interface/powered_object.h"
#include "object/interface/transportable_object.h"
#include "physics/physics.h"
// Graphics module namespace
namespace Gfx {
//! 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 = 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_rightDown = 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_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_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 = 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_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_cameraScroll = true;
m_cameraInvertX = false;
m_cameraInvertY = false;
}
CCamera::~CCamera()
{
}
void CCamera::SetEffect(bool enable)
{
m_effect = enable;
}
void CCamera::SetBlood(bool enable)
{
m_blood = enable;
}
bool CCamera::GetBlood() {
return m_blood;
}
void CCamera::SetCameraScroll(bool scroll)
{
m_cameraScroll = scroll;
}
void CCamera::SetCameraInvertX(bool invert)
{
m_cameraInvertX = invert;
}
void CCamera::SetCameraInvertY(bool invert)
{
m_cameraInvertY = invert;
}
float CCamera::GetMotorTurn()
{
if (m_type == CAM_TYPE_BACK)
return m_motorTurn;
return 0.0f;
}
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;
m_remoteZoom = 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;
m_remoteZoom = 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 == 0 ) 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::GetSmoth()
{
return m_smooth;
}
void CCamera::SetDist(float dist)
{
m_fixDist = dist;
}
float CCamera::GetDist()
{
return m_fixDist;
}
void CCamera::SetFixDirection(float angle)
{
m_fixDirectionH = angle;
}
float CCamera::GetFixDirection()
{
return m_fixDirectionH;
}
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_visitDirectionH = 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);
}
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;
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 = powf(dist, 1.5f) * rTime * 0.5f;
if (m_smooth == CAM_SMOOTH_HARD) prog = powf(dist, 1.0f) * rTime * 4.0f;
if (m_smooth == CAM_SMOOTH_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 == CAM_SMOOTH_NONE ) prog = dist;
if ( m_smooth == CAM_SMOOTH_NORM ) prog = powf(dist, 1.5f) * rTime * 2.0f;
if ( m_smooth == CAM_SMOOTH_HARD ) prog = powf(dist, 1.0f) * rTime * 4.0f;
if ( m_smooth == CAM_SMOOTH_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);
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 == NULL)
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_FIX ||
oType == OBJECT_FRET ||
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->GetAngleY(0));
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_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;
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_MOVE:
EventMouseMove(event);
break;
case EVENT_MOUSE_WHEEL:
EventMouseWheel(event.mouseWheel.dir);
break;
default:
break;
}
return true;
}
bool CCamera::EventMouseMove(const Event &event)
{
m_mousePos = event.mousePos;
return true;
}
void CCamera::EventMouseWheel(WheelDirection dir)
{
if (m_type == CAM_TYPE_BACK)
{
if (dir == WHEEL_UP)
{
m_backDist -= 8.0f;
if (m_backDist < m_backMin)
m_backDist = m_backMin;
}
else if (dir == WHEEL_DOWN)
{
m_backDist += 8.0f;
if (m_backDist > 200.0f)
m_backDist = 200.0f;
}
}
if ( m_type == CAM_TYPE_FIX ||
m_type == CAM_TYPE_PLANE )
{
if (dir == WHEEL_UP)
{
m_fixDist -= 8.0f;
if (m_fixDist < 10.0f)
m_fixDist = 10.0f;
}
else if (dir == WHEEL_DOWN)
{
m_fixDist += 8.0f;
if (m_fixDist > 200.0f)
m_fixDist = 200.0f;
}
}
if ( m_type == CAM_TYPE_VISIT )
{
if (dir == WHEEL_UP)
{
m_visitDist -= 8.0f;
if (m_visitDist < 20.0f)
m_visitDist = 20.0f;
}
else if (dir == WHEEL_DOWN)
{
m_visitDist += 8.0f;
if (m_visitDist > 200.0f)
m_visitDist = 200.0f;
}
}
}
bool CCamera::EventFrame(const Event &event)
{
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;
}
EngineMouseType CCamera::GetMouseDef(Math::Point pos)
{
EngineMouseType type = ENG_MOUSE_NORM;
m_mousePos = pos;
if (m_type == CAM_TYPE_INFO)
return type;
if (m_rightDown) // the right button pressed?
{
m_rightPosMove.x = pos.x - m_rightPosCenter.x;
m_rightPosMove.y = pos.y - m_rightPosCenter.y;
type = ENG_MOUSE_MOVE;
}
else
{
if (!m_cameraScroll)
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 == 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_mouseDirH > 0.0f)
type = ENG_MOUSE_SCROLLR;
if (m_mouseDirH < 0.0f)
type = ENG_MOUSE_SCROLLL;
}
if ( m_type == CAM_TYPE_FREE ||
m_type == CAM_TYPE_EDIT )
{
if (m_mouseDirV > 0.0f)
type = ENG_MOUSE_SCROLLU;
if (m_mouseDirV < 0.0f)
type = ENG_MOUSE_SCROLLD;
}
if (m_cameraInvertX)
m_mouseDirH = -m_mouseDirH;
}
return type;
}
bool CCamera::EventFrameFree(const Event &event)
{
float 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.motionInput.y * event.rTime * factor * m_speed);
// Left/Right
if ( event.kmodState & KEY_MOD(CTRL) )
{
if ( event.motionInput.x < 0.0f )
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -event.motionInput.x * event.rTime * factor * m_speed);
if ( event.motionInput.x > 0.0f )
m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, event.motionInput.x * event.rTime * factor * m_speed);
}
else
{
m_directionH -= event.motionInput.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;
}
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;
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_cameraScroll)
{
// Left/Right.
m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
}
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 == NULL)
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_motorTurn = 0.0f;
if (m_rightDown)
{
m_addDirectionH = m_rightPosMove.x * 6.0f;
m_addDirectionV = -m_rightPosMove.y * 2.0f;
}
else
{
if (m_cameraScroll)
{
// Left/Right
m_addDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
m_addDirectionH = Math::NormAngle(m_addDirectionH);
}
}
if ((m_mouseDirH != 0) || (m_mouseDirV != 0))
AbortCentering(); // special stops framing
// 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 != NULL)
{
Math::Vector lookatPt = m_cameraObj->GetPosition(0);
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->GetAngleY(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;
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);
CPhysics* physics = m_cameraObj->GetPhysics();
if ( (physics != NULL) && physics->GetLand() ) // 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;
}
if (m_cameraScroll)
{
// Left/Right
m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
}
if ((m_mouseDirH != 0) || (m_mouseDirV != 0))
AbortCentering(); // special stops framing
if (m_cameraObj != NULL)
{
Math::Vector lookatPt = m_cameraObj->GetPosition(0);
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)
{
if (m_mouseDirH != 0.0f)
m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
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 != NULL)
{
Math::Vector lookatPt, upVec;
m_cameraObj->SetViewFromHere(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;
}
if (m_cameraScroll)
{
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;
}
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 == NULL)
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;*/
}
}