/* * 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