forked from 0ad/0ad
Ykkrosh
5e3e78ca78
Atlas: Changed video format to 640x480 and losslessly compressed. Added most-recently-used files list. Stopped switching sidebar when selecting tools, since it was getting annoying. Added Slow playback mode. Fixed crash when resetting sim while projectiles exist. Renderer: Added JS-accessible renderer.shadowMapSize to override the size of shadow maps. ShadowMap: Changed default depth texture bits to 24, since that seems to go faster (see #180). PolygonSortModelRenderer: Made more similar to other renderers, so that the renderer.sortAllTransparent=true mode works better. Projectile: Fixed update, so it interpolates smoothly. Entgraph: Fixed promotion detection. This was SVN commit r4876.
410 lines
9.3 KiB
C++
410 lines
9.3 KiB
C++
#include "precompiled.h"
|
|
|
|
#include "View.h"
|
|
|
|
#include "ActorViewer.h"
|
|
#include "GameLoop.h"
|
|
#include "Messages.h"
|
|
|
|
#include "graphics/CinemaTrack.h"
|
|
#include "graphics/GameView.h"
|
|
#include "graphics/Model.h"
|
|
#include "graphics/ObjectBase.h"
|
|
#include "graphics/ObjectEntry.h"
|
|
#include "graphics/SColor.h"
|
|
#include "graphics/Unit.h"
|
|
#include "graphics/UnitManager.h"
|
|
#include "lib/timer.h"
|
|
#include "maths/MathUtil.h"
|
|
#include "ps/Game.h"
|
|
#include "ps/GameSetup/GameSetup.h"
|
|
#include "ps/Player.h"
|
|
#include "renderer/Renderer.h"
|
|
#include "simulation/Entity.h"
|
|
#include "simulation/EntityManager.h"
|
|
#include "simulation/EntityTemplate.h"
|
|
#include "simulation/EntityTemplateCollection.h"
|
|
#include "simulation/Projectile.h"
|
|
#include "simulation/Simulation.h"
|
|
|
|
extern void (*Atlas_GLSwapBuffers)(void* context);
|
|
|
|
extern int g_xres, g_yres;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void View::SetParam(const std::wstring& UNUSED(name), bool UNUSED(value))
|
|
{
|
|
}
|
|
|
|
void View::SetParam(const std::wstring& UNUSED(name), const AtlasMessage::Colour& UNUSED(value))
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
ViewActor::ViewActor()
|
|
: m_SpeedMultiplier(1.f), m_ActorViewer(new ActorViewer())
|
|
{
|
|
}
|
|
|
|
ViewActor::~ViewActor()
|
|
{
|
|
delete m_ActorViewer;
|
|
}
|
|
|
|
void ViewActor::Update(float frameLength)
|
|
{
|
|
m_ActorViewer->Update(frameLength * m_SpeedMultiplier);
|
|
}
|
|
|
|
void ViewActor::Render()
|
|
{
|
|
SViewPort vp = { 0, 0, g_xres, g_yres };
|
|
CCamera& camera = GetCamera();
|
|
camera.SetViewPort(&vp);
|
|
camera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
|
|
camera.UpdateFrustum();
|
|
|
|
m_ActorViewer->Render();
|
|
Atlas_GLSwapBuffers((void*)g_GameLoop->glCanvas);
|
|
}
|
|
|
|
CCamera& ViewActor::GetCamera()
|
|
{
|
|
return m_Camera;
|
|
}
|
|
|
|
CUnit* ViewActor::GetUnit(AtlasMessage::ObjectID UNUSED(id))
|
|
{
|
|
return m_ActorViewer->GetUnit();
|
|
}
|
|
|
|
bool ViewActor::WantsHighFramerate()
|
|
{
|
|
if (m_SpeedMultiplier != 0.f && m_ActorViewer->HasAnimation())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void ViewActor::SetSpeedMultiplier(float speed)
|
|
{
|
|
m_SpeedMultiplier = speed;
|
|
}
|
|
|
|
ActorViewer& ViewActor::GetActorViewer()
|
|
{
|
|
return *m_ActorViewer;
|
|
}
|
|
|
|
void ViewActor::SetParam(const std::wstring& name, bool value)
|
|
{
|
|
if (name == L"wireframe")
|
|
g_Renderer.SetModelRenderMode(value ? WIREFRAME : SOLID);
|
|
else if (name == L"walk")
|
|
m_ActorViewer->SetWalkEnabled(value);
|
|
else if (name == L"ground")
|
|
m_ActorViewer->SetGroundEnabled(value);
|
|
else if (name == L"shadows")
|
|
m_ActorViewer->SetShadowsEnabled(value);
|
|
else if (name == L"stats")
|
|
m_ActorViewer->SetStatsEnabled(value);
|
|
}
|
|
|
|
void ViewActor::SetParam(const std::wstring& name, const AtlasMessage::Colour& value)
|
|
{
|
|
if (name == L"background")
|
|
{
|
|
m_ActorViewer->SetBackgroundColour(SColor4ub(value.r, value.g, value.b, 255));
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace AtlasMessage
|
|
{
|
|
extern void AtlasRenderSelection();
|
|
}
|
|
|
|
struct SimState
|
|
{
|
|
struct Entity
|
|
{
|
|
CStrW templateName;
|
|
int unitID;
|
|
std::set<CStr> selections;
|
|
int playerID;
|
|
CVector3D position;
|
|
float angle;
|
|
};
|
|
|
|
struct Nonentity
|
|
{
|
|
CStrW actorName;
|
|
int unitID;
|
|
std::set<CStr> selections;
|
|
CVector3D position;
|
|
float angle;
|
|
};
|
|
|
|
bool onlyEntities;
|
|
std::vector<Entity> entities;
|
|
std::vector<Nonentity> nonentities;
|
|
};
|
|
|
|
template<typename T, typename S>
|
|
static void delete_pair_2nd(std::pair<T,S> v)
|
|
{
|
|
delete v.second;
|
|
}
|
|
|
|
ViewGame::ViewGame()
|
|
: m_SpeedMultiplier(0.f)
|
|
{
|
|
debug_assert(g_Game);
|
|
}
|
|
|
|
ViewGame::~ViewGame()
|
|
{
|
|
std::for_each(m_SavedStates.begin(), m_SavedStates.end(), delete_pair_2nd<std::wstring, SimState*>);
|
|
}
|
|
|
|
void ViewGame::Update(float frameLength)
|
|
{
|
|
float actualFrameLength = frameLength * m_SpeedMultiplier;
|
|
|
|
if (m_SpeedMultiplier == 0.f)
|
|
{
|
|
// Update unit interpolation
|
|
g_Game->GetSimulation()->Interpolate(0.0);
|
|
}
|
|
else
|
|
{
|
|
// Update the whole world
|
|
// (Tell the game update not to interpolate graphics - we'll do that
|
|
// ourselves)
|
|
bool ok = g_Game->Update(actualFrameLength, false);
|
|
if (! ok)
|
|
{
|
|
// Whoops, we're trying to go faster than the simulation can manage.
|
|
// It's probably better to run at the right sim rate, at the expense
|
|
// of framerate, so let's try simulating a few more times.
|
|
double t = get_time();
|
|
while (!ok && get_time() < t + 0.1) // don't go much worse than 10fps
|
|
{
|
|
ok = g_Game->Update(0.0, false); // don't add on any extra sim time
|
|
}
|
|
}
|
|
// Interpolate the graphics - we only want to do it once per visual frame,
|
|
// not in every call to g_Game->Update
|
|
g_Game->GetSimulation()->Interpolate(actualFrameLength);
|
|
}
|
|
|
|
// Cinematic motion should be independent of simulation update, so we can
|
|
// preview the cinematics by themselves
|
|
if (g_Game->GetView()->GetCinema()->IsPlaying())
|
|
g_Game->GetView()->GetCinema()->Update(frameLength);
|
|
}
|
|
|
|
void ViewGame::Render()
|
|
{
|
|
SViewPort vp = { 0, 0, g_xres, g_yres };
|
|
CCamera& camera = GetCamera();
|
|
camera.SetViewPort(&vp);
|
|
camera.SetProjection(CGameView::defaultNear, CGameView::defaultFar, CGameView::defaultFOV);
|
|
camera.UpdateFrustum();
|
|
|
|
::Render();
|
|
AtlasMessage::AtlasRenderSelection();
|
|
Atlas_GLSwapBuffers((void*)g_GameLoop->glCanvas);
|
|
}
|
|
|
|
CCamera& ViewGame::GetCamera()
|
|
{
|
|
return *g_Game->GetView()->GetCamera();
|
|
}
|
|
|
|
CUnit* ViewGame::GetUnit(AtlasMessage::ObjectID id)
|
|
{
|
|
return g_Game->GetWorld()->GetUnitManager().FindByID(id);
|
|
}
|
|
|
|
bool ViewGame::WantsHighFramerate()
|
|
{
|
|
if (g_Game->GetView()->GetCinema()->IsPlaying())
|
|
return true;
|
|
|
|
if (m_SpeedMultiplier != 0.f)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void ViewGame::SetSpeedMultiplier(float speed)
|
|
{
|
|
m_SpeedMultiplier = speed;
|
|
}
|
|
|
|
void ViewGame::SaveState(const std::wstring& label, bool onlyEntities)
|
|
{
|
|
SimState* simState = new SimState();
|
|
simState->onlyEntities = onlyEntities;
|
|
|
|
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
|
const std::vector<CUnit*>& units = unitMan.GetUnits();
|
|
|
|
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit)
|
|
{
|
|
CEntity* entity = (*unit)->GetEntity();
|
|
|
|
// Ignore objects that aren't entities
|
|
if (! entity)
|
|
continue;
|
|
|
|
SimState::Entity e;
|
|
e.templateName = entity->m_base->m_Tag;
|
|
e.unitID = (*unit)->GetID();
|
|
e.selections = (*unit)->GetActorSelections();
|
|
e.playerID = entity->GetPlayer()->GetPlayerID();
|
|
e.position = entity->m_position;
|
|
e.angle = entity->m_orientation.Y;
|
|
|
|
simState->entities.push_back(e);
|
|
}
|
|
|
|
if (! onlyEntities)
|
|
{
|
|
for (std::vector<CUnit*>::const_iterator unit = units.begin(); unit != units.end(); ++unit) {
|
|
|
|
// Ignore objects that are entities
|
|
if ((*unit)->GetEntity())
|
|
continue;
|
|
|
|
SimState::Nonentity n;
|
|
n.actorName = (*unit)->GetObject()->m_Base->m_Name;
|
|
n.unitID = (*unit)->GetID();
|
|
n.selections = (*unit)->GetActorSelections();
|
|
n.position = (*unit)->GetModel()->GetTransform().GetTranslation();
|
|
CVector3D orient = (*unit)->GetModel()->GetTransform().GetIn();
|
|
n.angle = atan2(-orient.X, -orient.Z);
|
|
|
|
simState->nonentities.push_back(n);
|
|
}
|
|
}
|
|
|
|
delete m_SavedStates[label]; // in case it already exists
|
|
m_SavedStates[label] = simState;
|
|
}
|
|
|
|
void ViewGame::RestoreState(const std::wstring& label)
|
|
{
|
|
SimState* simState = m_SavedStates[label];
|
|
if (! simState)
|
|
return;
|
|
|
|
CUnitManager& unitMan = g_Game->GetWorld()->GetUnitManager();
|
|
|
|
// delete all existing entities
|
|
g_Game->GetWorld()->GetProjectileManager().DeleteAll();
|
|
g_EntityManager.deleteAll();
|
|
|
|
if (! simState->onlyEntities)
|
|
{
|
|
// delete all remaining non-entity units
|
|
unitMan.DeleteAll();
|
|
// don't reset the unitID counter - there's no need, since it'll work alright anyway
|
|
}
|
|
|
|
for (size_t i = 0; i < simState->entities.size(); ++i)
|
|
{
|
|
SimState::Entity& e = simState->entities[i];
|
|
|
|
CEntityTemplate* base = g_EntityTemplateCollection.getTemplate(e.templateName, g_Game->GetPlayer(e.playerID));
|
|
if (base)
|
|
{
|
|
HEntity ent = g_EntityManager.create(base, e.position, e.angle, e.selections);
|
|
|
|
if (ent)
|
|
{
|
|
ent->m_actor->SetPlayerID(e.playerID);
|
|
ent->m_actor->SetID(e.unitID);
|
|
}
|
|
}
|
|
}
|
|
|
|
g_EntityManager.InitializeAll();
|
|
|
|
if (! simState->onlyEntities)
|
|
{
|
|
for (size_t i = 0; i < simState->nonentities.size(); ++i)
|
|
{
|
|
SimState::Nonentity& n = simState->nonentities[i];
|
|
|
|
CUnit* unit = unitMan.CreateUnit(n.actorName, NULL, n.selections);
|
|
|
|
if (unit)
|
|
{
|
|
CMatrix3D m;
|
|
m.SetYRotation(n.angle + PI);
|
|
m.Translate(n.position);
|
|
unit->GetModel()->SetTransform(m);
|
|
|
|
unit->SetID(n.unitID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
ViewNone* view_None = NULL;
|
|
ViewGame* view_Game = NULL;
|
|
ViewActor* view_Actor = NULL;
|
|
|
|
View::~View()
|
|
{
|
|
}
|
|
|
|
View* View::GetView(int /*eRenderView*/ view)
|
|
{
|
|
switch (view)
|
|
{
|
|
case AtlasMessage::eRenderView::NONE: return View::GetView_None();
|
|
case AtlasMessage::eRenderView::GAME: return View::GetView_Game();
|
|
case AtlasMessage::eRenderView::ACTOR: return View::GetView_Actor();
|
|
default:
|
|
debug_warn("Invalid view type");
|
|
return View::GetView_None();
|
|
}
|
|
}
|
|
|
|
View* View::GetView_None()
|
|
{
|
|
if (! view_None)
|
|
view_None = new ViewNone();
|
|
return view_None;
|
|
}
|
|
|
|
ViewGame* View::GetView_Game()
|
|
{
|
|
if (! view_Game)
|
|
view_Game = new ViewGame();
|
|
return view_Game;
|
|
}
|
|
|
|
ViewActor* View::GetView_Actor()
|
|
{
|
|
if (! view_Actor)
|
|
view_Actor = new ViewActor();
|
|
return view_Actor;
|
|
}
|
|
|
|
void View::DestroyViews()
|
|
{
|
|
delete view_None; view_None = NULL;
|
|
delete view_Game; view_Game = NULL;
|
|
delete view_Actor; view_Actor = NULL;
|
|
}
|