1
0
forked from 0ad/0ad
0ad/source/tools/atlas/GameInterface/ActorViewer.cpp
Ykkrosh 4d4dc98bb5 # Integrated Actor Viewer tool into the Scenario Editor
and rewrote its UI in JS, but lost a few features (which could be added
back later)

This was SVN commit r6936.
2009-07-02 12:58:51 +00:00

346 lines
8.4 KiB
C++

/* Copyright (C) 2009 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 "ActorViewer.h"
#include "View.h"
#include "graphics/ColladaManager.h"
#include "graphics/Model.h"
#include "graphics/ObjectManager.h"
#include "graphics/Patch.h"
#include "graphics/SkeletonAnim.h"
#include "graphics/SkeletonAnimDef.h"
#include "graphics/SkeletonAnimManager.h"
#include "graphics/Terrain.h"
#include "graphics/TextureEntry.h"
#include "graphics/TextureManager.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "maths/MathUtil.h"
#include "ps/Font.h"
#include "ps/GameSetup/Config.h"
#include "ps/ProfileViewer.h"
#include "renderer/Renderer.h"
#include "renderer/Scene.h"
#include "renderer/SkyManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/EntityTemplate.h"
struct ActorViewerImpl : public Scene
{
NONCOPYABLE(ActorViewerImpl);
public:
ActorViewerImpl()
: Unit(NULL), ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
ObjectManager(MeshManager, SkeletonAnimManager)
{
}
CUnit* Unit;
CStrW CurrentUnitID;
CStrW CurrentUnitAnim;
float CurrentSpeed;
bool WalkEnabled;
bool GroundEnabled;
bool ShadowsEnabled;
SColor4ub Background;
CTerrain Terrain;
CColladaManager ColladaManager;
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
// Simplistic implementation of the Scene interface
void EnumerateObjects(const CFrustum& UNUSED(frustum), SceneCollector* c)
{
if (GroundEnabled)
c->Submit(Terrain.GetPatch(0, 0));
if (Unit)
c->SubmitRecursive(Unit->GetModel());
}
};
ActorViewer::ActorViewer()
: m(*new ActorViewerImpl())
{
m.Unit = NULL;
m.WalkEnabled = false;
m.GroundEnabled = true;
m.ShadowsEnabled = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
m.Background = SColor4ub(255, 255, 255, 255);
// Set up the renderer
g_TexMan.LoadTerrainTextures();
g_Renderer.LoadAlphaMaps();
g_Renderer.GetSkyManager()->m_RenderSky = false;
// (TODO: should these be unloaded properly some time? and what should
// happen if we want the actor viewer and scenario editor loaded at
// the same time?)
// Create a tiny empty piece of terrain, just so we can put shadows
// on it without having to think too hard
m.Terrain.Initialize(1, NULL);
CTextureEntry* tex = g_TexMan.FindTexture("whiteness");
if (tex)
{
CPatch* patch = m.Terrain.GetPatch(0, 0);
for (ssize_t i = 0; i < PATCH_SIZE; ++i)
{
for (ssize_t j = 0; j < PATCH_SIZE; ++j)
{
CMiniPatch& mp = patch->m_MiniPatches[i][j];
mp.Tex1 = tex->GetHandle();
mp.Tex1Priority = 0;
}
}
}
}
ActorViewer::~ActorViewer()
{
delete m.Unit;
delete &m;
}
CUnit* ActorViewer::GetUnit()
{
return m.Unit;
}
void ActorViewer::UnloadObjects()
{
m.ObjectManager.UnloadObjects();
}
// We want to support selection of both entities and actors in the
// Actor Viewer tool, so work out the actor corresponding to the given
// string
static bool ParseObjectName(const CStrW& obj, CStrW& name)
{
if (obj.substr(0, 4) == L"(e) ")
{
CStrW entname = obj.substr(4);
CEntityTemplate* entity = g_EntityTemplateCollection.GetTemplate(entname);
if (! entity)
return false;
name = entity->m_actorName;
return true;
}
else if (obj.substr(0, 4) == L"(n) ")
{
name = obj.substr(4);
return true;
}
else
{
// By default, assume it's just an actor name. (TODO: This
// case is probably only used by the obsolete standalone
// Actor Viewer and should get removed eventually.)
name = obj;
return true;
}
}
void ActorViewer::SetActor(const CStrW& name, const CStrW& animation)
{
bool needsAnimReload = false;
CStrW id;
if (! ParseObjectName(name, id))
id = L"";
if (! m.Unit || id != m.CurrentUnitID)
{
delete m.Unit;
m.Unit = NULL;
// If there's no actor to display, return with nothing loaded
if (id.empty())
return;
m.Unit = CUnit::Create((CStr)id, NULL, std::set<CStr>(), m.ObjectManager);
if (! m.Unit)
return;
float angle = PI;
CMatrix3D mat;
mat.SetYRotation(angle + PI);
mat.Translate(CELL_SIZE * PATCH_SIZE/2, 0.f, CELL_SIZE * PATCH_SIZE/2);
m.Unit->GetModel()->SetTransform(mat);
m.Unit->GetModel()->ValidatePosition();
needsAnimReload = true;
}
if (animation != m.CurrentUnitAnim)
needsAnimReload = true;
if (needsAnimReload)
{
CStr anim = ((CStr)animation).LowerCase();
float speed;
// TODO: this is just copied from template_unit.xml and isn't the
// same for all units. But we don't know anything about entities here,
// so what to do?
if (anim == "walk")
speed = 7.f;
else if (anim == "run")
speed = 12.f;
else
speed = 0.f;
m.CurrentSpeed = speed;
m.Unit->SetEntitySelection(anim);
m.Unit->SetRandomAnimation(anim, false, speed);
}
m.CurrentUnitID = id;
m.CurrentUnitAnim = animation;
}
void ActorViewer::SetBackgroundColour(const SColor4ub& colour)
{
m.Background = colour;
m.Terrain.SetBaseColour(colour);
}
void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; }
void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; }
void ActorViewer::SetShadowsEnabled(bool enabled) { m.ShadowsEnabled = enabled; }
void ActorViewer::SetStatsEnabled(bool enabled)
{
if (enabled)
g_ProfileViewer.ShowTable("renderer");
else
g_ProfileViewer.ShowTable("");
}
void ActorViewer::Render()
{
m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR);
g_Renderer.SetClearColor(m.Background);
// Disable shadows locally (avoid clobbering global state)
bool oldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);
g_Renderer.BeginFrame();
// Find the centre of the interesting region, in the middle of the patch
// and half way up the model (assuming there is one)
CVector3D centre;
if (m.Unit)
m.Unit->GetModel()->GetBounds().GetCentre(centre);
else
centre.Y = 0.f;
centre.X = centre.Z = CELL_SIZE * PATCH_SIZE/2;
CCamera camera = View::GetView_Actor()->GetCamera();
camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z);
camera.UpdateFrustum();
g_Renderer.SetSceneCamera(camera, camera);
g_Renderer.RenderScene(&m);
// ....
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
CFont font("console");
font.Bind();
g_ProfileViewer.RenderProfile();
glPopAttrib();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
g_Renderer.EndFrame();
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, oldShadows);
ogl_WarnIfError();
}
void ActorViewer::Update(float dt)
{
if (m.Unit)
{
m.Unit->GetModel()->Update(dt);
CMatrix3D mat = m.Unit->GetModel()->GetTransform();
if (m.WalkEnabled && m.CurrentSpeed)
{
// Move the model by speed*dt forwards
float z = mat.GetTranslation().Z;
z -= m.CurrentSpeed*dt;
// Wrap at the edges, so it doesn't run off into the horizon
if (z < CELL_SIZE*PATCH_SIZE * 0.4f)
z = CELL_SIZE*PATCH_SIZE * 0.6f;
mat.Translate(0.f, 0.f, z - mat.GetTranslation().Z);
}
m.Unit->GetModel()->SetTransform(mat);
m.Unit->GetModel()->ValidatePosition();
}
}
bool ActorViewer::HasAnimation() const
{
if (m.Unit &&
m.Unit->GetModel()->GetAnimation() &&
m.Unit->GetModel()->GetAnimation()->m_AnimDef &&
m.Unit->GetModel()->GetAnimation()->m_AnimDef->GetNumFrames() > 1)
return true;
if (m.Unit && m.WalkEnabled && m.CurrentSpeed)
return true;
return false;
}