418 lines
13 KiB
C++
418 lines
13 KiB
C++
/*
|
|
* This file is part of the Colobot: Gold Edition source code
|
|
* Copyright (C) 2001-2023, 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
|
|
*/
|
|
|
|
/**
|
|
* \file graphics/engine/camera.h
|
|
* \brief Camera handling - CCamera class
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "graphics/core/color.h"
|
|
|
|
class CObject;
|
|
class CRobotMain;
|
|
class CInput;
|
|
struct Event;
|
|
|
|
|
|
// Graphics module namespace
|
|
namespace Gfx
|
|
{
|
|
|
|
class CEngine;
|
|
class CTerrain;
|
|
class CWater;
|
|
|
|
enum class TransparencyMode : unsigned char;
|
|
|
|
/**
|
|
\enum CameraType
|
|
\brief Type of camera */
|
|
enum CameraType : unsigned char
|
|
{
|
|
//! Undefined
|
|
CAM_TYPE_NULL = 0,
|
|
//! Free camera
|
|
CAM_TYPE_FREE,
|
|
//! Camera while editing a program
|
|
CAM_TYPE_EDIT,
|
|
//! Camera on board a robot
|
|
CAM_TYPE_ONBOARD,
|
|
//! Camera behind a robot
|
|
CAM_TYPE_BACK,
|
|
//! Static camera following robot
|
|
CAM_TYPE_FIX,
|
|
//! Camera steady after explosion
|
|
CAM_TYPE_EXPLO,
|
|
//! Camera during a cutscene
|
|
CAM_TYPE_SCRIPT,
|
|
//! Visit camera, rotates around given position
|
|
CAM_TYPE_VISIT,
|
|
//! Static camera height
|
|
CAM_TYPE_PLANE,
|
|
};
|
|
|
|
enum CameraSmooth
|
|
{
|
|
//! Sharp
|
|
CAM_SMOOTH_NONE = 0,
|
|
//! Normal
|
|
CAM_SMOOTH_NORM = 1,
|
|
//! Hard
|
|
CAM_SMOOTH_HARD = 2,
|
|
};
|
|
|
|
enum CenteringPhase
|
|
{
|
|
CAM_PHASE_NULL = 0,
|
|
CAM_PHASE_START = 1,
|
|
CAM_PHASE_WAIT = 2,
|
|
CAM_PHASE_STOP = 3,
|
|
};
|
|
|
|
enum CameraEffect
|
|
{
|
|
//! No effect
|
|
CAM_EFFECT_NULL = 0,
|
|
//! Digging in
|
|
CAM_EFFECT_TERRAFORM = 1,
|
|
//! Hard landing
|
|
CAM_EFFECT_CRASH = 2,
|
|
//! Explosion
|
|
CAM_EFFECT_EXPLO = 3,
|
|
//! Shot by an enemy
|
|
CAM_EFFECT_SHOT = 4,
|
|
//! Vibration during construction
|
|
CAM_EFFECT_VIBRATION = 5,
|
|
//! Overheated reactor
|
|
CAM_EFFECT_PET = 6,
|
|
};
|
|
|
|
enum CameraOverEffect
|
|
{
|
|
//! No effect
|
|
CAM_OVER_EFFECT_NULL = 0,
|
|
//! Flash red
|
|
CAM_OVER_EFFECT_BLOOD = 1,
|
|
//! White -> nothing
|
|
CAM_OVER_EFFECT_FADEIN_WHITE = 2,
|
|
//! Nothing -> white
|
|
CAM_OVER_EFFECT_FADEOUT_WHITE = 3,
|
|
//! Nothing -> blue
|
|
CAM_OVER_EFFECT_FADEOUT_BLACK = 4,
|
|
//! Lightning
|
|
CAM_OVER_EFFECT_LIGHTNING = 5,
|
|
};
|
|
|
|
|
|
/**
|
|
\class CCamera
|
|
\brief Camera moving in 3D scene
|
|
|
|
This class manages everything related to animating the camera in 3D scene.
|
|
Calculated values are then passed to Gfx::CEngine.
|
|
*/
|
|
class CCamera
|
|
{
|
|
public:
|
|
CCamera();
|
|
~CCamera();
|
|
|
|
//! Management of an event
|
|
bool EventProcess(const Event &event);
|
|
|
|
/**
|
|
* \brief Initializes the camera
|
|
* \param eye Initial eye position
|
|
* \param lookat Initial lookat position
|
|
* \param delay Time of the initial entry animation
|
|
*/
|
|
void Init(glm::vec3 eye, glm::vec3 lookat, float delay);
|
|
|
|
//! Sets the object controlling the camera
|
|
void SetControllingObject(CObject* object);
|
|
//! Gets the object controlling the camera
|
|
CObject* GetControllingObject();
|
|
|
|
//! Change the type of camera
|
|
void SetType(CameraType type);
|
|
//! Get the type of the camera
|
|
CameraType GetType();
|
|
|
|
//! Set smoothing mode
|
|
void SetSmooth(CameraSmooth type);
|
|
//! Get smoothing mode
|
|
CameraSmooth GetSmooth();
|
|
|
|
|
|
//! Returns the current point of view of the camera
|
|
void GetCamera(glm::vec3 &eye, glm::vec3 &lookat);
|
|
|
|
//! \name Visit camera management (CAM_TYPE_VISIT) - camera in this mode shows a position, constantly rotating around it
|
|
//@{
|
|
//! Start visit camera
|
|
void StartVisit(glm::vec3 goal, float dist);
|
|
//! Stop visit camera
|
|
void StopVisit();
|
|
//@}
|
|
|
|
//! \name Camera "centering" - moves the camera to show some happening action (e.g. sniffer sniffing)
|
|
//@{
|
|
//! Move camera to show happening action
|
|
bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time);
|
|
//! Go back to normal position after showing some happening action
|
|
bool StopCentering(CObject *object, float time);
|
|
//! Abort centering animation in the current position
|
|
void AbortCentering();
|
|
//@}
|
|
|
|
//! \name Camera shake effects
|
|
//@{
|
|
//! Starts a camera shake effect
|
|
void StartEffect(CameraEffect effect, glm::vec3 pos, float force);
|
|
//! Removes the camera shake effect
|
|
void FlushEffect();
|
|
//@}
|
|
|
|
//! \name Camera overlay effects
|
|
//@{
|
|
//! Starts camera overlay effect
|
|
void StartOver(CameraOverEffect effect, glm::vec3 pos, float force);
|
|
//! Removes camera overlay effect
|
|
void FlushOver();
|
|
//! Specifies camera overlay effect base color
|
|
void SetOverBaseColor(Color color);
|
|
//@}
|
|
|
|
//! \name Script camera - cutscenes controlled by external code
|
|
//@{
|
|
//! Script camera: Set camera position
|
|
void SetScriptCamera(glm::vec3 eye, glm::vec3 lookat);
|
|
//! Script camera: Animate to given camera position
|
|
void SetScriptCameraAnimate(glm::vec3 eye, glm::vec3 lookat);
|
|
//! Script camera: Animate to given eye position
|
|
void SetScriptCameraAnimateEye(glm::vec3 eye);
|
|
//! Script camera: Animate to given lookat position
|
|
void SetScriptCameraAnimateLookat(glm::vec3 lookat);
|
|
//@}
|
|
|
|
//! \name Configuration settings
|
|
//@{
|
|
void SetEffect(bool enable);
|
|
bool GetEffect();
|
|
void SetBlood(bool enable);
|
|
bool GetBlood();
|
|
void SetOldCameraScroll(bool scroll);
|
|
bool GetOldCameraScroll();
|
|
void SetCameraInvertX(bool invert);
|
|
bool GetCameraInvertX();
|
|
void SetCameraInvertY(bool invert);
|
|
bool GetCameraInvertY();
|
|
//@}
|
|
|
|
//! Temporarily freeze camera movement
|
|
void SetFreeze(bool freeze);
|
|
|
|
//! Set camera speed
|
|
void SetCameraSpeed(float speed);
|
|
|
|
protected:
|
|
//! Advances the effect of the camera
|
|
void EffectFrame(const Event &event);
|
|
//! Advanced overlay effect in the foreground
|
|
void OverFrame(const Event &event);
|
|
|
|
bool EventFrameFree(const Event &event, bool keysAllowed);
|
|
bool EventFrameBack(const Event &event);
|
|
bool EventFrameFix(const Event &event);
|
|
bool EventFrameExplo(const Event &event);
|
|
bool EventFrameOnBoard(const Event &event);
|
|
bool EventFrameVisit(const Event &event);
|
|
bool EventFrameScript(const Event &event);
|
|
|
|
/**
|
|
* \brief Calculates camera animation and sends updated camera position to the 3D engine
|
|
* \param eyePt Eye point
|
|
* \param lookatPt Lookat point
|
|
* \param rTime Time since last time this function was called (used to calculate animation)
|
|
* \see SetViewParams
|
|
*/
|
|
void UpdateCameraAnimation(const glm::vec3 &eyePt, const glm::vec3 &lookatPt, float rTime);
|
|
|
|
/**
|
|
* \brief Avoid the obstacles
|
|
*
|
|
* For CAM_TYPE_BACK: make obstacles transparent
|
|
* For CAM_TYPE_FIX or CAM_TYPE_PLANE: adjust eye not to hit the obstacles
|
|
*
|
|
* \param eye Eye position, may be adjusted
|
|
* \param lookat Lookat point
|
|
*/
|
|
void IsCollision(glm::vec3 &eye, glm::vec3 lookat);
|
|
//! Avoid the obstacles (CAM_TYPE_BACK)
|
|
void IsCollisionBack();
|
|
//! Avoid the obstacles (CAM_TYPE_FIX or CAM_TYPE_PLANE)
|
|
void IsCollisionFix(glm::vec3 &eye, glm::vec3 lookat);
|
|
|
|
//! Adjusts the camera not to enter the ground
|
|
glm::vec3 ExcludeTerrain(glm::vec3 eye, glm::vec3 lookat, float &angleH, float &angleV);
|
|
//! Adjusts the camera not to enter an object
|
|
glm::vec3 ExcludeObject(glm::vec3 eye, glm::vec3 lookat, float &angleH, float &angleV);
|
|
|
|
/**
|
|
* \brief Updates the location and direction of the camera in the 3D engine
|
|
* \param eye Eye point
|
|
* \param lookat Lookat point
|
|
* \param up Up vector
|
|
* \see CEngine::SetViewParams
|
|
*/
|
|
void SetViewParams(const glm::vec3 &eye, const glm::vec3 &lookat, const glm::vec3 &up = glm::vec3(0.0f, 1.0f, 0.0f));
|
|
|
|
/**
|
|
* \brief Calculate camera movement (from user inputs) to apply
|
|
* \return glm::vec3 where x, y represent respectively horizontal and vertical angle change in radians and z represents zoom (distance change)
|
|
* \remarks Should not be called more often than once every EVENT_FRAME
|
|
**/
|
|
glm::vec3 CalculateCameraMovement(const Event &event, bool keysAllowed = true);
|
|
|
|
protected:
|
|
CEngine* m_engine;
|
|
CRobotMain* m_main;
|
|
CTerrain* m_terrain;
|
|
CWater* m_water;
|
|
CInput* m_input;
|
|
|
|
//! The type of camera
|
|
CameraType m_type;
|
|
//! Type of smoothing
|
|
CameraSmooth m_smooth;
|
|
//! Object linked to the camera
|
|
CObject* m_cameraObj;
|
|
|
|
//! Remaining time of initial camera entry animation
|
|
float m_initDelay;
|
|
|
|
//! Current eye
|
|
glm::vec3 m_actualEye{ 0, 0, 0 };
|
|
//! Current aim
|
|
glm::vec3 m_actualLookat{ 0, 0, 0 };
|
|
//! Final eye
|
|
glm::vec3 m_finalEye{ 0, 0, 0 };
|
|
//! Final lookat
|
|
glm::vec3 m_finalLookat{ 0, 0, 0 };
|
|
//! Eye position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT
|
|
glm::vec3 m_prevEye{ 0, 0, 0 };
|
|
//! Lookat position at the moment of entering CAM_TYPE_INFO/CAM_TYPE_VISIT
|
|
glm::vec3 m_prevLookat{ 0, 0, 0 };
|
|
|
|
float m_focus;
|
|
|
|
//! CAM_TYPE_FREE: eye
|
|
glm::vec3 m_eyePt{ 0, 0, 0 };
|
|
//! CAM_TYPE_FREE: horizontal direction
|
|
float m_directionH;
|
|
//! CAM_TYPE_FREE: vertical direction
|
|
float m_directionV;
|
|
//! CAM_TYPE_FREE: height above the ground
|
|
float m_heightEye;
|
|
//! CAM_TYPE_FREE: height above the ground
|
|
float m_heightLookat;
|
|
//! CAM_TYPE_FREE: speed of movement
|
|
float m_speed;
|
|
|
|
//! CAM_TYPE_BACK: distance
|
|
float m_backDist;
|
|
//! CAM_TYPE_BACK: minimal distance
|
|
float m_backMin;
|
|
//! CAM_TYPE_BACK: additional horizontal direction
|
|
float m_addDirectionH;
|
|
//! CAM_TYPE_BACK: additional vertical direction
|
|
float m_addDirectionV;
|
|
|
|
//! CAM_TYPE_FIX: distance
|
|
float m_fixDist;
|
|
//! CAM_TYPE_FIX: horizontal direction
|
|
float m_fixDirectionH;
|
|
//! CAM_TYPE_FIX: vertical direction
|
|
float m_fixDirectionV;
|
|
|
|
//! CAM_TYPE_VISIT: target position
|
|
glm::vec3 m_visitGoal{ 0, 0, 0 };
|
|
//! CAM_TYPE_VISIT: distance
|
|
float m_visitDist;
|
|
//! CAM_TYPE_VISIT: relative time
|
|
float m_visitTime;
|
|
//! CAM_TYPE_VISIT: initial type
|
|
CameraType m_visitType;
|
|
//! CAM_TYPE_VISIT: direction
|
|
float m_visitDirectionV;
|
|
|
|
//! Last known mouse position, used to calculate change since last frame
|
|
glm::vec2 m_mousePos = { 0.5f, 0.5f };
|
|
//! Change of mouse position since last frame
|
|
glm::vec2 m_mouseDelta = { 0.0f, 0.0f };
|
|
//! Change of camera position caused by edge camera
|
|
glm::vec2 m_mouseDeltaEdge = { 0.0f, 0.0f };
|
|
//! Change of mouse wheel since last frame
|
|
float m_mouseWheelDelta = 0.0f;
|
|
|
|
CenteringPhase m_centeringPhase;
|
|
float m_centeringAngleH;
|
|
float m_centeringAngleV;
|
|
float m_centeringDist;
|
|
float m_centeringCurrentH;
|
|
float m_centeringCurrentV;
|
|
float m_centeringTime;
|
|
float m_centeringProgress;
|
|
|
|
CameraEffect m_effectType;
|
|
glm::vec3 m_effectPos{ 0, 0, 0 };
|
|
float m_effectForce;
|
|
float m_effectProgress;
|
|
glm::vec3 m_effectOffset{ 0, 0, 0 };
|
|
|
|
CameraOverEffect m_overType;
|
|
float m_overForce;
|
|
float m_overTime;
|
|
Color m_overColorBase;
|
|
Color m_overColor;
|
|
TransparencyMode m_overMode;
|
|
float m_overFadeIn;
|
|
float m_overFadeOut;
|
|
|
|
glm::vec3 m_scriptEye{ 0, 0, 0 };
|
|
glm::vec3 m_scriptLookat{ 0, 0, 0 };
|
|
|
|
//! Is camera frozen?
|
|
bool m_freeze = false;
|
|
|
|
//! \name Configuration settings
|
|
//@{
|
|
bool m_effect;
|
|
bool m_blood;
|
|
bool m_oldCameraScroll;
|
|
bool m_cameraInvertX;
|
|
bool m_cameraInvertY;
|
|
//@}
|
|
};
|
|
|
|
|
|
} // namespace Gfx
|