mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Accepted By: @vladislavbelov Comments By: @Stan Differential Revision: https://code.wildfiregames.com/D4739 This was SVN commit r27861.
407 lines
10 KiB
C++
407 lines
10 KiB
C++
/* Copyright (C) 2023 Wildfire Games.
|
||
* This file is part of 0 A.D.
|
||
*
|
||
* 0 A.D. 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 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "precompiled.h"
|
||
|
||
#include "GameView.h"
|
||
|
||
#include "graphics/CameraController.h"
|
||
#include "graphics/CinemaManager.h"
|
||
#include "graphics/ColladaManager.h"
|
||
#include "graphics/HFTracer.h"
|
||
#include "graphics/LOSTexture.h"
|
||
#include "graphics/LightEnv.h"
|
||
#include "graphics/MiniMapTexture.h"
|
||
#include "graphics/Model.h"
|
||
#include "graphics/ObjectManager.h"
|
||
#include "graphics/Patch.h"
|
||
#include "graphics/SkeletonAnimManager.h"
|
||
#include "graphics/SmoothedValue.h"
|
||
#include "graphics/Terrain.h"
|
||
#include "graphics/TerrainTextureManager.h"
|
||
#include "graphics/TerritoryTexture.h"
|
||
#include "graphics/Unit.h"
|
||
#include "graphics/UnitManager.h"
|
||
#include "lib/input.h"
|
||
#include "lib/timer.h"
|
||
#include "lobby/IXmppClient.h"
|
||
#include "maths/BoundingBoxAligned.h"
|
||
#include "maths/MathUtil.h"
|
||
#include "maths/Matrix3D.h"
|
||
#include "maths/Quaternion.h"
|
||
#include "ps/ConfigDB.h"
|
||
#include "ps/Filesystem.h"
|
||
#include "ps/Game.h"
|
||
#include "ps/Globals.h"
|
||
#include "ps/Hotkey.h"
|
||
#include "ps/Loader.h"
|
||
#include "ps/Profile.h"
|
||
#include "ps/Pyrogenesis.h"
|
||
#include "ps/TouchInput.h"
|
||
#include "ps/World.h"
|
||
#include "renderer/Renderer.h"
|
||
#include "renderer/SceneRenderer.h"
|
||
#include "renderer/WaterManager.h"
|
||
#include "simulation2/Simulation2.h"
|
||
#include "simulation2/components/ICmpPosition.h"
|
||
#include "simulation2/components/ICmpRangeManager.h"
|
||
|
||
#include <memory>
|
||
|
||
class CGameViewImpl
|
||
{
|
||
NONCOPYABLE(CGameViewImpl);
|
||
public:
|
||
CGameViewImpl(Renderer::Backend::IDevice* device, CGame* game)
|
||
: Game(game),
|
||
ColladaManager(g_VFS), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
|
||
ObjectManager(MeshManager, SkeletonAnimManager, *game->GetSimulation2()),
|
||
LOSTexture(*game->GetSimulation2()),
|
||
TerritoryTexture(*game->GetSimulation2()),
|
||
MiniMapTexture(device, *game->GetSimulation2()),
|
||
ViewCamera(),
|
||
CullCamera(),
|
||
LockCullCamera(false),
|
||
Culling(true),
|
||
CameraController(new CCameraController(ViewCamera))
|
||
{
|
||
}
|
||
|
||
CGame* Game;
|
||
CColladaManager ColladaManager;
|
||
CMeshManager MeshManager;
|
||
CSkeletonAnimManager SkeletonAnimManager;
|
||
CObjectManager ObjectManager;
|
||
CLOSTexture LOSTexture;
|
||
CTerritoryTexture TerritoryTexture;
|
||
CMiniMapTexture MiniMapTexture;
|
||
|
||
/**
|
||
* this camera controls the eye position when rendering
|
||
*/
|
||
CCamera ViewCamera;
|
||
|
||
/**
|
||
* this camera controls the frustum that is used for culling
|
||
* and shadow calculations
|
||
*
|
||
* Note that all code that works with camera movements should only change
|
||
* m_ViewCamera. The render functions automatically sync the cull camera to
|
||
* the view camera depending on the value of m_LockCullCamera.
|
||
*/
|
||
CCamera CullCamera;
|
||
|
||
/**
|
||
* When @c true, the cull camera is locked in place.
|
||
* When @c false, the cull camera follows the view camera.
|
||
*
|
||
* Exposed to JS as gameView.lockCullCamera
|
||
*/
|
||
bool LockCullCamera;
|
||
|
||
/**
|
||
* When @c true, culling is enabled so that only models that have a chance of
|
||
* being visible are sent to the renderer.
|
||
* Otherwise, the entire world is sent to the renderer.
|
||
*
|
||
* Exposed to JS as gameView.culling
|
||
*/
|
||
bool Culling;
|
||
|
||
CCinemaManager CinemaManager;
|
||
|
||
/**
|
||
* Controller of the view's camera. We use a std::unique_ptr for an easy
|
||
* on the fly replacement. It's guaranteed that the pointer is never nulllptr.
|
||
*/
|
||
std::unique_ptr<ICameraController> CameraController;
|
||
};
|
||
|
||
#define IMPLEMENT_BOOLEAN_SETTING(NAME) \
|
||
bool CGameView::Get##NAME##Enabled() const \
|
||
{ \
|
||
return m->NAME; \
|
||
} \
|
||
\
|
||
void CGameView::Set##NAME##Enabled(bool Enabled) \
|
||
{ \
|
||
m->NAME = Enabled; \
|
||
}
|
||
|
||
IMPLEMENT_BOOLEAN_SETTING(Culling);
|
||
IMPLEMENT_BOOLEAN_SETTING(LockCullCamera);
|
||
|
||
bool CGameView::GetConstrainCameraEnabled() const
|
||
{
|
||
return m->CameraController->GetConstrainCamera();
|
||
}
|
||
|
||
void CGameView::SetConstrainCameraEnabled(bool enabled)
|
||
{
|
||
m->CameraController->SetConstrainCamera(enabled);
|
||
}
|
||
|
||
#undef IMPLEMENT_BOOLEAN_SETTING
|
||
|
||
CGameView::CGameView(Renderer::Backend::IDevice* device, CGame *pGame):
|
||
m(new CGameViewImpl(device, pGame))
|
||
{
|
||
m->CullCamera = m->ViewCamera;
|
||
g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera);
|
||
}
|
||
|
||
CGameView::~CGameView()
|
||
{
|
||
UnloadResources();
|
||
|
||
delete m;
|
||
}
|
||
|
||
void CGameView::SetViewport(const SViewPort& vp)
|
||
{
|
||
m->CameraController->SetViewport(vp);
|
||
}
|
||
|
||
CObjectManager& CGameView::GetObjectManager()
|
||
{
|
||
return m->ObjectManager;
|
||
}
|
||
|
||
CCamera* CGameView::GetCamera()
|
||
{
|
||
return &m->ViewCamera;
|
||
}
|
||
|
||
CCinemaManager* CGameView::GetCinema()
|
||
{
|
||
return &m->CinemaManager;
|
||
}
|
||
|
||
CLOSTexture& CGameView::GetLOSTexture()
|
||
{
|
||
return m->LOSTexture;
|
||
}
|
||
|
||
CTerritoryTexture& CGameView::GetTerritoryTexture()
|
||
{
|
||
return m->TerritoryTexture;
|
||
}
|
||
|
||
CMiniMapTexture& CGameView::GetMiniMapTexture()
|
||
{
|
||
return m->MiniMapTexture;
|
||
}
|
||
|
||
void CGameView::RegisterInit()
|
||
{
|
||
// CGameView init
|
||
LDR_Register([this](const double)
|
||
{
|
||
m->CameraController->LoadConfig();
|
||
return 0;
|
||
}, L"CGameView init", 1);
|
||
|
||
LDR_Register([](const double)
|
||
{
|
||
return g_TexMan.LoadTerrainTextures();
|
||
}, L"LoadTerrainTextures", 60);
|
||
}
|
||
|
||
void CGameView::BeginFrame()
|
||
{
|
||
if (m->LockCullCamera == false)
|
||
{
|
||
// Set up cull camera
|
||
m->CullCamera = m->ViewCamera;
|
||
}
|
||
g_Renderer.GetSceneRenderer().SetSceneCamera(m->ViewCamera, m->CullCamera);
|
||
|
||
m->Game->CachePlayerColors();
|
||
}
|
||
|
||
void CGameView::Prepare(
|
||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||
{
|
||
g_Renderer.GetSceneRenderer().PrepareScene(deviceCommandContext, *this);
|
||
}
|
||
|
||
void CGameView::Render(
|
||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||
{
|
||
g_Renderer.GetSceneRenderer().RenderScene(deviceCommandContext);
|
||
}
|
||
|
||
void CGameView::RenderOverlays(
|
||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
|
||
{
|
||
g_Renderer.GetSceneRenderer().RenderSceneOverlays(deviceCommandContext);
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////
|
||
// This callback is part of the Scene interface
|
||
// Submit all objects visible in the given frustum
|
||
void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
|
||
{
|
||
{
|
||
PROFILE3("submit terrain");
|
||
|
||
const CTerrain& terrain = m->Game->GetWorld()->GetTerrain();
|
||
float waterHeight = g_Renderer.GetSceneRenderer().GetWaterManager().m_WaterHeight + 0.001f;
|
||
const ssize_t patchesPerSide = terrain.GetPatchesPerSide();
|
||
|
||
// find out which patches will be drawn
|
||
for (ssize_t j=0; j<patchesPerSide; ++j)
|
||
{
|
||
for (ssize_t i=0; i<patchesPerSide; ++i)
|
||
{
|
||
CPatch* const patch = terrain.GetPatch(i,j); // can't fail
|
||
|
||
// If the patch is underwater, calculate a bounding box that also contains the water plane
|
||
CBoundingBoxAligned bounds = patch->GetWorldBounds();
|
||
if(bounds[1].Y < waterHeight)
|
||
bounds[1].Y = waterHeight;
|
||
|
||
if (!m->Culling || frustum.IsBoxVisible(bounds))
|
||
c->Submit(patch);
|
||
}
|
||
}
|
||
}
|
||
|
||
m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling);
|
||
}
|
||
|
||
void CGameView::UnloadResources()
|
||
{
|
||
g_TexMan.UnloadTerrainTextures();
|
||
g_Renderer.GetSceneRenderer().GetWaterManager().UnloadWaterTextures();
|
||
}
|
||
|
||
void CGameView::Update(const float deltaRealTime)
|
||
{
|
||
m->MiniMapTexture.Update(deltaRealTime);
|
||
|
||
// If camera movement is being handled by the touch-input system,
|
||
// then we should stop to avoid conflicting with it
|
||
if (g_TouchInput.IsEnabled())
|
||
return;
|
||
|
||
if (!g_app_has_focus)
|
||
return;
|
||
|
||
m->CinemaManager.Update(deltaRealTime);
|
||
if (m->CinemaManager.IsEnabled())
|
||
return;
|
||
|
||
m->CameraController->Update(deltaRealTime);
|
||
}
|
||
|
||
CVector3D CGameView::GetCameraPivot() const
|
||
{
|
||
return m->CameraController->GetCameraPivot();
|
||
}
|
||
|
||
CVector3D CGameView::GetCameraPosition() const
|
||
{
|
||
return m->CameraController->GetCameraPosition();
|
||
}
|
||
|
||
CVector3D CGameView::GetCameraRotation() const
|
||
{
|
||
return m->CameraController->GetCameraRotation();
|
||
}
|
||
|
||
float CGameView::GetCameraZoom() const
|
||
{
|
||
return m->CameraController->GetCameraZoom();
|
||
}
|
||
|
||
void CGameView::SetCamera(const CVector3D& pos, float rotX, float rotY, float zoom)
|
||
{
|
||
m->CameraController->SetCamera(pos, rotX, rotY, zoom);
|
||
}
|
||
|
||
void CGameView::MoveCameraTarget(const CVector3D& target)
|
||
{
|
||
m->CameraController->MoveCameraTarget(target);
|
||
}
|
||
|
||
void CGameView::ResetCameraTarget(const CVector3D& target)
|
||
{
|
||
m->CameraController->ResetCameraTarget(target);
|
||
}
|
||
|
||
void CGameView::FollowEntity(entity_id_t entity, bool firstPerson)
|
||
{
|
||
m->CameraController->FollowEntity(entity, firstPerson);
|
||
}
|
||
|
||
entity_id_t CGameView::GetFollowedEntity()
|
||
{
|
||
return m->CameraController->GetFollowedEntity();
|
||
}
|
||
|
||
InReaction game_view_handler(const SDL_Event_* ev)
|
||
{
|
||
// put any events that must be processed even if inactive here
|
||
if (!g_app_has_focus || !g_Game || !g_Game->IsGameStarted() || g_Game->GetView()->GetCinema()->IsEnabled())
|
||
return IN_PASS;
|
||
|
||
CGameView *pView=g_Game->GetView();
|
||
|
||
return pView->HandleEvent(ev);
|
||
}
|
||
|
||
InReaction CGameView::HandleEvent(const SDL_Event_* ev)
|
||
{
|
||
switch(ev->ev.type)
|
||
{
|
||
case SDL_HOTKEYPRESS:
|
||
{
|
||
std::string hotkey = static_cast<const char*>(ev->ev.user.data1);
|
||
CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer();
|
||
if (hotkey == "wireframe")
|
||
{
|
||
if (g_XmppClient && g_rankedGame == true)
|
||
break;
|
||
else if (sceneRenderer.GetModelRenderMode() == SOLID)
|
||
{
|
||
sceneRenderer.SetTerrainRenderMode(EDGED_FACES);
|
||
sceneRenderer.SetWaterRenderMode(EDGED_FACES);
|
||
sceneRenderer.SetModelRenderMode(EDGED_FACES);
|
||
sceneRenderer.SetOverlayRenderMode(EDGED_FACES);
|
||
}
|
||
else if (sceneRenderer.GetModelRenderMode() == EDGED_FACES)
|
||
{
|
||
sceneRenderer.SetTerrainRenderMode(WIREFRAME);
|
||
sceneRenderer.SetWaterRenderMode(WIREFRAME);
|
||
sceneRenderer.SetModelRenderMode(WIREFRAME);
|
||
sceneRenderer.SetOverlayRenderMode(WIREFRAME);
|
||
}
|
||
else
|
||
{
|
||
sceneRenderer.SetTerrainRenderMode(SOLID);
|
||
sceneRenderer.SetWaterRenderMode(SOLID);
|
||
sceneRenderer.SetModelRenderMode(SOLID);
|
||
sceneRenderer.SetOverlayRenderMode(SOLID);
|
||
}
|
||
return IN_HANDLED;
|
||
}
|
||
}
|
||
}
|
||
|
||
return m->CameraController->HandleEvent(ev);
|
||
}
|