Index: ps/trunk/source/renderer/SkyManager.cpp
===================================================================
--- ps/trunk/source/renderer/SkyManager.cpp (revision 21951)
+++ ps/trunk/source/renderer/SkyManager.cpp (revision 21952)
@@ -1,329 +1,300 @@
-/* Copyright (C) 2013 Wildfire Games.
+/* Copyright (C) 2018 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 .
*/
/*
* Sky settings, texture management and rendering.
*/
#include "precompiled.h"
#include
+#include "graphics/LightEnv.h"
+#include "graphics/ShaderManager.h"
+#include "graphics/Terrain.h"
+#include "graphics/TextureManager.h"
#include "lib/timer.h"
#include "lib/tex/tex.h"
#include "lib/res/graphics/ogl_tex.h"
-
#include "maths/MathUtil.h"
-
#include "ps/CStr.h"
#include "ps/CLogger.h"
#include "ps/Game.h"
#include "ps/Loader.h"
#include "ps/Filesystem.h"
#include "ps/World.h"
-
#include "renderer/SkyManager.h"
#include "renderer/Renderer.h"
-#include "graphics/LightEnv.h"
-#include "graphics/ShaderManager.h"
-#include "graphics/Terrain.h"
-#include "graphics/TextureManager.h"
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// SkyManager implementation
-
-///////////////////////////////////////////////////////////////////
-// String names for each image, in order of the IMG_ constants
-const wchar_t* SkyManager::s_imageNames[numTextures] = {
- L"front",
- L"back",
- L"right",
- L"left",
- L"top"
-};
-
-
-///////////////////////////////////////////////////////////////////
-// Construction/Destruction
SkyManager::SkyManager()
+ : m_RenderSky(true), m_HorizonHeight(-150.0f), m_SkyCubeMap(0)
{
- m_RenderSky = true;
-
- m_SkySet = L"";
-
- m_HorizonHeight = -150.0f;
-
- m_SkyCubeMap = 0;
}
-
///////////////////////////////////////////////////////////////////
// Load all sky textures
void SkyManager::LoadSkyTextures()
{
+ static const CStrW images[NUMBER_OF_TEXTURES + 1] = {
+ L"front",
+ L"back",
+ L"right",
+ L"left",
+ L"top",
+ L"top"
+ };
/*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i)
{
VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds");
CTextureProperties textureProps(path);
textureProps.SetWrap(GL_CLAMP_TO_EDGE);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch();
m_SkyTexture[i] = texture;
}*/
///////////////////////////////////////////////////////////////////////////
// HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
// as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
glGenTextures(1, &m_SkyCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap);
- int types[] = {
+ static const int types[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
};
- const wchar_t* images[numTextures+1] = {
- L"front",
- L"back",
- L"right",
- L"left",
- L"top",
- L"top"
- };
-
- for (size_t i = 0; i < numTextures+1; ++i)
+ for (size_t i = 0; i < NUMBER_OF_TEXTURES + 1; ++i)
{
VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds");
shared_ptr file;
size_t fileSize;
- if (g_VFS->LoadFile(path, file, fileSize) < 0)
+ if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
{
- VfsPath path2 = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds.cached.dds");
- if (g_VFS->LoadFile(path2, file, fileSize) < 0)
+ path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds.cached.dds");
+ if (g_VFS->LoadFile(path, file, fileSize) != INFO::OK)
{
glDeleteTextures(1, &m_SkyCubeMap);
LOGERROR("Error creating sky cubemap.");
return;
}
}
Tex tex;
tex.decode(file, fileSize);
tex.transform_to((tex.m_Flags | TEX_BOTTOM_UP | TEX_ALPHA) & ~(TEX_DXT | TEX_MIPMAPS));
u8* data = tex.get_data();
if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y)
{
std::vector rotated(tex.m_DataSize);
for (size_t y = 0; y < tex.m_Height; ++y)
{
for (size_t x = 0; x < tex.m_Width; ++x)
{
size_t invx = y, invy = tex.m_Width-x-1;
rotated[(y*tex.m_Width + x) * 4 + 0] = data[(invy*tex.m_Width + invx) * 4 + 0];
rotated[(y*tex.m_Width + x) * 4 + 1] = data[(invy*tex.m_Width + invx) * 4 + 1];
rotated[(y*tex.m_Width + x) * 4 + 2] = data[(invy*tex.m_Width + invx) * 4 + 2];
rotated[(y*tex.m_Width + x) * 4 + 3] = data[(invy*tex.m_Width + invx) * 4 + 3];
}
}
glTexImage2D(types[i], 0, GL_RGB, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]);
}
else
{
glTexImage2D(types[i], 0, GL_RGB, tex.m_Width, tex.m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if CONFIG2_GLES
#warning TODO: fix SkyManager::LoadSkyTextures for GLES
#else
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
#endif
glBindTexture(GL_TEXTURE_2D, 0);
///////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////
// Switch to a different sky set (while the game is running)
-void SkyManager::SetSkySet( const CStrW& newSet )
+void SkyManager::SetSkySet(const CStrW& newSet)
{
- if(newSet == m_SkySet)
+ if (newSet == m_SkySet)
return;
if (m_SkyCubeMap)
{
glDeleteTextures(1, &m_SkyCubeMap);
m_SkyCubeMap = 0;
}
m_SkySet = newSet;
LoadSkyTextures();
}
///////////////////////////////////////////////////////////////////
// Generate list of available skies
std::vector SkyManager::GetSkySets() const
{
std::vector skies;
// Find all subdirectories in art/textures/skies
const VfsPath path(L"art/textures/skies/");
DirectoryNames subdirectories;
- if(g_VFS->GetDirectoryEntries(path, 0, &subdirectories) < 0)
+ if (g_VFS->GetDirectoryEntries(path, 0, &subdirectories) != INFO::OK)
{
LOGERROR("Error opening directory '%s'", path.string8());
return std::vector(1, GetSkySet()); // just return what we currently have
}
for(size_t i = 0; i < subdirectories.size(); i++)
skies.push_back(subdirectories[i].string());
sort(skies.begin(), skies.end());
return skies;
}
///////////////////////////////////////////////////////////////////
// Render sky
void SkyManager::RenderSky()
{
#if CONFIG2_GLES
#warning TODO: implement SkyManager::RenderSky for GLES
#else
// Draw the sky as a small box around the map, with depth write enabled.
// This will be done before anything else is drawn so we'll be overlapped by everything else.
// Do nothing unless SetSkySet was called
if (m_SkySet.empty())
return;
glDepthMask( GL_FALSE );
pglActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Translate so we are at the center of the map.
ssize_t mapSize = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
glTranslatef(mapSize*(TERRAIN_TILE_SIZE/2.0f), m_HorizonHeight, mapSize*(TERRAIN_TILE_SIZE/2.0f) );
// Rotate so that the "left" face, which contains the brightest part of each
// skymap, is in the direction of the sun from our light environment
glRotatef( 180.0f /*+ 45.0f*/ + RADTODEG(g_Renderer.GetLightEnv().GetRotation()), 0.0f, 1.0f, 0.0f );
// Distance to draw the faces at
const float D = 1500.0f; // distance from map center
const float H = 500.0f; // height of the ceiling
const float FH = -100.0f; // height of the "floor"
CShaderProgramPtr shader;
CShaderTechniquePtr skytech;
if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
{
skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple);
skytech->BeginPass();
shader = skytech->GetShader();
shader->BindTexture(str_baseTex, m_SkyCubeMap);
}
else
{
glDisable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap);
}
glBegin(GL_QUADS);
// GL_TEXTURE_CUBE_MAP_NEGATIVE_X
glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, FH, -D );
glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, FH, +D );
glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +H, +D );
glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +H, -D );
// GL_TEXTURE_CUBE_MAP_POSITIVE_X
glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, FH, +D );
glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, FH, -D );
glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +H, -D );
glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +H, +D );
// GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, FH, -D );
glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, FH, +D );
glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, FH, +D );
glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, FH, -D );
// GL_TEXTURE_CUBE_MAP_POSITIVE_Y
glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +H, -D );
glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +H, +D );
glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +H, +D );
glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +H, -D );
// GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, FH, -D );
glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, FH, -D );
glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +H, -D );
glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +H, -D );
// GL_TEXTURE_CUBE_MAP_POSITIVE_Z
glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, FH, +D );
glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, FH, +D );
glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +H, +D );
glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +H, +D );
glEnd();
if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
{
skytech->EndPass();
}
else
{
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
glDisable(GL_TEXTURE_CUBE_MAP);
glEnable(GL_TEXTURE_2D);
}
glPopMatrix();
glDepthMask( GL_TRUE );
#endif
}
Index: ps/trunk/source/renderer/SkyManager.h
===================================================================
--- ps/trunk/source/renderer/SkyManager.h (revision 21951)
+++ ps/trunk/source/renderer/SkyManager.h (revision 21952)
@@ -1,93 +1,101 @@
-/* Copyright (C) 2012 Wildfire Games.
+/* Copyright (C) 2018 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 .
*/
/*
* Sky settings and texture management
*/
#ifndef INCLUDED_SKYMANAGER
#define INCLUDED_SKYMANAGER
#include "graphics/Texture.h"
/**
* Class SkyManager: Maintain sky settings and textures, and render the sky.
*/
class SkyManager
{
public:
- bool m_RenderSky;
- float m_HorizonHeight;
-
-public:
SkyManager();
/**
- * RenderSky: Render the sky.
+ * Render the sky.
*/
void RenderSky();
/**
- * GetSkySet(): Return the currently selected sky set name.
+ * Return the currently selected sky set name.
*/
- inline const CStrW& GetSkySet() const {
+ inline const CStrW& GetSkySet() const
+ {
return m_SkySet;
}
- GLuint GetSkyCube() {
+ GLuint GetSkyCube()
+ {
return m_SkyCubeMap;
}
/**
- * GetSkySet(): Set the sky set name, potentially loading the textures.
+ * Set the sky set name, potentially loading the textures.
*/
void SetSkySet(const CStrW& name);
/**
* Return a sorted list of available sky sets, in a form suitable
* for passing to SetSkySet.
*/
std::vector GetSkySets() const;
+ bool GetRenderSky() const
+ {
+ return m_RenderSky;
+ }
+
+ void SetRenderSky(bool value)
+ {
+ m_RenderSky = value;
+ }
+
private:
void LoadSkyTextures();
+ bool m_RenderSky;
+ float m_HorizonHeight;
+
/// Name of current skyset (a directory within art/textures/skies)
CStrW m_SkySet;
// Indices into m_SkyTexture
enum
{
FRONT,
BACK,
RIGHT,
LEFT,
TOP,
- numTextures
+ NUMBER_OF_TEXTURES
};
// Sky textures
- CTexturePtr m_SkyTexture[numTextures];
+ CTexturePtr m_SkyTexture[NUMBER_OF_TEXTURES];
GLuint m_SkyCubeMap;
-
- // Array of image names (defined in SkyManager.cpp), in the order of the IMG_ id's
- static const wchar_t* s_imageNames[numTextures];
};
#endif // INCLUDED_SKYMANAGER
Index: ps/trunk/source/tools/atlas/GameInterface/ActorViewer.cpp
===================================================================
--- ps/trunk/source/tools/atlas/GameInterface/ActorViewer.cpp (revision 21951)
+++ ps/trunk/source/tools/atlas/GameInterface/ActorViewer.cpp (revision 21952)
@@ -1,557 +1,557 @@
/* Copyright (C) 2018 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 .
*/
#include "precompiled.h"
#include "ActorViewer.h"
#include "View.h"
#include "graphics/ColladaManager.h"
#include "graphics/LOSTexture.h"
#include "graphics/Unit.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "graphics/ObjectManager.h"
#include "graphics/ParticleManager.h"
#include "graphics/Patch.h"
#include "graphics/SkeletonAnimManager.h"
#include "graphics/Terrain.h"
#include "graphics/TerrainTextureEntry.h"
#include "graphics/TerrainTextureManager.h"
#include "graphics/TerritoryTexture.h"
#include "graphics/UnitManager.h"
#include "graphics/Overlay.h"
#include "maths/MathUtil.h"
#include "ps/Filesystem.h"
#include "ps/CLogger.h"
#include "ps/GameSetup/Config.h"
#include "ps/ProfileViewer.h"
#include "renderer/Renderer.h"
#include "renderer/Scene.h"
#include "renderer/SkyManager.h"
#include "renderer/WaterManager.h"
#include "scriptinterface/ScriptInterface.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpRangeManager.h"
#include "simulation2/components/ICmpTerrain.h"
#include "simulation2/components/ICmpUnitMotion.h"
#include "simulation2/components/ICmpVisual.h"
#include "simulation2/components/ICmpWaterManager.h"
#include "simulation2/helpers/Render.h"
struct ActorViewerImpl : public Scene
{
NONCOPYABLE(ActorViewerImpl);
public:
ActorViewerImpl() :
Entity(INVALID_ENTITY),
Terrain(),
ColladaManager(g_VFS),
MeshManager(ColladaManager),
SkeletonAnimManager(ColladaManager),
UnitManager(),
Simulation2(&UnitManager, g_ScriptRuntime, &Terrain),
ObjectManager(MeshManager, SkeletonAnimManager, Simulation2),
LOSTexture(Simulation2),
TerritoryTexture(Simulation2)
{
UnitManager.SetObjectManager(ObjectManager);
}
entity_id_t Entity;
CStrW CurrentUnitID;
CStrW CurrentUnitAnim;
float CurrentSpeed;
bool WalkEnabled;
bool GroundEnabled;
bool WaterEnabled;
bool ShadowsEnabled;
// Whether shadows, sky and water are enabled outside of the actor viewer.
bool OldShadows;
bool OldSky;
bool OldWater;
bool SelectionBoxEnabled;
bool AxesMarkerEnabled;
int PropPointsMode; // 0 disabled, 1 for point markers, 2 for point markers + axes
SColor4ub Background;
CTerrain Terrain;
CColladaManager ColladaManager;
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
CUnitManager UnitManager;
CSimulation2 Simulation2;
CLOSTexture LOSTexture;
CTerritoryTexture TerritoryTexture;
SOverlayLine SelectionBoxOverlay;
SOverlayLine AxesMarkerOverlays[3];
std::vector Props;
std::vector PropPointOverlays;
// Simplistic implementation of the Scene interface
virtual void EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
{
if (GroundEnabled)
{
for (ssize_t pj = 0; pj < Terrain.GetPatchesPerSide(); ++pj)
for (ssize_t pi = 0; pi < Terrain.GetPatchesPerSide(); ++pi)
c->Submit(Terrain.GetPatch(pi, pj));
}
CmpPtr cmpVisual(Simulation2, Entity);
if (cmpVisual)
{
// add selection box outlines manually
if (SelectionBoxEnabled)
{
SelectionBoxOverlay.m_Color = CColor(35/255.f, 86/255.f, 188/255.f, .75f); // pretty blue
SelectionBoxOverlay.m_Thickness = 2;
SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), SelectionBoxOverlay);
c->Submit(&SelectionBoxOverlay);
}
// add origin axis thingy
if (AxesMarkerEnabled)
{
CMatrix3D worldSpaceAxes;
// offset from the ground a little bit to prevent fighting with the floor texture (also note: SetTranslation
// sets the identity 3x3 transformation matrix, which are the world axes)
worldSpaceAxes.SetTranslation(cmpVisual->GetPosition() + CVector3D(0, 0.02f, 0));
SimRender::ConstructAxesMarker(worldSpaceAxes, AxesMarkerOverlays[0], AxesMarkerOverlays[1], AxesMarkerOverlays[2]);
c->Submit(&AxesMarkerOverlays[0]);
c->Submit(&AxesMarkerOverlays[1]);
c->Submit(&AxesMarkerOverlays[2]);
}
// add prop point overlays
if (PropPointsMode > 0 && Props.size() > 0)
{
PropPointOverlays.clear(); // doesn't clear capacity, but should be ok since the number of prop points is usually pretty limited
for (size_t i = 0; i < Props.size(); ++i)
{
CModel::Prop& prop = Props[i];
if (prop.m_Model) // should always be the case
{
// prop point positions are automatically updated during animations etc. by CModel::ValidatePosition
const CMatrix3D& propCoordSystem = prop.m_Model->GetTransform();
SOverlayLine pointGimbal;
pointGimbal.m_Color = CColor(1.f, 0.f, 1.f, 1.f);
SimRender::ConstructGimbal(propCoordSystem.GetTranslation(), 0.05f, pointGimbal);
PropPointOverlays.push_back(pointGimbal);
if (PropPointsMode > 1)
{
// scale the prop axes coord system down a bit to distinguish them from the main world-space axes markers
CMatrix3D displayCoordSystem = propCoordSystem;
displayCoordSystem.Scale(0.5f, 0.5f, 0.5f);
// revert translation scaling
displayCoordSystem._14 = propCoordSystem._14;
displayCoordSystem._24 = propCoordSystem._24;
displayCoordSystem._34 = propCoordSystem._34;
// construct an XYZ axes marker for the prop's coordinate system
SOverlayLine xAxis, yAxis, zAxis;
SimRender::ConstructAxesMarker(displayCoordSystem, xAxis, yAxis, zAxis);
PropPointOverlays.push_back(xAxis);
PropPointOverlays.push_back(yAxis);
PropPointOverlays.push_back(zAxis);
}
}
}
for (size_t i = 0; i < PropPointOverlays.size(); ++i)
{
c->Submit(&PropPointOverlays[i]);
}
}
}
// send a RenderSubmit message so the components can submit their visuals to the renderer
Simulation2.RenderSubmit(*c, frustum, false);
}
virtual CLOSTexture& GetLOSTexture()
{
return LOSTexture;
}
virtual CTerritoryTexture& GetTerritoryTexture()
{
return TerritoryTexture;
}
/**
* Recursively fetches the props of the currently displayed entity model and its submodels, and stores them for rendering.
*/
void UpdatePropList();
void UpdatePropListRecursive(CModelAbstract* model);
};
void ActorViewerImpl::UpdatePropList()
{
Props.clear();
CmpPtr cmpVisual(Simulation2, Entity);
if (cmpVisual)
{
CUnit* unit = cmpVisual->GetUnit();
if (unit)
{
CModelAbstract& modelAbstract = unit->GetModel();
UpdatePropListRecursive(&modelAbstract);
}
}
}
void ActorViewerImpl::UpdatePropListRecursive(CModelAbstract* modelAbstract)
{
ENSURE(modelAbstract);
CModel* model = modelAbstract->ToCModel();
if (model)
{
std::vector& modelProps = model->GetProps();
for (CModel::Prop& modelProp : modelProps)
{
Props.push_back(modelProp);
if (modelProp.m_Model)
UpdatePropListRecursive(modelProp.m_Model);
}
}
}
ActorViewer::ActorViewer()
: m(*new ActorViewerImpl())
{
m.WalkEnabled = false;
m.GroundEnabled = true;
m.WaterEnabled = false;
m.ShadowsEnabled = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
m.SelectionBoxEnabled = false;
m.AxesMarkerEnabled = false;
m.PropPointsMode = 0;
m.Background = SColor4ub(0, 0, 0, 255);
// Create a tiny empty piece of terrain, just so we can put shadows
// on it without having to think too hard
m.Terrain.Initialize(2, NULL);
CTerrainTextureEntry* tex = g_TexMan.FindTexture("whiteness");
if (tex)
{
for (ssize_t pi = 0; pi < m.Terrain.GetPatchesPerSide(); ++pi)
{
for (ssize_t pj = 0; pj < m.Terrain.GetPatchesPerSide(); ++pj)
{
CPatch* patch = m.Terrain.GetPatch(pi, pj);
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.Tex = tex;
mp.Priority = 0;
}
}
}
}
}
else
{
debug_warn(L"Failed to load whiteness texture");
}
// Prepare the simulation
m.Simulation2.LoadDefaultScripts();
m.Simulation2.ResetState();
// Set player data
m.Simulation2.SetMapSettings(m.Simulation2.GetPlayerDefaults());
m.Simulation2.LoadPlayerSettings(true);
// Tell the simulation we've already loaded the terrain
CmpPtr cmpTerrain(m.Simulation2, SYSTEM_ENTITY);
if (cmpTerrain)
cmpTerrain->ReloadTerrain(false);
// Remove FOW since we're in Atlas
CmpPtr cmpRangeManager(m.Simulation2, SYSTEM_ENTITY);
if (cmpRangeManager)
cmpRangeManager->SetLosRevealAll(-1, true);
m.Simulation2.InitGame();
}
ActorViewer::~ActorViewer()
{
delete &m;
}
CSimulation2* ActorViewer::GetSimulation2()
{
return &m.Simulation2;
}
entity_id_t ActorViewer::GetEntity()
{
return m.Entity;
}
void ActorViewer::UnloadObjects()
{
m.ObjectManager.UnloadObjects();
}
void ActorViewer::SetActor(const CStrW& name, const CStrW& animation, player_id_t playerID)
{
bool needsAnimReload = false;
CStrW id = name;
// Recreate the entity, if we don't have one or if the new one is different
if (m.Entity == INVALID_ENTITY || id != m.CurrentUnitID)
{
// Delete the old entity (if any)
if (m.Entity != INVALID_ENTITY)
{
m.Simulation2.DestroyEntity(m.Entity);
m.Simulation2.FlushDestroyedEntities();
m.Entity = INVALID_ENTITY;
}
// Clear particles associated with deleted entity
g_Renderer.GetParticleManager().ClearUnattachedEmitters();
// If there's no actor to display, return with nothing loaded
if (id.empty())
return;
m.Entity = m.Simulation2.AddEntity(L"preview|" + id);
if (m.Entity == INVALID_ENTITY)
return;
CmpPtr cmpPosition(m.Simulation2, m.Entity);
if (cmpPosition)
{
ssize_t c = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
cmpPosition->JumpTo(entity_pos_t::FromInt(c), entity_pos_t::FromInt(c));
cmpPosition->SetYRotation(entity_angle_t::Pi());
}
CmpPtr cmpOwnership(m.Simulation2, m.Entity);
if (cmpOwnership)
cmpOwnership->SetOwner(playerID);
needsAnimReload = true;
}
if (animation != m.CurrentUnitAnim)
needsAnimReload = true;
if (needsAnimReload)
{
CStr anim = animation.ToUTF8().LowerCase();
// Emulate the typical simulation animation behaviour
float speed;
float repeattime = 0.f;
if (anim == "walk")
{
CmpPtr cmpUnitMotion(m.Simulation2, m.Entity);
if (cmpUnitMotion)
speed = cmpUnitMotion->GetWalkSpeed().ToFloat();
else
speed = 7.f; // typical unit speed
m.CurrentSpeed = speed;
}
else if (anim == "run")
{
CmpPtr cmpUnitMotion(m.Simulation2, m.Entity);
if (cmpUnitMotion)
speed = cmpUnitMotion->GetRunSpeed().ToFloat();
else
speed = 12.f; // typical unit speed
m.CurrentSpeed = speed;
}
else if (anim == "melee")
{
speed = 1.f; // speed will be ignored if we have a repeattime
m.CurrentSpeed = 0.f;
CStr code = "var cmp = Engine.QueryInterface("+CStr::FromUInt(m.Entity)+", IID_Attack); " +
"if (cmp) cmp.GetTimers(cmp.GetBestAttack()).repeat; else 0;";
m.Simulation2.GetScriptInterface().Eval(code.c_str(), repeattime);
}
else
{
// Play the animation at normal speed, but movement speed is zero
speed = 1.f;
m.CurrentSpeed = 0.f;
}
CStr sound;
if (anim == "melee")
sound = "attack";
else if (anim == "build")
sound = "build";
else if (anim.Find("gather_") == 0)
sound = anim;
CmpPtr cmpVisual(m.Simulation2, m.Entity);
if (cmpVisual)
{
// TODO: SetEntitySelection(anim)
cmpVisual->SelectAnimation(anim, false, fixed::FromFloat(speed));
if (repeattime)
cmpVisual->SetAnimationSyncRepeat(fixed::FromFloat(repeattime));
}
// update prop list for new entity/animation (relies on needsAnimReload also getting called for entire entity changes)
m.UpdatePropList();
}
m.CurrentUnitID = id;
m.CurrentUnitAnim = animation;
}
void ActorViewer::SetEnabled(bool enabled)
{
if (enabled)
{
// Set shadows, sky and water.
m.OldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);
- m.OldSky = g_Renderer.GetSkyManager()->m_RenderSky;
- g_Renderer.GetSkyManager()->m_RenderSky = false;
+ m.OldSky = g_Renderer.GetSkyManager()->GetRenderSky();
+ g_Renderer.GetSkyManager()->SetRenderSky(false);
m.OldWater = g_Renderer.GetWaterManager()->m_RenderWater;
g_Renderer.GetWaterManager()->m_RenderWater = m.WaterEnabled;
}
else
{
// Restore the old renderer state
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.OldShadows);
- g_Renderer.GetSkyManager()->m_RenderSky = m.OldSky;
+ g_Renderer.GetSkyManager()->SetRenderSky(m.OldSky);
g_Renderer.GetWaterManager()->m_RenderWater = m.OldWater;
}
}
void ActorViewer::SetBackgroundColor(const SColor4ub& color)
{
m.Background = color;
m.Terrain.SetBaseColor(color);
}
void ActorViewer::SetWalkEnabled(bool enabled) { m.WalkEnabled = enabled; }
void ActorViewer::SetGroundEnabled(bool enabled) { m.GroundEnabled = enabled; }
void ActorViewer::SetWaterEnabled(bool enabled)
{
m.WaterEnabled = enabled;
// Adjust water level
entity_pos_t waterLevel = entity_pos_t::FromFloat(enabled ? 10.f : 0.f);
CmpPtr cmpWaterManager(m.Simulation2, SYSTEM_ENTITY);
if (cmpWaterManager)
cmpWaterManager->SetWaterLevel(waterLevel);
}
void ActorViewer::SetShadowsEnabled(bool enabled) { m.ShadowsEnabled = enabled; }
void ActorViewer::SetBoundingBoxesEnabled(bool enabled) { m.SelectionBoxEnabled = enabled; }
void ActorViewer::SetAxesMarkerEnabled(bool enabled) { m.AxesMarkerEnabled = enabled; }
void ActorViewer::SetPropPointsMode(int mode) { m.PropPointsMode = mode; }
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);
// Set simulation context for rendering purposes
g_Renderer.SetSimulation(&m.Simulation2);
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;
CmpPtr cmpVisual(m.Simulation2, m.Entity);
if (cmpVisual)
cmpVisual->GetBounds().GetCentre(centre);
else
centre.Y = 0.f;
centre.X = centre.Z = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
CCamera camera = AtlasView::GetView_Actor()->GetCamera();
camera.m_Orientation.Translate(centre.X, centre.Y, centre.Z);
camera.UpdateFrustum();
g_Renderer.SetSceneCamera(camera, camera);
g_Renderer.RenderScene(m);
glDisable(GL_DEPTH_TEST);
g_Logger->Render();
g_ProfileViewer.RenderProfile();
glEnable(GL_DEPTH_TEST);
g_Renderer.EndFrame();
ogl_WarnIfError();
}
void ActorViewer::Update(float simFrameLength, float realFrameLength)
{
m.Simulation2.Update((int)(simFrameLength*1000));
m.Simulation2.Interpolate(simFrameLength, 0, realFrameLength);
if (m.WalkEnabled && m.CurrentSpeed)
{
CmpPtr cmpPosition(m.Simulation2, m.Entity);
if (cmpPosition)
{
// Move the model by speed*simFrameLength forwards
float z = cmpPosition->GetPosition().Z.ToFloat();
z -= m.CurrentSpeed*simFrameLength;
// Wrap at the edges, so it doesn't run off into the horizon
ssize_t c = TERRAIN_TILE_SIZE * m.Terrain.GetPatchesPerSide()*PATCH_SIZE/2;
if (z < c - TERRAIN_TILE_SIZE*PATCH_SIZE * 0.1f)
z = c + TERRAIN_TILE_SIZE*PATCH_SIZE * 0.1f;
cmpPosition->JumpTo(cmpPosition->GetPosition().X, entity_pos_t::FromFloat(z));
}
}
}