diff --git a/binaries/data/tools/atlas/lists.xml b/binaries/data/tools/atlas/lists.xml index 4905257901..0c42b4bc3f 100644 --- a/binaries/data/tools/atlas/lists.xml +++ b/binaries/data/tools/atlas/lists.xml @@ -25,21 +25,20 @@ - Attack - AttackA - AttackB - AttackC - Death - DeathA - DeathB - Idle - IdleA - IdleB - IdleC - Run - Special - Walk - Pack + + attack1 + attack2 + build + corpse + death + gather_fruit + gather_grain + gather_stone + gather_wood + idle + melee + run + walk diff --git a/binaries/system/ActorViewer.bat b/binaries/system/ActorViewer.bat new file mode 100644 index 0000000000..c27706d79c --- /dev/null +++ b/binaries/system/ActorViewer.bat @@ -0,0 +1 @@ +pyrogenesis.exe -editor -actorviewer \ No newline at end of file diff --git a/build/premake/premake.lua b/build/premake/premake.lua index 0f3a997cbb..ec4a748e65 100755 --- a/build/premake/premake.lua +++ b/build/premake/premake.lua @@ -484,9 +484,11 @@ function setup_atlas_packages() setup_atlas_package("AtlasUI", "dll", { -- src "ActorEditor", + "ActorViewer", "ArchiveViewer", "ColourTester", "CustomControls/Buttons", + "CustomControls/Canvas", "CustomControls/ColourDialog", "CustomControls/DraggableListCtrl", "CustomControls/EditableListCtrl", diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index e82ccb21cd..92e6321feb 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -303,32 +303,6 @@ void CGameView::SubmitModelRecursive(CModel* model) } } -void CGameView::RenderNoCull() -{ - CUnitManager *pUnitMan=m_pWorld->GetUnitManager(); - CTerrain *pTerrain=m_pWorld->GetTerrain(); - - if (m_LockCullCamera == false) - m_CullCamera = m_ViewCamera; - g_Renderer.SetCamera(m_ViewCamera, m_CullCamera); - - CheckLightEnv(); - - uint i,j; - const std::vector& units=pUnitMan->GetUnits(); - for (i=0;iGetModel()); - } - - u32 patchesPerSide=pTerrain->GetPatchesPerSide(); - for (j=0; jGetPatch(i,j); - g_Renderer.Submit(patch); - } - } -} - static void MarkUpdateColorRecursive(CModel* model) { model->SetDirty(RENDERDATA_UPDATE_COLOR); diff --git a/source/graphics/GameView.h b/source/graphics/GameView.h index f45d3a0dcd..36b04c87f8 100644 --- a/source/graphics/GameView.h +++ b/source/graphics/GameView.h @@ -141,10 +141,6 @@ public: void CameraLock(CVector3D Trans, bool smooth=true); void CameraLock(float x, float y, float z, bool smooth=true); - // RenderNoCull: render absolutely everything to a blank frame to force - // renderer to load required assets - void RenderNoCull(); - // Camera Control Functions (used by input handler) void ResetCamera(); void ResetCameraOrientation(); diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index 7a7eec5eb0..457487db01 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -1,31 +1,31 @@ #include "precompiled.h" #include "MapReader.h" -#include "lib/types.h" -#include "UnitManager.h" -#include "Unit.h" -#include "ps/Game.h" -#include "ObjectManager.h" -#include "simulation/Entity.h" -#include "simulation/EntityTemplate.h" -#include "simulation/EntityTemplateCollection.h" -#include "simulation/EntityManager.h" -#include "ps/CLogger.h" -#include "maths/MathUtil.h" -#include "Camera.h" -#include "graphics/Patch.h" + +#include "graphics/Camera.h" #include "graphics/GameView.h" -#include "renderer/WaterManager.h" -#include "renderer/SkyManager.h" - -#include "Model.h" -#include "Terrain.h" -#include "TextureManager.h" -#include "TextureEntry.h" - +#include "graphics/Model.h" +#include "graphics/ObjectManager.h" +#include "graphics/Patch.h" +#include "graphics/Terrain.h" +#include "graphics/TextureEntry.h" +#include "graphics/TextureManager.h" +#include "graphics/Unit.h" +#include "graphics/UnitManager.h" #include "lib/timer.h" +#include "lib/types.h" +#include "maths/MathUtil.h" +#include "ps/CLogger.h" +#include "ps/Game.h" #include "ps/Loader.h" #include "ps/LoaderThunks.h" +#include "ps/xml/Xeromyces.h" +#include "renderer/SkyManager.h" +#include "renderer/WaterManager.h" +#include "simulation/Entity.h" +#include "simulation/EntityManager.h" +#include "simulation/EntityTemplate.h" +#include "simulation/EntityTemplateCollection.h" #define LOG_CATEGORY "graphics" diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp index e2ca946e9e..317948acab 100644 --- a/source/graphics/MapWriter.cpp +++ b/source/graphics/MapWriter.cpp @@ -237,7 +237,7 @@ void CMapWriter::WriteXML(const char* filename, CVector3D in = pCamera->m_Orientation.GetIn(); // Convert to spherical coordinates float rotation = atan2(in.X, in.Z); - float declination = atan2(sqrt(in.X*in.X + in.Z*in.Z), in.Y) - M_PI_2; + float declination = atan2(sqrt(in.X*in.X + in.Z*in.Z), in.Y) - PI/2; { XML_Element("Rotation"); diff --git a/source/graphics/ObjectManager.cpp b/source/graphics/ObjectManager.cpp index d49f895833..0f82132aaf 100644 --- a/source/graphics/ObjectManager.cpp +++ b/source/graphics/ObjectManager.cpp @@ -29,7 +29,7 @@ bool operator< (const CObjectManager::ObjectKey& a, const CObjectManager::Object return a.ActorVariation < b.ActorVariation; } -CObjectManager::CObjectManager() : m_SelectedThing(NULL) +CObjectManager::CObjectManager() { m_ObjectTypes.reserve(32); } @@ -158,6 +158,10 @@ void CObjectManager::DeleteObject(CObjectEntry* entry) int CObjectManager::LoadObjects() { + // This is kind of useless - it should probably be removed, + // and UnloadObject moved into the destructor, and singletonness + // removed if we still want to unload the object manager and reuse it + // again later. AddObjectType(""); return 0; } @@ -177,9 +181,6 @@ void CObjectManager::UnloadObjects() ); } m_ObjectTypes.clear(); - - delete m_SelectedThing; - m_SelectedThing = NULL; } diff --git a/source/graphics/ObjectManager.h b/source/graphics/ObjectManager.h index d3121b2079..f7f01693e3 100644 --- a/source/graphics/ObjectManager.h +++ b/source/graphics/ObjectManager.h @@ -14,16 +14,6 @@ class CMatrix3D; // access to sole CObjectManager object #define g_ObjMan CObjectManager::GetSingleton() -// Slight hack, to allow ScEd to place either entities or objects -class CObjectThing -{ -public: - virtual ~CObjectThing() {} - virtual void Create(CMatrix3D& transform, int playerID)=0; - virtual void SetTransform(CMatrix3D& transform)=0; - virtual CObjectEntry* GetObjectEntry()=0; -}; - /////////////////////////////////////////////////////////////////////////////////////////// // CObjectManager: manager class for all possible actor types class CObjectManager : public Singleton @@ -51,7 +41,6 @@ public: }; public: - CObjectThing* m_SelectedThing; // constructor, destructor CObjectManager(); @@ -68,8 +57,8 @@ public: CObjectBase* FindObjectBase(const char* objname); - CObjectEntry* FindObjectVariation(const char* objname, const std::vector >& selections); - CObjectEntry* FindObjectVariation(CObjectBase* base, const std::vector >& selections); + CObjectEntry* FindObjectVariation(const char* objname, const std::vector >& selections); + CObjectEntry* FindObjectVariation(CObjectBase* base, const std::vector >& selections); // Get all names, quite slowly. (Intended only for ScEd.) void GetAllObjectNames(std::vector& names); diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index 1286d524d7..52f88e33da 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -7,18 +7,37 @@ #include "SkeletonAnim.h" #include "SkeletonAnimDef.h" -CUnit::CUnit(CObjectEntry* object, CEntity* entity, const std::set& actorSelections) +CUnit::CUnit(CObjectEntry* object, CEntity* entity, const std::set& actorSelections) : m_Object(object), m_Model(object->m_Model->Clone()), m_Entity(entity), m_ID(-1), m_ActorSelections(actorSelections) { } - CUnit::~CUnit() { delete m_Model; } +CUnit* CUnit::Create(const CStr& actorName, CEntity* entity, const std::set& selections) +{ + CObjectBase* base = g_ObjMan.FindObjectBase(actorName); + + if (! base) + return NULL; + + std::set actorSelections = base->CalculateRandomVariation(selections); + + std::vector > selectionsVec; + selectionsVec.push_back(actorSelections); + + CObjectEntry* obj = g_ObjMan.FindObjectVariation(base, selectionsVec); + + if (! obj) + return NULL; + + return new CUnit(obj, entity, actorSelections); +} + void CUnit::ShowAmmunition() { if (!m_Object->m_AmmunitionModel || !m_Object->m_AmmunitionPoint) @@ -115,9 +134,9 @@ void CUnit::SetPlayerID(int id) m_Model->SetPlayerID(m_PlayerID); } -void CUnit::SetEntitySelection(const CStrW& selection) +void CUnit::SetEntitySelection(const CStr& selection) { - CStrW selection_lc = selection.LowerCase(); + CStr selection_lc = selection.LowerCase(); // If we've already selected this, don't do anything if (m_EntitySelections.find(selection_lc) != m_EntitySelections.end()) @@ -130,7 +149,7 @@ void CUnit::SetEntitySelection(const CStrW& selection) ReloadObject(); } -void CUnit::SetActorSelections(const std::set& selections) +void CUnit::SetActorSelections(const std::set& selections) { m_ActorSelections = selections; ReloadObject(); @@ -138,7 +157,7 @@ void CUnit::SetActorSelections(const std::set& selections) void CUnit::ReloadObject() { - std::vector > selections; + std::vector > selections; // TODO: push world selections (seasons, etc) (and reload whenever they're changed) selections.push_back(m_EntitySelections); selections.push_back(m_ActorSelections); diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index a6be5fb065..97ecf4d2eb 100644 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -3,24 +3,31 @@ #include +#include "ps/CStr.h" + class CModel; class CObjectEntry; class CEntity; class CSkeletonAnim; -class CStr8; class CStrW; ///////////////////////////////////////////////////////////////////////////////////////////// // CUnit: simple "actor" definition - defines a sole object within the world class CUnit { +private: + // Private constructor. Needs complete list of selections for the variation. + CUnit(CObjectEntry* object, CEntity* entity, const std::set& actorSelections); + public: - CUnit(CObjectEntry* object, CEntity* entity, const std::set& actorSelections); + // Attempt to create a unit with the given actor, attached to an entity + // (or NULL), with a set of suggested selections (with the rest being randomised). + // Returns NULL on failure. + static CUnit* Create(const CStr& actorName, CEntity* entity, const std::set& selections); // destructor ~CUnit(); - // get unit's template object; never NULL CObjectEntry* GetObject() { return m_Object; } // get unit's model data; never NULL @@ -34,19 +41,20 @@ public: // Sets the animation a random one matching 'name'. If none is found, // sets to idle instead. Applies recursively to props. - bool SetRandomAnimation(const CStr8& name, bool once = false, float speed = 0.0f); + // SetEntitySelection(name) should typically be used before this. + bool SetRandomAnimation(const CStr& name, bool once = false, float speed = 0.0f); // Returns a random animation matching 'name'. If none is found, // returns idle instead. - CSkeletonAnim* GetRandomAnimation(const CStr8& name); + CSkeletonAnim* GetRandomAnimation(const CStr& name); // Sets the entity-selection, and updates the unit to use the new // actor variation. - void SetEntitySelection(const CStrW& selection); + void SetEntitySelection(const CStr& selection); // Returns whether the currently active animation is one of the ones // matching 'name'. - bool IsPlayingAnimation(const CStr8& name); + bool IsPlayingAnimation(const CStr& name); // Set player ID of this unit void SetPlayerID(int id); @@ -57,9 +65,9 @@ public: int GetID() const { return m_ID; } void SetID(int id) { m_ID = id; } - const std::set& GetActorSelections() const { return m_ActorSelections; } + const std::set& GetActorSelections() const { return m_ActorSelections; } - void SetActorSelections(const std::set& selections); + void SetActorSelections(const std::set& selections); private: // object from which unit was created @@ -76,9 +84,9 @@ private: int m_ID; // actor-level selections for this unit - std::set m_ActorSelections; + std::set m_ActorSelections; // entity-level selections for this unit - std::set m_EntitySelections; + std::set m_EntitySelections; void ReloadObject(); }; diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index 26305c4144..97217cbf89 100644 --- a/source/graphics/UnitManager.cpp +++ b/source/graphics/UnitManager.cpp @@ -19,7 +19,6 @@ #include "ObjectEntry.h" #include "simulation/Entity.h" #include "simulation/LOSManager.h" -#include "simulation/TerritoryManager.h" extern CConsole* g_Console; @@ -127,23 +126,9 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) con // CreateUnit: create a new unit and add it to the world CUnit* CUnitManager::CreateUnit(const CStr& actorName, CEntity* entity, const std::set& selections) { - CObjectBase* base = g_ObjMan.FindObjectBase(actorName); - - if (! base) - return NULL; - - std::set actorSelections = base->CalculateRandomVariation(selections); - - std::vector > selectionsVec; - selectionsVec.push_back(actorSelections); - - CObjectEntry* obj = g_ObjMan.FindObjectVariation(base, selectionsVec); - - if (! obj) - return NULL; - - CUnit* unit = new CUnit(obj, entity, actorSelections); - AddUnit(unit); + CUnit* unit = CUnit::Create(actorName, entity, selections); + if (unit) + AddUnit(unit); return unit; } diff --git a/source/graphics/UnitManager.h b/source/graphics/UnitManager.h index c110e47cb2..bd10bb042b 100644 --- a/source/graphics/UnitManager.h +++ b/source/graphics/UnitManager.h @@ -41,7 +41,7 @@ public: void DeleteAll(); // creates a new unit and adds it to the world - CUnit* CreateUnit(const CStr& actorName, CEntity* entity, const std::set& selections); + CUnit* CreateUnit(const CStr& actorName, CEntity* entity, const std::set& selections); // return the units const std::vector& GetUnits() const { return m_Units; } diff --git a/source/lib/app_hooks.cpp b/source/lib/app_hooks.cpp index f22e88291f..33aeed64d9 100644 --- a/source/lib/app_hooks.cpp +++ b/source/lib/app_hooks.cpp @@ -157,7 +157,6 @@ static AppHooks ah = void app_hooks_update(AppHooks* ah_) { debug_assert(ah_); - ONCE_NOT(debug_warn("app hooks already set")); // override members in if they are non-zero in // (otherwise, we stick with the defaults set above) diff --git a/source/lib/res/sound/snd_mgr.cpp b/source/lib/res/sound/snd_mgr.cpp index 6f6b4ea19c..80855497f5 100644 --- a/source/lib/res/sound/snd_mgr.cpp +++ b/source/lib/res/sound/snd_mgr.cpp @@ -1394,7 +1394,7 @@ static float fade_factor_exponential(float t) static float fade_factor_s_curve(float t) { // cosine curve - float y = cos(t*M_PI + M_PI); + float y = cos(t*PI + PI); // map [-1,1] to [0,1] return (y + 1.0f) / 2.0f; } diff --git a/source/lib/sysdep/win/win.cpp b/source/lib/sysdep/win/win.cpp index 5ca0b43e2b..bad4b423e9 100644 --- a/source/lib/sysdep/win/win.cpp +++ b/source/lib/sysdep/win/win.cpp @@ -327,7 +327,7 @@ static inline void pre_libc_init() static int SEH_wrapped_entry() { int ret; - //__try + __try { pre_libc_init(); #ifdef USE_WINMAIN @@ -336,7 +336,7 @@ static int SEH_wrapped_entry() ret = mainCRTStartup(); // calls _cinit and then our main #endif } - //__except(wdbg_exception_filter(GetExceptionInformation())) + __except(wdbg_exception_filter(GetExceptionInformation())) { ret = -1; } diff --git a/source/main.cpp b/source/main.cpp index 3ab8ee6d2e..5bbde1f62a 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -357,6 +357,9 @@ void kill_mainloop() int main(int argc, char* argv[]) { + // If you ever want to catch a particular allocation: + //_CrtSetBreakAlloc(7864); + // see discussion at declaration of win_pre_main_init. #if OS_WIN win_pre_main_init(); diff --git a/source/maths/MathUtil.h b/source/maths/MathUtil.h index 09253be38b..21927d3465 100644 --- a/source/maths/MathUtil.h +++ b/source/maths/MathUtil.h @@ -5,42 +5,32 @@ #define PI 3.14159265358979323846f #endif -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 -#endif - #define DEGTORAD(a) ((a) * (PI/180.0f)) #define RADTODEG(a) ((a) * (180.0f/PI)) #define SQR(x) ((x) * (x)) -#define MAX3(a,b,c) ( MAX (MAX(a,b), c) ) -#define ABS(a) ((a > 0) ? (a) : (-a)) template -T Interpolate( T& a, T& b, float l ) +T Interpolate(T& a, T& b, float l) { - return( a + ( b - a ) * l ); + return a + (b - a) * l; } template inline T clamp(T value, T min, T max) { - if (value<=min) return min; - else if (value>=max) return max; + if (value <= min) return min; + else if (value >= max) return max; else return value; } static inline int RoundUpToPowerOf2(int x) { - if ((x & (x-1))==0) return x; - int d=x; - while (d & (d-1)) { - d&=(d-1); - } - return d<<1; + if ((x & (x-1)) == 0) + return x; + int d = x; + while (d & (d-1)) + d &= (d-1); + return d << 1; } inline float sgn(float a) diff --git a/source/maths/Noise.cpp b/source/maths/Noise.cpp index b1675db998..22e563f298 100644 --- a/source/maths/Noise.cpp +++ b/source/maths/Noise.cpp @@ -31,7 +31,7 @@ Noise2D::Noise2D(int f) grads[i] = new CVector2D_Maths[freq]; for(int j=0; jGetView()->RenderNoCull(); - - g_Renderer.FlushFrame(); - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - g_Renderer.EndFrame(); -} - - void Render() { MICROLOG(L"begin frame"); @@ -389,12 +378,6 @@ void Render() g_Game->GetView()->GetCinema()->DrawAllSplines(); PROFILE_END( "render cinematic splines" ); } - else - { - PROFILE_START( "flush frame" ); - g_Renderer.FlushFrame(); - PROFILE_END( "flush frame" ); - } oglCheck(); @@ -898,9 +881,6 @@ void Init(int argc, char* argv[], uint flags) // add all debug_printf "tags" that we are interested in: debug_filter_add("TIMER"); - // If you ever want to catch a particular allocation: - //_CrtSetBreakAlloc(187); - // Query CPU capabilities, possibly set some CPU-dependent flags cpu_init(); @@ -1004,7 +984,13 @@ void Init(int argc, char* argv[], uint flags) } // (must come after SetVideoMode, since it calls oglInit) - const char* missing = oglHaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", "GL_ARB_texture_env_combine", "GL_ARB_texture_env_dot3", "GL_ARB_texture_env_crossbar", 0); + const char* missing = oglHaveExtensions(0, + "GL_ARB_multitexture", + "GL_EXT_draw_range_elements", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_dot3", + "GL_ARB_texture_env_crossbar", + 0); if(missing) { wchar_t buf[500]; @@ -1065,7 +1051,7 @@ void Init(int argc, char* argv[], uint flags) // Check for heap corruption after every allocation. Very, very slowly. // (And it highlights the allocation just after the one you care about, // so you need to run it again and tell it to break on the one before.) - //debug_heap_enable(DEBUG_HEAP_ALL); +// debug_heap_enable(DEBUG_HEAP_ALL); InitInput(); @@ -1079,27 +1065,20 @@ void Init(int argc, char* argv[], uint flags) } #endif - { - TIMER("Init_renderblank"); - MICROLOG(L"render blank"); - // render everything to a blank frame to force renderer to load everything - RenderNoCull(); - } - if (g_FixedFrameTiming) { - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); + CCamera &camera = *g_Game->GetView()->GetCamera(); #if 0 // TOPDOWN - g_Camera.SetProjection(1.0f,10000.0f,DEGTORAD(90)); - g_Camera.m_Orientation.SetIdentity(); - g_Camera.m_Orientation.RotateX(DEGTORAD(90)); - g_Camera.m_Orientation.Translate(CELL_SIZE*250*0.5, 250, CELL_SIZE*250*0.5); + camera.SetProjection(1.0f,10000.0f,DEGTORAD(90)); + camera.m_Orientation.SetIdentity(); + camera.m_Orientation.RotateX(DEGTORAD(90)); + camera.m_Orientation.Translate(CELL_SIZE*250*0.5, 250, CELL_SIZE*250*0.5); #else // std view - g_Camera.SetProjection(1.0f,10000.0f,DEGTORAD(20)); - g_Camera.m_Orientation.SetXRotation(DEGTORAD(30)); - g_Camera.m_Orientation.RotateY(DEGTORAD(-45)); - g_Camera.m_Orientation.Translate(350, 350, -275); + camera.SetProjection(1.0f,10000.0f,DEGTORAD(20)); + camera.m_Orientation.SetXRotation(DEGTORAD(30)); + camera.m_Orientation.RotateY(DEGTORAD(-45)); + camera.m_Orientation.Translate(350, 350, -275); #endif - g_Camera.UpdateFrustum(); + camera.UpdateFrustum(); } if (g_AutostartMap.Length()) diff --git a/source/ps/GameSetup/GameSetup.h b/source/ps/GameSetup/GameSetup.h index 2b8902efc2..321a18226e 100644 --- a/source/ps/GameSetup/GameSetup.h +++ b/source/ps/GameSetup/GameSetup.h @@ -15,6 +15,7 @@ extern void GUI_DisplayLoadProgress(int percent, const wchar_t* pending_task); extern void Render(); +extern void RenderActor(); extern void Shutdown(); diff --git a/source/ps/Interact.cpp b/source/ps/Interact.cpp index 3c8a7ae5bf..227916ed3b 100644 --- a/source/ps/Interact.cpp +++ b/source/ps/Interact.cpp @@ -2,9 +2,6 @@ #include "Interact.h" -#include "ps/CConsole.h" -#include "ps/Game.h" -#include "ps/Hotkey.h" #include "graphics/GameView.h" #include "graphics/HFTracer.h" #include "graphics/Model.h" @@ -18,22 +15,27 @@ #include "lib/res/graphics/unifont.h" #include "lib/timer.h" #include "maths/MathUtil.h" -#include "ps/Globals.h" #include "network/NetMessage.h" +#include "ps/CConsole.h" +#include "ps/Game.h" +#include "ps/Globals.h" +#include "ps/Hotkey.h" #include "ps/Player.h" #include "ps/VFSUtil.h" #include "ps/World.h" #include "renderer/Renderer.h" #include "scripting/GameEvents.h" -#include "simulation/EntityTemplateCollection.h" #include "simulation/BoundingObjects.h" #include "simulation/Collision.h" #include "simulation/Entity.h" #include "simulation/EntityFormation.h" #include "simulation/EntityManager.h" +#include "simulation/EntityTemplate.h" +#include "simulation/EntityTemplateCollection.h" +#include "simulation/EventHandlers.h" #include "simulation/FormationManager.h" -#include "simulation/TerritoryManager.h" #include "simulation/Simulation.h" +#include "simulation/TerritoryManager.h" #include "ps/CLogger.h" #define LOG_CATEGORY "world" @@ -1294,7 +1296,7 @@ InReaction interactInputHandler( const SDL_Event_* ev ) { int deltax = ev->ev.motion.x - button_down_x; int deltay = ev->ev.motion.y - button_down_y; - if( ABS( deltax ) > 2 || ABS( deltay ) > 2 ) + if( abs( deltax ) > 2 || abs( deltay ) > 2 ) g_Mouseover.startBandbox( button_down_x, button_down_y ); } break; @@ -1384,9 +1386,9 @@ bool CBuildingPlacer::activate(CStrW& templateName) void CBuildingPlacer::mousePressed() { - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); + CCamera &camera=*g_Game->GetView()->GetCamera(); if( m_template->m_socket == L"" ) - clickPos = g_Camera.GetWorldCoordinates(); + clickPos = camera.GetWorldCoordinates(); m_clicked = true; } @@ -1430,8 +1432,8 @@ void CBuildingPlacer::update( float timeStep ) { // Rotate object m_timeSinceClick += timeStep; - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); - CVector3D mousePos = g_Camera.GetWorldCoordinates(); + CCamera &camera = *g_Game->GetView()->GetCamera(); + CVector3D mousePos = camera.GetWorldCoordinates(); CVector3D dif = mousePos - clickPos; float x = dif.X, z = dif.Z; if(x*x + z*z < 3*3) { @@ -1454,8 +1456,8 @@ void CBuildingPlacer::update( float timeStep ) } else { - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); - pos = g_Camera.GetWorldCoordinates(); + CCamera &camera = *g_Game->GetView()->GetCamera(); + pos = camera.GetWorldCoordinates(); } bool onSocket = false; diff --git a/source/ps/KeyName.cpp b/source/ps/KeyName.cpp index cb4b1a3e64..37e80886e2 100644 --- a/source/ps/KeyName.cpp +++ b/source/ps/KeyName.cpp @@ -288,7 +288,6 @@ void initKeyNameMap() SKeycodeMapping* it = keycodeMapping; while( it->keycode != 0 ) { - debug_printf("adding key %s\n", it->keyname); keymap.insert( std::pair( CStr( it->keyname ).LowerCase(), it->keycode ) ); if( it->altkeyname ) keymap.insert( std::pair( CStr( it->altkeyname ).LowerCase(), it->keycode ) ); diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index d43a094032..7f50becadb 100644 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -412,38 +412,54 @@ void CPatchRData::Update() CTerrain* terrain=m_Patch->m_Parent; int mapSize=terrain->GetVerticesPerSide(); - CLOSManager* losMgr = g_Game->GetWorld()->GetLOSManager(); int vsize=PATCH_SIZE+1; - // this is very similar to BuildVertices(), but just for color - for (int j=0;jGetWorld()->GetLOSManager(); - const int DX[] = {1,1,0,0}; - const int DZ[] = {0,1,1,0}; - SColor4ub losMod(255, 255, 255, 255); + // this is very similar to BuildVertices(), but just for color + for (int j=0;j= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2) + for(int k=0; k<4; k++) { - ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer()); - if(s==LOS_EXPLORED && losMod.R > 178) - losMod = SColor4ub(178, 178, 178, 255); - else if(s==LOS_UNEXPLORED && losMod.R > 0) - losMod = SColor4ub(0, 0, 0, 255); - } - } + int tx = ix - DX[k]; + int tz = iz - DZ[k]; - m_Vertices[v].m_LOSColor = losMod; + if(tx >= 0 && tz >= 0 && tx <= mapSize-2 && tz <= mapSize-2) + { + ELOSStatus s = losMgr->GetStatus(tx, tz, g_Game->GetLocalPlayer()); + if(s==LOS_EXPLORED && losMod.R > 178) + losMod = SColor4ub(178, 178, 178, 255); + else if(s==LOS_UNEXPLORED && losMod.R > 0) + losMod = SColor4ub(0, 0, 0, 255); + } + } + + m_Vertices[v].m_LOSColor = losMod; + } } } + else + { + for (int j = 0; j < vsize; ++j) + { + for (int i = 0; i < vsize; ++i) + { + int v = (j*vsize)+i; + m_Vertices[v].m_LOSColor = SColor4ub(255, 255, 255, 255); + } + } + + } // upload base vertices into their vertex buffer m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase,m_Vertices); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index a5ae646b95..776e4eaa22 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -705,9 +705,6 @@ void CRenderer::SetFastPlayerColor(bool fast) // BeginFrame: signal frame start void CRenderer::BeginFrame() { - if(!g_Game || !g_Game->IsGameStarted()) - return; - // bump frame counter m_FrameCounter++; @@ -1158,9 +1155,6 @@ void CRenderer::RenderRefractions() // FlushFrame: force rendering of any batched objects void CRenderer::FlushFrame() { - if(!g_Game || !g_Game->IsGameStarted()) - return; - oglCheck(); // Prepare model renderers @@ -1178,7 +1172,8 @@ void CRenderer::FlushFrame() m->terrainRenderer->PrepareForRendering(); PROFILE_END("prepare terrain"); - if (m_Options.m_Shadows) { + if (m_Options.m_Shadows) + { MICROLOG(L"render shadows"); RenderShadowMap(); } @@ -1189,7 +1184,7 @@ void CRenderer::FlushFrame() oglCheck(); - if(m_WaterManager->m_RenderWater && m_Options.m_FancyWater) + if (m_WaterManager->m_RenderWater && m_Options.m_FancyWater) { // render reflected and refracted scenes, then re-clear the screen RenderReflections(); @@ -1227,7 +1222,7 @@ void CRenderer::FlushFrame() oglCheck(); // render water - if (m_WaterManager->m_RenderWater) + if (m_WaterManager->m_RenderWater && g_Game) { MICROLOG(L"render water"); m->terrainRenderer->RenderWater(); @@ -1247,7 +1242,6 @@ void CRenderer::FlushFrame() // on all the time, so it might not be worth worrying about. } - // Clean up texture blend mode so particles and other things render OK // (really this should be cleaned up by whoever set it) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); @@ -1284,9 +1278,6 @@ void CRenderer::FlushFrame() // EndFrame: signal frame end void CRenderer::EndFrame() { - if(!g_Game || !g_Game->IsGameStarted()) - return; - g_Renderer.SetTexture(0,0); static bool once=false; diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index 84971fe562..4ca3fc8205 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -205,7 +205,7 @@ void SkyManager::RenderSky() // 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( 90.0f + g_Renderer.GetLightEnv().GetRotation()*180.0f/M_PI, 0.0f, 1.0f, 0.0f ); + glRotatef( 90.0f + RADTODEG(g_Renderer.GetLightEnv().GetRotation()), 0.0f, 1.0f, 0.0f ); // Distance to draw the faces at const float D = 2000.0; diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 80f83aa5fb..97b663c68e 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -132,7 +132,7 @@ void TerrainRenderer::EndFrame() // Query if patches have been submitted this frame bool TerrainRenderer::HaveSubmissions() { - return m->visiblePatches.size() > 0; + return !m->visiblePatches.empty(); } @@ -332,10 +332,10 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow) glMatrixMode(GL_MODELVIEW); // restore OpenGL state - if ( shadow ) + if (shadow) { - if ( shadow->GetUseDepthTexture() ) - g_Renderer.BindTexture(2,0); + if (shadow->GetUseDepthTexture()) + g_Renderer.BindTexture(2,0); } g_Renderer.BindTexture(1,0); diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index a6d5d36e45..d19ce15279 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -40,6 +40,7 @@ #include "simulation/EntityFormation.h" #include "simulation/EntityHandles.h" #include "simulation/EntityManager.h" +#include "simulation/EntityTemplate.h" #include "simulation/FormationManager.h" #include "simulation/LOSManager.h" #include "simulation/Scheduler.h" diff --git a/source/scripting/ScriptableComplex.h b/source/scripting/ScriptableComplex.h index c966048636..2f7e6ba758 100644 --- a/source/scripting/ScriptableComplex.h +++ b/source/scripting/ScriptableComplex.h @@ -14,15 +14,15 @@ before, 30+ files had to be recompiled because they #included Entity.h which #includes ScriptableComplex.h. */ +#ifndef SCRIPTABLE_COMPLEX_INCLUDED +#define SCRIPTABLE_COMPLEX_INCLUDED + #include "scripting/ScriptingHost.h" #include "simulation/ScriptObject.h" #include "JSConversions.h" #include -#ifndef SCRIPTABLE_COMPLEX_INCLUDED -#define SCRIPTABLE_COMPLEX_INCLUDED - class IJSComplex; class IJSComplexProperty @@ -285,5 +285,3 @@ extern void* jscomplexproperty_suballoc(); extern void jscomplexproperty_suballoc_free(IJSComplexProperty* p); #endif - - diff --git a/source/scripting/ScriptableComplex.inl b/source/scripting/ScriptableComplex.inl index 73a0d8efea..191600b06e 100644 --- a/source/scripting/ScriptableComplex.inl +++ b/source/scripting/ScriptableComplex.inl @@ -52,6 +52,7 @@ linker won't find the definitions of these functions. Right now this is only #ifndef SCRIPTABLE_COMPLEX_INL_INCLUDED #define SCRIPTABLE_COMPLEX_INL_INCLUDED +#include "ScriptableComplex.h" //----------------------------------------------------------------------------- // CJSComplexPropertyAccessor diff --git a/source/simulation/Collision.cpp b/source/simulation/Collision.cpp index fe7bf25453..520780bb91 100644 --- a/source/simulation/Collision.cpp +++ b/source/simulation/Collision.cpp @@ -3,6 +3,7 @@ #include "Collision.h" #include "Entity.h" #include "EntityManager.h" +#include "EntityTemplate.h" #include diff --git a/source/simulation/Entity.cpp b/source/simulation/Entity.cpp index 26f87e2a51..9c9d2f1b5a 100644 --- a/source/simulation/Entity.cpp +++ b/source/simulation/Entity.cpp @@ -1,36 +1,36 @@ -// Last modified: May 15 2004, Mark Thompson (mark@wildfiregames.com) - #include "precompiled.h" -#include "ps/Profile.h" - -#include "Entity.h" -#include "EntityManager.h" -#include "EntityTemplateCollection.h" -#include "graphics/Unit.h" -#include "Aura.h" -#include "ProductionQueue.h" -#include "renderer/Renderer.h" -#include "graphics/Model.h" -#include "graphics/Terrain.h" -#include "ps/Interact.h" -#include "Collision.h" -#include "PathfindEngine.h" -#include "ps/Game.h" -#include "maths/scripting/JSInterface_Vector3D.h" -#include "maths/MathUtil.h" -#include "ps/CConsole.h" -#include "renderer/WaterManager.h" -#include "EntityFormation.h" -#include "FormationManager.h" -#include "TerritoryManager.h" -#include "Formation.h" -#include "TechnologyCollection.h" #include "graphics/GameView.h" +#include "graphics/Model.h" #include "graphics/Sprite.h" +#include "graphics/Terrain.h" +#include "graphics/Unit.h" #include "graphics/UnitManager.h" +#include "maths/MathUtil.h" +#include "maths/scripting/JSInterface_Vector3D.h" +#include "ps/CConsole.h" +#include "ps/Game.h" +#include "ps/Interact.h" +#include "ps/Profile.h" +#include "renderer/Renderer.h" +#include "renderer/WaterManager.h" #include "scripting/ScriptableComplex.inl" +#include "Aura.h" +#include "Collision.h" +#include "Entity.h" +#include "EntityFormation.h" +#include "EntityManager.h" +#include "EntityTemplate.h" +#include "EntityTemplateCollection.h" +#include "EventHandlers.h" +#include "Formation.h" +#include "FormationManager.h" +#include "PathfindEngine.h" +#include "ProductionQueue.h" +#include "TechnologyCollection.h" +#include "TerritoryManager.h" + extern CConsole* g_Console; extern int g_xres, g_yres; @@ -467,7 +467,7 @@ void CEntity::update( size_t timestep ) { if( ( m_lastState != -1 ) || !m_actor->GetModel()->GetAnimation() ) { - m_actor->SetEntitySelection( L"idle" ); + m_actor->SetEntitySelection( "idle" ); m_actor->SetRandomAnimation( "idle" ); } } @@ -1167,14 +1167,14 @@ void CEntity::renderAuras() CVector2D CEntity::getScreenCoords( float height ) { - CCamera &g_Camera=*g_Game->GetView()->GetCamera(); + CCamera &camera = *g_Game->GetView()->GetCamera(); float sx, sy; CVector3D above; above.X = m_position.X; above.Z = m_position.Z; above.Y = getAnchorLevel(m_position.X, m_position.Z) + height; - g_Camera.GetScreenCoordinates(above, sx, sy); + camera.GetScreenCoordinates(above, sx, sy); return CVector2D( sx, sy ); } @@ -1399,14 +1399,14 @@ void CEntity::renderRank() if( g_Selection.m_unitUITextures.find( m_rankName ) == g_Selection.m_unitUITextures.end() ) return; - CCamera *g_Camera=g_Game->GetView()->GetCamera(); + CCamera *camera = g_Game->GetView()->GetCamera(); float sx, sy; CVector3D above; above.X = m_position.X; above.Z = m_position.Z; above.Y = getAnchorLevel(m_position.X, m_position.Z) + m_base->m_rankHeight; - g_Camera->GetScreenCoordinates(above, sx, sy); + camera->GetScreenCoordinates(above, sx, sy); int size = m_base->m_rankWidth/2; float x1 = sx + m_base->m_healthBarSize/2; @@ -1853,7 +1853,7 @@ bool CEntity::Kill( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(arg if( m_actor ) { - m_actor->SetEntitySelection( L"death" ); + m_actor->SetEntitySelection( "death" ); m_actor->SetRandomAnimation( "death", true ); } diff --git a/source/simulation/Entity.h b/source/simulation/Entity.h index d3bf44ca5f..988457ed2a 100644 --- a/source/simulation/Entity.h +++ b/source/simulation/Entity.h @@ -38,13 +38,8 @@ #include "scripting/DOMEvent.h" #include "scripting/ScriptCustomTypes.h" -// JW: must be pulled in because CEntity no longer mirrors CEntityTemplate exactly. -// some fields have been moved out of CEntity and are accessed via m_base, -// so CEntityTemplate must be fully defined. -#include "EntityTemplate.h" - class CAura; -//class CEntityTemplate; // see comment above +class CEntityTemplate; class CBoundingObject; class CPlayer; class CProductionQueue; diff --git a/source/simulation/EntityManager.cpp b/source/simulation/EntityManager.cpp index 392d4b59af..022d833234 100644 --- a/source/simulation/EntityManager.cpp +++ b/source/simulation/EntityManager.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "EntityTemplateCollection.h" +#include "EntityTemplate.h" #include "ps/ConfigDB.h" #include "ps/Profile.h" #include "graphics/Terrain.h" diff --git a/source/simulation/EntityManager.h b/source/simulation/EntityManager.h index 09228e12c9..5210de459d 100644 --- a/source/simulation/EntityManager.h +++ b/source/simulation/EntityManager.h @@ -24,10 +24,11 @@ #include "EntityMessage.h" #include "ps/Game.h" #include "ps/World.h" -#include "ps/CStr.h" #include "maths/Vector3D.h" class CEntityTemplate; +class CPlayer; +class CStrW; #define MAX_HANDLES 4096 diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index b77aa871bb..67c81fa689 100644 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -4,6 +4,7 @@ #include "Entity.h" #include "EntityTemplate.h" +#include "EventHandlers.h" #include "graphics/Model.h" #include "graphics/ObjectEntry.h" #include "graphics/SkeletonAnim.h" @@ -406,7 +407,7 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times popOrder(); entf_clear(ENTF_IS_RUNNING); entf_clear(ENTF_SHOULD_RUN); - m_actor->SetEntitySelection( L"idle" ); + m_actor->SetEntitySelection( "idle" ); m_actor->SetRandomAnimation( "idle" ); return( false ); } diff --git a/source/simulation/EntitySupport.h b/source/simulation/EntitySupport.h index c7475f7e7c..064ffd0a6f 100644 --- a/source/simulation/EntitySupport.h +++ b/source/simulation/EntitySupport.h @@ -4,7 +4,6 @@ #define ENTITY_SUPPORT_INCLUDED #include "EntityHandles.h" -#include "ScriptObject.h" class CEntityManager; diff --git a/source/simulation/EntityTemplate.h b/source/simulation/EntityTemplate.h index b8250eda05..7287e9551e 100644 --- a/source/simulation/EntityTemplate.h +++ b/source/simulation/EntityTemplate.h @@ -21,13 +21,14 @@ #include "graphics/ObjectEntry.h" #include "scripting/ScriptableComplex.h" +#include "scripting/DOMEvent.h" #include "BoundingObjects.h" -#include "EventHandlers.h" #include "EntitySupport.h" #include "ScriptObject.h" -#include "ps/XML/Xeromyces.h" class CPlayer; +class CXeromyces; +class XMBElement; class CEntityTemplate : public CJSComplex, public IEventTarget { diff --git a/source/simulation/EntityTemplateCollection.cpp b/source/simulation/EntityTemplateCollection.cpp index ee2e78b1a0..e7e67f71b3 100644 --- a/source/simulation/EntityTemplateCollection.cpp +++ b/source/simulation/EntityTemplateCollection.cpp @@ -1,6 +1,7 @@ #include "precompiled.h" #include "EntityTemplateCollection.h" +#include "EntityTemplate.h" #include "graphics/ObjectManager.h" #include "graphics/Model.h" #include "ps/CLogger.h" diff --git a/source/simulation/EntityTemplateCollection.h b/source/simulation/EntityTemplateCollection.h index cc5afe496b..5d1f2ada40 100644 --- a/source/simulation/EntityTemplateCollection.h +++ b/source/simulation/EntityTemplateCollection.h @@ -20,16 +20,18 @@ #include #include "ps/CStr.h" #include "ps/Singleton.h" -#include "graphics/ObjectEntry.h" -#include "EntityTemplate.h" #include "ps/Game.h" #define g_EntityTemplateCollection CEntityTemplateCollection::GetSingleton() class CPlayer; +class CEntityTemplate; class CEntityTemplateCollection : public Singleton { + // TODO: PS_MAX_PLAYERS doesn't seem to be an upper limit - + // "This may be overridden by system.cfg ("max_players")" + // - so we shouldn't use it here static const uint NULL_PLAYER = (PS_MAX_PLAYERS+1); typedef STL_HASH_MAP TemplateMap; diff --git a/source/simulation/LOSManager.cpp b/source/simulation/LOSManager.cpp index c245447dd7..8bfc8e7f2d 100644 --- a/source/simulation/LOSManager.cpp +++ b/source/simulation/LOSManager.cpp @@ -7,6 +7,7 @@ #include "graphics/Terrain.h" #include "Entity.h" #include "EntityManager.h" +#include "EntityTemplate.h" #include "graphics/Unit.h" #include "maths/Bound.h" #include "graphics/Model.h" @@ -209,7 +210,16 @@ ELOSStatus CLOSManager::GetStatus(float fx, float fz, CPlayer* player) EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player) { - CVector3D centre = unit->GetModel()->GetTransform().GetTranslation(); + CVector3D centre; + + // For entities, we must use the simulation position so that we stay synchronised + // (because the output of this function will presumably affect AI) + CEntity* entity = unit->GetEntity(); + if (entity) + centre = entity->m_position; + else + centre = unit->GetModel()->GetTransform().GetTranslation(); + ELOSStatus status = GetStatus(centre.X, centre.Z, player); if(status & LOS_VISIBLE) @@ -217,7 +227,7 @@ EUnitLOSStatus CLOSManager::GetUnitStatus(CUnit* unit, CPlayer* player) if(status & LOS_EXPLORED) { - if(unit->GetEntity() == 0 || unit->GetEntity()->m_base->m_visionPermanent) + if(!entity || entity->m_base->m_visionPermanent) { // both actors (which are usually for decoration) and units with the // permanent flag should be remembered diff --git a/source/simulation/PathfindEngine.cpp b/source/simulation/PathfindEngine.cpp index beacf16169..cacf0f1ae0 100644 --- a/source/simulation/PathfindEngine.cpp +++ b/source/simulation/PathfindEngine.cpp @@ -4,6 +4,7 @@ #include "EntityOrders.h" #include "Entity.h" +#include "EntityTemplate.h" #include "PathfindEngine.h" diff --git a/source/simulation/TerritoryManager.cpp b/source/simulation/TerritoryManager.cpp index e06decffb5..69cafc8b8a 100644 --- a/source/simulation/TerritoryManager.cpp +++ b/source/simulation/TerritoryManager.cpp @@ -15,12 +15,12 @@ #include "lib/timer.h" #include "lib/ogl.h" #include "EntityManager.h" - -using namespace std; +#include "EntityTemplate.h" CTerritoryManager::CTerritoryManager() { m_TerritoryMatrix = 0; + m_DelayedRecalculate = false; } CTerritoryManager::~CTerritoryManager() @@ -129,6 +129,14 @@ void CTerritoryManager::Recalculate() } } +void CTerritoryManager::DelayedRecalculate() +{ + // This is useful particularly for Atlas, which wants to recalculate + // the boundaries as you move an object around but which doesn't want + // to waste time recalculating multiple times per frame + m_DelayedRecalculate = true; +} + CTerritory* CTerritoryManager::GetTerritory(int x, int z) { debug_assert( (uint) x < m_TilesPerSide && (uint) z < m_TilesPerSide ); @@ -208,7 +216,13 @@ void CTerritoryManager::CalculateBoundary( std::vector& centres, size_ } } void CTerritoryManager::renderTerritories() -{ +{ + if (m_DelayedRecalculate) + { + Recalculate(); + m_DelayedRecalculate = false; + } + const CTerrain* pTerrain = g_Game->GetWorld()->GetTerrain(); CFrustum frustum = g_Game->GetView()->GetCamera()->GetFrustum(); std::vector::iterator terr=m_Territories.begin(); @@ -218,6 +232,9 @@ void CTerritoryManager::renderTerritories() for ( ; terr != m_Territories.end(); ++terr ) { + if ((*terr)->boundary.empty()) + continue; + std::vector::iterator it=(*terr)->boundary.begin()+1; //const SPlayerColour& col = (*terr)->owner->GetColour(); //glColor3f(col.r, col.g, col.b); diff --git a/source/simulation/TerritoryManager.h b/source/simulation/TerritoryManager.h index c1d1a51d31..5f73dbfcc4 100644 --- a/source/simulation/TerritoryManager.h +++ b/source/simulation/TerritoryManager.h @@ -10,10 +10,6 @@ #ifndef TERRITORY_MANAGER_INCLUDED #define TERRITORY_MANAGER_INCLUDED -#include "ps/Singleton.h" -#include "ps/Game.h" -#include "ps/World.h" -#include "ps/Player.h" #include "ps/Vector2D.h" #include "EntityHandles.h" @@ -39,6 +35,7 @@ class CTerritoryManager CTerritory*** m_TerritoryMatrix; // m_TerritoryMatrix[x][z] points to the territory for tile (x, z) uint m_TilesPerSide; + bool m_DelayedRecalculate; public: CTerritoryManager(); @@ -46,6 +43,7 @@ public: void Initialize(); // initialize, called after the game is fully loaded void Recalculate(); // recalculate the territory boundaries + void DelayedRecalculate(); // recalculate the territory boundaries when next rendered void renderTerritories(); CTerritory* GetTerritory(int x, int z); // get the territory to which the given tile belongs CTerritory* GetTerritory(float x, float z); // get the territory to which the given world-space point belongs diff --git a/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp new file mode 100644 index 0000000000..09498de6ea --- /dev/null +++ b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp @@ -0,0 +1,299 @@ +#include "stdafx.h" + +#include "ActorViewer.h" + +#include "wx/treectrl.h" + +#include "General/Datafile.h" +#include "ScenarioEditor/Tools/Common/Tools.h" +#include "ScenarioEditor/ScenarioEditor.h" +#include "ScenarioEditor/Sections/Environment/LightControl.h" +#include "GameInterface/Messages.h" +#include "CustomControls/Canvas/Canvas.h" +#include "CustomControls/SnapSplitterWindow/SnapSplitterWindow.h" + +using namespace AtlasMessage; + +////////////////////////////////////////////////////////////////////////// + +class ActorCanvas : public Canvas +{ +public: + ActorCanvas(wxWindow* parent, int* attribList) + : Canvas(parent, attribList, wxBORDER_SUNKEN), + m_Distance(20.f), m_Angle(0.f), m_LastIsValid(false) + { + } + + void PostLookAt() + { + POST_MESSAGE(LookAt, (eRenderView::ACTOR, + Position(m_Distance*sin(m_Angle), m_Distance/2.f, m_Distance*cos(m_Angle)), + Position(0, 0, 0))); + } + +protected: + virtual void HandleMouseEvent(wxMouseEvent& evt) + { + bool camera_changed = false; + + if (evt.GetWheelRotation()) + { + float speed = -1.f * ScenarioEditor::GetSpeedModifier(); + + m_Distance += evt.GetWheelRotation() * speed / evt.GetWheelDelta(); + + camera_changed = true; + } + + if (evt.ButtonDown(wxMOUSE_BTN_LEFT)) + { + m_LastX = evt.GetX(); + m_LastY = evt.GetY(); + m_LastIsValid = true; + } + else if (evt.Dragging() && evt.ButtonIsDown(wxMOUSE_BTN_LEFT) && m_LastIsValid) + { + int dx = evt.GetX() - m_LastX; + int dy = evt.GetY() - m_LastY; + m_LastX = evt.GetX(); + m_LastY = evt.GetY(); + + m_Angle += dx * M_PI/256.f * ScenarioEditor::GetSpeedModifier(); + m_Distance += dy / 8.f * ScenarioEditor::GetSpeedModifier(); + camera_changed = true; + } + else if (evt.ButtonUp(wxMOUSE_BTN_ANY)) + { + // In some situations (e.g. double-clicking the title bar to + // maximise the window) we get a dragging event without the matching + // buttondown; so disallow dragging when there was a buttonup since + // the last buttondown. + // (TODO: does this affect the scenario editor too?) + m_LastIsValid = false; + } + + m_Distance = std::max(m_Distance, 1/64.f); // don't let people fly through the origin + + if (camera_changed) + PostLookAt(); + } + +private: + float m_Distance; + float m_Angle; + int m_LastX, m_LastY; + bool m_LastIsValid; +}; + +////////////////////////////////////////////////////////////////////////// + +class StringTreeItemData : public wxTreeItemData +{ +public: + StringTreeItemData(const wxString& string) : m_String(string) {} + wxString m_String; +}; + +enum +{ + ID_Actors, + ID_Animations, + ID_Play, + ID_Pause, + ID_Slow, +}; + +BEGIN_EVENT_TABLE(ActorViewer, wxFrame) + EVT_CLOSE(ActorViewer::OnClose) + EVT_TREE_SEL_CHANGED(ID_Actors, ActorViewer::OnTreeSelection) + EVT_COMBOBOX(ID_Animations, ActorViewer::OnAnimationSelection) + EVT_TEXT_ENTER(ID_Animations, ActorViewer::OnAnimationSelection) + EVT_BUTTON(ID_Play, ActorViewer::OnSpeedButton) + EVT_BUTTON(ID_Pause, ActorViewer::OnSpeedButton) + EVT_BUTTON(ID_Slow, ActorViewer::OnSpeedButton) +END_EVENT_TABLE() + +static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings) +{ + POST_COMMAND(SetEnvironmentSettings, (settings)); +} + +ActorViewer::ActorViewer(wxWindow* parent) + : wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)), + m_CurrentSpeed(0.f) +{ + SetIcon(wxIcon(_T("ICON_ActorEditor"))); + + SnapSplitterWindow* splitter = new SnapSplitterWindow(this, 0); + splitter->SetDefaultSashPosition(250); + + wxPanel* sidePanel = new wxPanel(splitter); + + // TODO: don't have this duplicated from ScenarioEditor.cpp + int glAttribList[] = { + WX_GL_RGBA, + WX_GL_DOUBLEBUFFER, + WX_GL_DEPTH_SIZE, 24, + WX_GL_BUFFER_SIZE, 24, + WX_GL_MIN_ALPHA, 8, + 0 + }; + + ActorCanvas* canvas = new ActorCanvas(splitter, glAttribList); + + splitter->SplitVertically(sidePanel, canvas); + + wglMakeCurrent(NULL, NULL); + POST_MESSAGE(SetContext, (canvas->GetContext())); + + POST_MESSAGE(Init, ()); + + canvas->InitSize(); + canvas->PostLookAt(); + + ////////////////////////////////////////////////////////////////////////// + + // Construct a tree containing all the available actors + + qGetObjectsList qry; + qry.Post(); + std::vector objects = *qry.objects; + + m_TreeCtrl = new wxTreeCtrl(sidePanel, ID_Actors); + wxTreeItemId root = m_TreeCtrl->AddRoot(_("Actors")); + + std::map treeEntries; + + wxRegEx stripDirs (_T("^([^/]+)/"), wxRE_ADVANCED); // the non-empty string up to the first slash + + for (std::vector::iterator it = objects.begin(); it != objects.end(); ++it) + { + if (it->type != 1) + continue; + + wxString name = it->name.c_str(); + // Loop through the directory components of the name, stripping them + // off and search down the tree hierarchy + wxString path = _T(""); + wxTreeItemId treeItem = root; + while (stripDirs.Matches(name)) + { + wxString dir = stripDirs.GetMatch(name, 1); + path += dir + _T("/"); + + // If we've got 'path' in the tree already, use it + std::map::iterator entry = treeEntries.find(path.c_str()); + if (entry != treeEntries.end()) + { + treeItem = entry->second; + } + else + { + // Add this new path into the tree + treeItem = m_TreeCtrl->AppendItem(treeItem, dir); + treeEntries.insert(std::make_pair(path, treeItem)); + } + + // Remove the leading directory name from the full filename + stripDirs.Replace(&name, _T("")); + } + + m_TreeCtrl->AppendItem(treeItem, name, -1, -1, new StringTreeItemData(it->name.c_str())); + } + + m_TreeCtrl->Expand(root); + + + wxArrayString animations; + + AtObj animationsList (Datafile::ReadList("animations")); + for (AtIter it = animationsList["item"]; it.defined(); ++it) + animations.Add(it); + + m_AnimationBox = new wxComboBox(sidePanel, ID_Animations, _T("Idle"), wxDefaultPosition, wxDefaultSize, animations); + + m_EnvironmentSettings.sunelevation = 45 * M_PI/180; + m_EnvironmentSettings.sunrotation = 315 * M_PI/180; + m_EnvironmentSettings.suncolour = Colour(255, 255, 255); + m_EnvironmentSettings.terraincolour = Colour(164, 164, 164); + m_EnvironmentSettings.unitcolour = Colour(164, 164, 164); + LightControl* lightControl = new LightControl(sidePanel, wxSize(100, 100), m_EnvironmentSettings); + m_Conn = m_EnvironmentSettings.RegisterObserver(0, &SendToGame); + SendToGame(m_EnvironmentSettings); + + wxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + wxSizer* bottomSizer = new wxBoxSizer(wxHORIZONTAL); + wxSizer* bottomRightSizer = new wxBoxSizer(wxVERTICAL); + wxSizer* playButtonSizer = new wxBoxSizer(wxHORIZONTAL); + + mainSizer->Add(m_TreeCtrl, wxSizerFlags().Expand().Proportion(1)); + mainSizer->Add(bottomSizer, wxSizerFlags().Expand()); + + bottomSizer->Add(lightControl, wxSizerFlags().Border(wxRIGHT, 5)); + bottomSizer->Add(bottomRightSizer, wxSizerFlags().Proportion(1)); + + playButtonSizer->Add(new wxButton(sidePanel, ID_Play, _("Play")), wxSizerFlags().Proportion(1)); + playButtonSizer->Add(new wxButton(sidePanel, ID_Pause, _("Pause")), wxSizerFlags().Proportion(1)); + playButtonSizer->Add(new wxButton(sidePanel, ID_Slow, _("Slow")), wxSizerFlags().Proportion(1)); + + bottomRightSizer->Add(m_AnimationBox, wxSizerFlags().Expand()); + bottomRightSizer->Add(playButtonSizer, wxSizerFlags().Expand()); + sidePanel->SetSizer(mainSizer); + + ////////////////////////////////////////////////////////////////////////// + + // Start by displaying the default non-existent actor + m_CurrentActor = _T("structures/fndn_1x1.xml"); + SetActorView(); + + POST_MESSAGE(RenderEnable, (eRenderView::ACTOR)); +} + +void ActorViewer::OnClose(wxCloseEvent& WXUNUSED(event)) +{ + POST_MESSAGE(Shutdown, ()); + + AtlasMessage::qExit().Post(); + // blocks until engine has noticed the message, so we won't be + // destroying the GLCanvas while it's still rendering + + Destroy(); +} + +void ActorViewer::SetActorView() +{ + POST_MESSAGE(SetActorViewer, (m_CurrentActor.c_str(), m_AnimationBox->GetValue().c_str(), m_CurrentSpeed)); +} + +void ActorViewer::OnTreeSelection(wxTreeEvent& event) +{ + wxTreeItemData* data = m_TreeCtrl->GetItemData(event.GetItem()); + if (! data) + return; + + m_CurrentActor = static_cast(data)->m_String; + SetActorView(); +} + +void ActorViewer::OnAnimationSelection(wxCommandEvent& WXUNUSED(event)) +{ + SetActorView(); +} + +void ActorViewer::OnSpeedButton(wxCommandEvent& event) +{ + if (event.GetId() == ID_Play) + m_CurrentSpeed = 1.f; + else if (event.GetId() == ID_Pause) + m_CurrentSpeed = 0.f; + else if (event.GetId() == ID_Slow) + m_CurrentSpeed = 0.1f; + else + { + wxLogDebug(_T("Invalid OnSpeedButton (%d)"), event.GetId()); + m_CurrentSpeed = 1.f; + } + + SetActorView(); +} \ No newline at end of file diff --git a/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.h b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.h new file mode 100644 index 0000000000..1a710bbf42 --- /dev/null +++ b/source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.h @@ -0,0 +1,29 @@ +#include "Windows/AtlasWindow.h" + +#include "GameInterface/Messages.h" +#include "General/Observable.h" + +class wxTreeCtrl; + +class ActorViewer : public wxFrame +{ +public: + ActorViewer(wxWindow* parent); + +private: + void SetActorView(); + void OnClose(wxCloseEvent& event); + void OnTreeSelection(wxTreeEvent& event); + void OnAnimationSelection(wxCommandEvent& event); + void OnSpeedButton(wxCommandEvent& event); + + wxTreeCtrl* m_TreeCtrl; + wxComboBox* m_AnimationBox; + wxString m_CurrentActor; + float m_CurrentSpeed; + + Observable m_EnvironmentSettings; + ObservableScopedConnection m_Conn; + + DECLARE_EVENT_TABLE(); +}; diff --git a/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.cpp b/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.cpp new file mode 100644 index 0000000000..5dd70f63d0 --- /dev/null +++ b/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.cpp @@ -0,0 +1,88 @@ +#include "stdafx.h" + +#include "Canvas.h" + +#include "GameInterface/Messages.h" +#include "ScenarioEditor/tools/Common/Tools.h" + +Canvas::Canvas(wxWindow* parent, int* attribList, long style) + : wxGLCanvas(parent, -1, wxDefaultPosition, wxDefaultSize, style, _T("GLCanvas"), attribList), + m_SuppressResize(true), + m_LastMousePos(-1, -1), m_MouseCaptured(false) +{ +} + +void Canvas::OnResize(wxSizeEvent&) +{ + // Be careful not to send 'resize' messages to the game before we've + // told it that this canvas exists + if (! m_SuppressResize) + POST_MESSAGE(ResizeScreen, (GetClientSize().GetWidth(), GetClientSize().GetHeight())); + // TODO: fix flashing +} + +void Canvas::InitSize() +{ + m_SuppressResize = false; + SetSize(320, 240); +} + + +void Canvas::OnMouseCapture(wxMouseCaptureChangedEvent& WXUNUSED(evt)) +{ + if (m_MouseCaptured) + { + // unexpected loss of capture (i.e. not through ReleaseMouse) + m_MouseCaptured = false; + + // (Note that this can be made to happen easily, by alt-tabbing away, + // and mouse events will be missed; so it is never guaranteed that e.g. + // two LeftDown events will be separated by a LeftUp.) + } +} + +void Canvas::OnMouse(wxMouseEvent& evt) +{ + // Capture on button-down, so we can respond even when the mouse + // moves off the window + if (!m_MouseCaptured && evt.ButtonDown()) + { + m_MouseCaptured = true; + CaptureMouse(); + } + // Un-capture when all buttons are up + else if (m_MouseCaptured && evt.ButtonUp() && + ! (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_MIDDLE) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT)) + ) + { + m_MouseCaptured = false; + ReleaseMouse(); + } + + // Set focus when clicking + if (evt.ButtonDown()) + SetFocus(); + + // Reject motion events if the mouse has not actually moved + if (evt.Moving() || evt.Dragging()) + { + if (m_LastMousePos == evt.GetPosition()) + return; + m_LastMousePos = evt.GetPosition(); + } + + HandleMouseEvent(evt); +} + +BEGIN_EVENT_TABLE(Canvas, wxGLCanvas) + EVT_SIZE(Canvas::OnResize) + EVT_LEFT_DOWN (Canvas::OnMouse) + EVT_LEFT_UP (Canvas::OnMouse) + EVT_RIGHT_DOWN (Canvas::OnMouse) + EVT_RIGHT_UP (Canvas::OnMouse) + EVT_MIDDLE_DOWN(Canvas::OnMouse) + EVT_MIDDLE_UP (Canvas::OnMouse) + EVT_MOUSEWHEEL (Canvas::OnMouse) + EVT_MOTION (Canvas::OnMouse) + EVT_MOUSE_CAPTURE_CHANGED(Canvas::OnMouseCapture) +END_EVENT_TABLE() diff --git a/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.h b/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.h new file mode 100644 index 0000000000..e98aa36feb --- /dev/null +++ b/source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.h @@ -0,0 +1,24 @@ +#include "wx/glcanvas.h" + +class Canvas : public wxGLCanvas +{ +public: + Canvas(wxWindow* parent, int* attribList, long style); + + void InitSize(); + +protected: + virtual void HandleMouseEvent(wxMouseEvent& evt) = 0; + +private: + void OnResize(wxSizeEvent&); + void OnMouseCapture(wxMouseCaptureChangedEvent& evt); + void OnMouse(wxMouseEvent& evt); + + bool m_SuppressResize; + + wxPoint m_LastMousePos; + bool m_MouseCaptured; + + DECLARE_EVENT_TABLE(); +}; diff --git a/source/tools/atlas/AtlasUI/General/AtlasEventLoop.cpp b/source/tools/atlas/AtlasUI/General/AtlasEventLoop.cpp index 8fed7731c1..2811b610f0 100644 --- a/source/tools/atlas/AtlasUI/General/AtlasEventLoop.cpp +++ b/source/tools/atlas/AtlasUI/General/AtlasEventLoop.cpp @@ -1,5 +1,8 @@ #include "stdafx.h" +/* Disabled (and should be removed if it turns out to be unnecessary) +- see MessagePasserImpl.cpp for information + #include "AtlasEventLoop.h" AtlasEventLoop::AtlasEventLoop() @@ -36,3 +39,4 @@ bool AtlasEventLoop::Dispatch() return wxEventLoop::Dispatch(); } +*/ \ No newline at end of file diff --git a/source/tools/atlas/AtlasUI/General/AtlasEventLoop.h b/source/tools/atlas/AtlasUI/General/AtlasEventLoop.h index 6750acdf77..f3b354981a 100644 --- a/source/tools/atlas/AtlasUI/General/AtlasEventLoop.h +++ b/source/tools/atlas/AtlasUI/General/AtlasEventLoop.h @@ -1,6 +1,9 @@ #ifndef ATLASEVENTLOOP_H__ #define ATLASEVENTLOOP_H__ +/* Disabled (and should be removed if it turns out to be unnecessary) +- see MessagePasserImpl.cpp for information + #include "wx/evtloop.h" struct tagMSG; @@ -21,4 +24,6 @@ public: virtual bool Dispatch(); }; +*/ + #endif // ATLASEVENTLOOP_H__ diff --git a/source/tools/atlas/AtlasUI/General/Observable.h b/source/tools/atlas/AtlasUI/General/Observable.h index 9c0bebdd3f..23f610c60a 100644 --- a/source/tools/atlas/AtlasUI/General/Observable.h +++ b/source/tools/atlas/AtlasUI/General/Observable.h @@ -5,6 +5,7 @@ #include typedef boost::signals::connection ObservableConnection; +typedef boost::signals::scoped_connection ObservableScopedConnection; template class Observable : public T { diff --git a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp index 5d069b2f0f..e269c17a48 100644 --- a/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp +++ b/source/tools/atlas/AtlasUI/Misc/DLLInterface.cpp @@ -5,11 +5,13 @@ #include "General/AtlasEventLoop.h" #include "General/Datafile.h" + #include "ActorEditor/ActorEditor.h" -#include "ColourTester/ColourTester.h" -#include "ScenarioEditor/ScenarioEditor.h" -#include "FileConverter/FileConverter.h" +#include "ActorViewer/ActorViewer.h" #include "ArchiveViewer/ArchiveViewer.h" +#include "ColourTester/ColourTester.h" +#include "FileConverter/FileConverter.h" +#include "ScenarioEditor/ScenarioEditor.h" #include "GameInterface/MessagePasser.h" @@ -26,7 +28,7 @@ ATLASDLLIMPEXP void* ShareableMalloc(size_t n) } ATLASDLLIMPEXP void ShareableFree(void* p) { - return free(p); + free(p); } // Define the function pointers that we'll use when calling those functions. // (The game loads the addresses of the above functions, then does the same.) @@ -72,16 +74,30 @@ ATLASDLLIMPEXP void Atlas_SetMessagePasser(MessagePasser* passer) g_MessagePasser = passer; } -ATLASDLLIMPEXP void Atlas_StartWindow(wchar_t* type) +ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type) { g_InitialWindowType = type; wxEntry(g_Module); } +ATLASDLLIMPEXP void Atlas_DisplayError(const wchar_t* text, unsigned int WXUNUSED(flags)) +{ + // This is called from the game thread. + // wxLog appears to be thread-safe, so that's okay. + wxLogError(L"%s", text); -class wxDLLApp : public wxApp + // TODO: wait for user response (if possible) before returning, + // and return their status (break/continue/debug/etc), but only in + // cases where we're certain it won't deadlock (i.e. the UI event loop + // is still running and won't block before showing the dialog to the user) + // and where it matters (i.e. errors, not warnings (unless they're going to + // turn into errors after continuing)) +} + +class AtlasDLLApp : public wxApp { public: + virtual bool OnInit() { if (! wxIsDebuggerRunning()) @@ -99,10 +115,11 @@ public: wxFrame* frame; #define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else MAYBE(ActorEditor) - MAYBE(ColourTester) - MAYBE(ScenarioEditor) - MAYBE(FileConverter) + MAYBE(ActorViewer) MAYBE(ArchiveViewer) + MAYBE(ColourTester) + MAYBE(FileConverter) + MAYBE(ScenarioEditor) #undef MAYBE // else { @@ -188,6 +205,8 @@ public: } } +/* Disabled (and should be removed if it turns out to be unnecessary) +- see MessagePasserImpl.cpp for information virtual int MainLoop() { // Override the default MainLoop so that we can provide our own event loop @@ -201,6 +220,8 @@ public: m_mainLoop = old; return ret; } +*/ + }; -IMPLEMENT_APP_NO_MAIN(wxDLLApp) +IMPLEMENT_APP_NO_MAIN(AtlasDLLApp) diff --git a/source/tools/atlas/AtlasUI/Misc/DLLInterface.h b/source/tools/atlas/AtlasUI/Misc/DLLInterface.h index 0aed96aea3..fd004c74bd 100644 --- a/source/tools/atlas/AtlasUI/Misc/DLLInterface.h +++ b/source/tools/atlas/AtlasUI/Misc/DLLInterface.h @@ -3,9 +3,11 @@ namespace AtlasMessage { class MessagePasser; } ATLASDLLIMPEXP void Atlas_SetMessagePasser(AtlasMessage::MessagePasser*); -ATLASDLLIMPEXP void Atlas_StartWindow(wchar_t* type); +ATLASDLLIMPEXP void Atlas_StartWindow(const wchar_t* type); ATLASDLLIMPEXP void Atlas_GLSetCurrent(void* context); ATLASDLLIMPEXP void Atlas_GLSwapBuffers(void* context); ATLASDLLIMPEXP void Atlas_NotifyEndOfFrame(); + +ATLASDLLIMPEXP void Atlas_DisplayError(const wchar_t* text, unsigned int flags); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp index ce26770109..6c47b97e06 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp @@ -2,7 +2,6 @@ #include "ScenarioEditor.h" -#include "wx/glcanvas.h" #include "wx/evtloop.h" #include "wx/tooltip.h" #include "wx/image.h" @@ -11,84 +10,74 @@ #include "General/AtlasEventLoop.h" #include "General/Datafile.h" -#include "SnapSplitterWindow/SnapSplitterWindow.h" #include "HighResTimer/HighResTimer.h" #include "Buttons/ToolButton.h" +#include "CustomControls/Canvas/Canvas.h" #include "GameInterface/MessagePasser.h" #include "GameInterface/Messages.h" #include "tools/Common/Tools.h" -// #define UI_ONLY - static HighResTimer g_Timer; +using namespace AtlasMessage; + ////////////////////////////////////////////////////////////////////////// -// TODO: move into another file -class Canvas : public wxGLCanvas +// GL functions exported from DLL, and called by game (in a separate +// thread to the standard wx one) +ATLASDLLIMPEXP void Atlas_GLSetCurrent(void* context) +{ + ((wxGLContext*)context)->SetCurrent(); +} + +ATLASDLLIMPEXP void Atlas_GLSwapBuffers(void* context) +{ + ((wxGLContext*)context)->SwapBuffers(); +} + + +////////////////////////////////////////////////////////////////////////// + +class GameCanvas : public Canvas { public: - Canvas(wxWindow* parent, int* attribList) - : wxGLCanvas(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS, _T("GLCanvas"), attribList), - m_SuppressResize(true), - m_MouseState(NONE), m_LastMouseState(NONE), m_MouseCaptured(false), - m_LastMousePos(-1, -1) + GameCanvas(wxWindow* parent, int* attribList) + : Canvas(parent, attribList, wxWANTS_CHARS), + m_MouseState(NONE), m_LastMouseState(NONE) { } - void OnResize(wxSizeEvent&) - { -#ifndef UI_ONLY - // Be careful not to send 'resize' messages to the game before we've - // told it that this canvas exists - if (! m_SuppressResize) - POST_MESSAGE(ResizeScreen, (GetClientSize().GetWidth(), GetClientSize().GetHeight())); - // TODO: fix flashing -#endif // UI_ONLY - } - - void InitSize() - { - m_SuppressResize = false; - SetSize(320, 240); - } +private: bool KeyScroll(wxKeyEvent& evt, bool enable) { -#ifndef UI_ONLY int dir; switch (evt.GetKeyCode()) { - case WXK_LEFT: dir = AtlasMessage::eScrollConstantDir::LEFT; break; - case WXK_RIGHT: dir = AtlasMessage::eScrollConstantDir::RIGHT; break; - case WXK_UP: dir = AtlasMessage::eScrollConstantDir::FORWARDS; break; - case WXK_DOWN: dir = AtlasMessage::eScrollConstantDir::BACKWARDS; break; + case WXK_LEFT: dir = eScrollConstantDir::LEFT; break; + case WXK_RIGHT: dir = eScrollConstantDir::RIGHT; break; + case WXK_UP: dir = eScrollConstantDir::FORWARDS; break; + case WXK_DOWN: dir = eScrollConstantDir::BACKWARDS; break; case WXK_SHIFT: case WXK_CONTROL: dir = -1; break; default: return false; } - float speed = 120.f; - if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL)) - speed /= 64.f; - else if (wxGetKeyState(WXK_CONTROL)) - speed /= 4.f; - else if (wxGetKeyState(WXK_SHIFT)) - speed *= 4.f; + float speed = 120.f * ScenarioEditor::GetSpeedModifier(); if (dir == -1) // changed modifier keys - update all currently-scrolling directions { - if (wxGetKeyState(WXK_LEFT)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::LEFT, speed)); - if (wxGetKeyState(WXK_RIGHT)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::RIGHT, speed)); - if (wxGetKeyState(WXK_UP)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::FORWARDS, speed)); - if (wxGetKeyState(WXK_DOWN)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::BACKWARDS, speed)); + if (wxGetKeyState(WXK_LEFT)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::LEFT, speed)); + if (wxGetKeyState(WXK_RIGHT)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::RIGHT, speed)); + if (wxGetKeyState(WXK_UP)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::FORWARDS, speed)); + if (wxGetKeyState(WXK_DOWN)) POST_MESSAGE(ScrollConstant, (eRenderView::GAME, eScrollConstantDir::BACKWARDS, speed)); } else { - POST_MESSAGE(ScrollConstant, (dir, enable ? speed : 0.0f)); + POST_MESSAGE(ScrollConstant, (eRenderView::GAME, dir, enable ? speed : 0.0f)); } -#endif // UI_ONLY + return true; } @@ -135,47 +124,14 @@ public: float speed = 16.f; if (wxGetKeyState(WXK_SHIFT)) speed *= 4.f; - POST_MESSAGE(SmoothZoom, (speed*dir)); + POST_MESSAGE(SmoothZoom, (eRenderView::GAME, speed*dir)); } else evt.Skip(); - } - void OnMouseCapture(wxMouseCaptureChangedEvent& WXUNUSED(evt)) + virtual void HandleMouseEvent(wxMouseEvent& evt) { - if (m_MouseCaptured) - { - // unexpected loss of capture (i.e. not through ReleaseMouse) - m_MouseCaptured = false; - - // (Note that this can be made to happen easily, by alt-tabbing away, - // and mouse events will be missed; so it is never guaranteed that e.g. - // two LeftDown events will be separated by a LeftUp.) - } - } - - void OnMouse(wxMouseEvent& evt) - { - // Capture on button-down, so we can respond even when the mouse - // moves off the window - if (!m_MouseCaptured && evt.ButtonDown()) - { - m_MouseCaptured = true; - CaptureMouse(); - } - // Un-capture when all buttons are up - else if (m_MouseCaptured && evt.ButtonUp() && - ! (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_MIDDLE) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT)) - ) - { - m_MouseCaptured = false; - ReleaseMouse(); - } - - // Set focus when clicking - if (evt.ButtonDown()) - SetFocus(); // TODO or at least to think about: When using other controls in the // editor, it's annoying that keyboard/scrollwheel no longer navigate @@ -188,16 +144,6 @@ public: if (evt.Moving()) SetFocus(); - // Reject motion events if the mouse has not actually moved - if (evt.Moving() || evt.Dragging()) - { - if (m_LastMousePos == evt.GetPosition()) - return; - m_LastMousePos = evt.GetPosition(); - } - -#ifndef UI_ONLY - if (GetCurrentTool().OnMouse(evt)) { // Mouse event has been handled by the tool, so don't try @@ -209,15 +155,8 @@ public: if (evt.GetWheelRotation()) { - float speed = 16.f; - if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL)) - speed /= 64.f; - else if (wxGetKeyState(WXK_CONTROL)) - speed /= 4.f; - else if (wxGetKeyState(WXK_SHIFT)) - speed *= 4.f; - - POST_MESSAGE(SmoothZoom, (evt.GetWheelRotation() * speed / evt.GetWheelDelta())); + float speed = 16.f * ScenarioEditor::GetSpeedModifier(); + POST_MESSAGE(SmoothZoom, (eRenderView::GAME, evt.GetWheelRotation() * speed / evt.GetWheelDelta())); } else { @@ -236,8 +175,8 @@ public: switch (m_MouseState) { case NONE: break; - case SCROLL: POST_MESSAGE(Scroll, (AtlasMessage::eScrollType::FROM, evt.GetPosition())); break; - case ROTATEAROUND: POST_MESSAGE(RotateAround, (AtlasMessage::eRotateAroundType::FROM, evt.GetPosition())); break; + case SCROLL: POST_MESSAGE(Scroll, (eRenderView::GAME, eScrollType::FROM, evt.GetPosition())); break; + case ROTATEAROUND: POST_MESSAGE(RotateAround, (eRenderView::GAME, eRotateAroundType::FROM, evt.GetPosition())); break; default: wxFAIL; } m_LastMouseState = m_MouseState; @@ -247,59 +186,28 @@ public: switch (m_MouseState) { case NONE: break; - case SCROLL: POST_MESSAGE(Scroll, (AtlasMessage::eScrollType::TO, evt.GetPosition())); break; - case ROTATEAROUND: POST_MESSAGE(RotateAround, (AtlasMessage::eRotateAroundType::TO, evt.GetPosition())); break; + case SCROLL: POST_MESSAGE(Scroll, (eRenderView::GAME, eScrollType::TO, evt.GetPosition())); break; + case ROTATEAROUND: POST_MESSAGE(RotateAround, (eRenderView::GAME, eRotateAroundType::TO, evt.GetPosition())); break; default: wxFAIL; } } } -#endif // UI_ONLY } -private: - bool m_SuppressResize; - enum { NONE, SCROLL, ROTATEAROUND }; int m_MouseState, m_LastMouseState; - bool m_MouseCaptured; - - wxPoint m_LastMousePos; DECLARE_EVENT_TABLE(); }; -BEGIN_EVENT_TABLE(Canvas, wxGLCanvas) - EVT_SIZE (Canvas::OnResize) - EVT_KEY_DOWN (Canvas::OnKeyDown) - EVT_KEY_UP (Canvas::OnKeyUp) - EVT_CHAR (Canvas::OnChar) - - EVT_LEFT_DOWN (Canvas::OnMouse) - EVT_LEFT_UP (Canvas::OnMouse) - EVT_RIGHT_DOWN (Canvas::OnMouse) - EVT_RIGHT_UP (Canvas::OnMouse) - EVT_MIDDLE_DOWN(Canvas::OnMouse) - EVT_MIDDLE_UP (Canvas::OnMouse) - EVT_MOUSEWHEEL (Canvas::OnMouse) - EVT_MOTION (Canvas::OnMouse) - EVT_MOUSE_CAPTURE_CHANGED(Canvas::OnMouseCapture) + +BEGIN_EVENT_TABLE(GameCanvas, Canvas) + EVT_KEY_DOWN(GameCanvas::OnKeyDown) + EVT_KEY_UP(GameCanvas::OnKeyUp) + EVT_CHAR(GameCanvas::OnChar) END_EVENT_TABLE() -// GL functions exported from DLL, and called by game (in a separate -// thread to the standard wx one) -ATLASDLLIMPEXP void Atlas_GLSetCurrent(void* context) -{ - ((wxGLContext*)context)->SetCurrent(); -} - -ATLASDLLIMPEXP void Atlas_GLSwapBuffers(void* context) -{ - ((wxGLContext*)context)->SwapBuffers(); -} - - ////////////////////////////////////////////////////////////////////////// - volatile bool g_FrameHasEnded; // Called from game thread ATLASDLLIMPEXP void Atlas_NotifyEndOfFrame() @@ -434,7 +342,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) WX_GL_MIN_ALPHA, 8, // alpha bits 0 }; - Canvas* canvas = new Canvas(m_SectionLayout.GetCanvasParent(), glAttribList); + Canvas* canvas = new GameCanvas(m_SectionLayout.GetCanvasParent(), glAttribList); m_SectionLayout.SetCanvas(canvas); // The canvas' context gets made current on creation; but it can only be // current for one thread at a time, and it needs to be current for the @@ -447,7 +355,6 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) // Send setup messages to game engine: -#ifndef UI_ONLY POST_MESSAGE(SetContext, (canvas->GetContext())); POST_MESSAGE(Init, ()); @@ -458,8 +365,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) // a valid map loaded) POST_MESSAGE(GenerateMap, (9)); - POST_MESSAGE(RenderEnable, (true)); -#endif + POST_MESSAGE(RenderEnable, (eRenderView::GAME)); // Set up a timer to make sure tool-updates happen frequently (in addition // to the idle handler (which makes them happen more frequently if there's nothing @@ -468,16 +374,26 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) m_Timer.Start(20); } +float ScenarioEditor::GetSpeedModifier() +{ + if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL)) + return 1.f/64.f; + else if (wxGetKeyState(WXK_CONTROL)) + return 1.f/4.f; + else if (wxGetKeyState(WXK_SHIFT)) + return 4.f; + else + return 1.f; +} + void ScenarioEditor::OnClose(wxCloseEvent&) { SetCurrentTool(_T("")); -#ifndef UI_ONLY POST_MESSAGE(Shutdown, ()); -#endif - AtlasMessage::qExit().Post(); + qExit().Post(); // blocks until engine has noticed the message, so we won't be // destroying the GLCanvas while it's still rendering @@ -553,7 +469,7 @@ void ScenarioEditor::OnOpen(wxCommandEvent& WXUNUSED(event)) SetOpenFilename(dlg.GetFilename()); // Wait for it to load, while the wxBusyInfo is telling the user that we're doing that - AtlasMessage::qPing qry; + qPing qry; qry.Post(); } @@ -576,7 +492,7 @@ void ScenarioEditor::OnSave(wxCommandEvent& event) POST_MESSAGE(SaveMap, (map)); // Wait for it to finish saving - AtlasMessage::qPing qry; + qPing qry; qry.Post(); } } @@ -599,7 +515,7 @@ void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event)) SetOpenFilename(dlg.GetFilename()); // Wait for it to finish saving - AtlasMessage::qPing qry; + qPing qry; qry.Post(); } } @@ -631,7 +547,7 @@ void ScenarioEditor::OnScreenshot(wxCommandEvent& WXUNUSED(event)) ////////////////////////////////////////////////////////////////////////// -AtlasMessage::Position::Position(const wxPoint& pt) +Position::Position(const wxPoint& pt) : type(1) { type1.x = pt.x; @@ -640,6 +556,8 @@ AtlasMessage::Position::Position(const wxPoint& pt) ////////////////////////////////////////////////////////////////////////// +/* Disabled (and should be removed if it turns out to be unnecessary) + - see MessagePasserImpl.cpp for information static void QueryCallback() { @@ -670,6 +588,14 @@ static void QueryCallback() AtlasEventLoop* evtLoop = (AtlasEventLoop*)wxEventLoop::GetActive(); + // evtLoop might be NULL, particularly if we're still initialising windows + // and haven't got into the normal event loop yet. But we'd have to process + // messages anyway, to avoid the deadlocks that this is for. So, don't bother + // with that and just crash instead. + // (Maybe it could be solved better by constructing/finding an event loop + // object here and setting it as the global one, assuming it's not overwritten + // later by wx.) + while (evtLoop->Pending()) { // Based on src/msw/evtloop.cpp's wxEventLoop::Dispatch() @@ -712,8 +638,9 @@ static void QueryCallback() } } } - -void AtlasMessage::QueryMessage::Post() +*/ +void QueryMessage::Post() { - g_MessagePasser->Query(this, &QueryCallback); +// g_MessagePasser->Query(this, &QueryCallback); + g_MessagePasser->Query(this, NULL); } diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h index 2ffd4bd57f..b9d2406f8d 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h @@ -27,6 +27,8 @@ public: static AtlasWindowCommandProc& GetCommandProc(); + static float GetSpeedModifier(); + private: wxTimer m_Timer; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp index c5956051db..59b3578f17 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Cinematic/Cinematic.cpp @@ -729,7 +729,7 @@ public: m_Sizer->Add(m_Track, 0); m_Sizer->Add(m_Path, 0); - m_Timer = new wxTimer(this, wxID_ANY); + m_Timer.SetOwner(this); } void Update() { @@ -744,7 +744,7 @@ public: void PrepareTimers() { m_OldTime = m_NewTime = m_HighResTimer.GetTime(); - m_Timer->Start(10); + m_Timer.Start(10); } void Reset() { @@ -754,7 +754,7 @@ public: float m_OldTime; float m_NewTime; - wxTimer* m_Timer; + wxTimer m_Timer; private: TrackSlider* m_Track; HighResTimer m_HighResTimer; @@ -771,7 +771,7 @@ END_EVENT_TABLE() void TrackSlider::OnScroll(wxScrollEvent& WXUNUSED(event)) { //Move path and send movement message - m_Sidebar->m_SliderBox->m_Timer->Stop(); + m_Sidebar->m_SliderBox->m_Timer.Stop(); if ( m_Sidebar->m_SelectedTrack < 0 || m_Sidebar->m_SelectedPath < 0 ) { SetValue(0); @@ -792,7 +792,7 @@ void TrackSlider::OnScroll(wxScrollEvent& WXUNUSED(event)) } void PathSlider::OnScroll(wxScrollEvent& WXUNUSED(event)) { - m_Sidebar->m_SliderBox->m_Timer->Stop(); + m_Sidebar->m_SliderBox->m_Timer.Stop(); if ( m_Sidebar->m_SelectedTrack < 0 || m_Sidebar->m_SelectedPath < 0 ) { SetValue(0); @@ -834,7 +834,7 @@ void TrackSlider::Update(float interval) if ( move == range && m_Sidebar->m_Playing ) { - m_Parent->m_Timer->Stop(); + m_Parent->m_Timer.Stop(); SetValue(0); m_Path->SetValue(0); m_Sidebar->GotoNode(0); @@ -859,7 +859,7 @@ public: { if ( m_Parent->m_SelectedTrack < 0 ) return; - m_Parent->m_SliderBox->m_Timer->Stop(); + m_Parent->m_SliderBox->m_Timer.Stop(); m_Parent->m_Playing = false; std::wstring name=*m_Parent->m_Tracks[m_Parent->m_SelectedTrack].name; @@ -894,7 +894,7 @@ public: { if ( m_Parent->m_SelectedTrack < 0 || m_Parent->m_SelectedPath < 0) return; - m_Parent->m_SliderBox->m_Timer->Stop(); + m_Parent->m_SliderBox->m_Timer.Stop(); m_Parent->m_Playing = false; m_Parent->m_AbsoluteTime = m_Parent->m_TimeElapsed = 0.0f; m_Parent->SelectPath(0); @@ -910,7 +910,7 @@ public: { if ( m_Parent->m_SelectedTrack < 0 ) return; - m_Parent->m_SliderBox->m_Timer->Stop(); + m_Parent->m_SliderBox->m_Timer.Stop(); m_Parent->m_SliderBox->PrepareTimers(); POST_MESSAGE(CinemaEvent, @@ -925,7 +925,7 @@ public: { if ( m_Parent->m_SelectedTrack < 0 ) return; - m_Parent->m_SliderBox->m_Timer->Stop(); + m_Parent->m_SliderBox->m_Timer.Stop(); m_Parent->m_SliderBox->Reset(); //m_Parent->m_NodeList->Thaw(); m_Parent->m_Playing = false; @@ -939,7 +939,7 @@ public: //void OnForward(wxCommandEvent& event) void OnNext(wxCommandEvent& WXUNUSED(event)) { - m_Parent->m_SliderBox->m_Timer->Stop(); + m_Parent->m_SliderBox->m_Timer.Stop(); m_Parent->m_Playing = false; std::wstring name=*m_Parent->m_Tracks[m_Parent->m_SelectedTrack].name; sCinemaPath path = m_Parent->GetCurrentPath(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp index 661d3097bd..c81a9bb1f2 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp @@ -60,18 +60,13 @@ public: Add(m_Slider); } - ~VariableSliderBox() - { - m_Conn.disconnect(); - } - void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env)) { m_Slider->UpdateFromVar(); } private: - ObservableConnection m_Conn; + ObservableScopedConnection m_Conn; VariableSlider* m_Slider; }; @@ -121,11 +116,6 @@ public: m_Combo = new VariableCombo(parent, var, m_Conn); Add(m_Combo); } - - ~VariableListBox() - { - m_Conn.disconnect(); - } void SetChoices(const std::vector& choices) { @@ -145,7 +135,7 @@ public: } private: - ObservableConnection m_Conn; + ObservableScopedConnection m_Conn; VariableCombo* m_Combo; }; @@ -210,18 +200,13 @@ public: Add(m_Button); } - ~VariableColourBox() - { - m_Conn.disconnect(); - } - void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& WXUNUSED(env)) { m_Button->UpdateDisplay(); } private: - ObservableConnection m_Conn; + ObservableScopedConnection m_Conn; VariableColourButton* m_Button; }; @@ -240,7 +225,7 @@ EnvironmentSidebar::EnvironmentSidebar(wxWindow* sidebarContainer, wxWindow* bot m_MainSizer->Add(new VariableSliderBox(this, _("Water waviness"), g_EnvironmentSettings.waterwaviness, 0, 10.f)); m_MainSizer->Add(new VariableSliderBox(this, _("Sun rotation"), g_EnvironmentSettings.sunrotation, -M_PI, M_PI)); m_MainSizer->Add(new VariableSliderBox(this, _("Sun elevation"), g_EnvironmentSettings.sunelevation, -M_PI/2, M_PI/2)); - m_MainSizer->Add(new LightControl(this, g_EnvironmentSettings)); + m_MainSizer->Add(new LightControl(this, wxSize(150, 150), g_EnvironmentSettings)); m_MainSizer->Add(m_SkyList = new VariableListBox(this, _("Sky set"), g_EnvironmentSettings.skyset)); m_MainSizer->Add(new VariableColourBox(this, _("Sun colour"), g_EnvironmentSettings.suncolour)); m_MainSizer->Add(new VariableColourBox(this, _("Terrain ambient colour"), g_EnvironmentSettings.terraincolour)); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h index e940b58e85..3d7aa787a9 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.h @@ -14,5 +14,5 @@ protected: private: VariableListBox* m_SkyList; - ObservableConnection m_Conn; + ObservableScopedConnection m_Conn; }; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp index 5d36d4cbe6..388998c0fb 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.cpp @@ -8,13 +8,13 @@ class LightSphere : public wxControl { public: - LightSphere(wxWindow* parent, LightControl* lightControl) - : wxControl(parent, wxID_ANY, wxDefaultPosition, wxSize(150, 150)), + LightSphere(wxWindow* parent, const wxSize& size, LightControl* lightControl) + : wxControl(parent, wxID_ANY, wxDefaultPosition, size), m_LightControl(lightControl) { } - void OnPaint(wxPaintEvent& event) + void OnPaint(wxPaintEvent& WXUNUSED(event)) { // Draw a lit 3D sphere: @@ -87,9 +87,16 @@ public: float mz2 = 1 - mx*mx - my*my; if (mz2 >= 0.f) { - float mz = sqrt(mz2); + //float mz = sqrt(mz2); + //phi = asin(mz); + + // ^^ That's giving the height of the sphere at that point, so it's + // matching the point the user clicked on - but that's quite inconvenient + // when you want to move the sun near the horizon. So just make up + // some formula that gives a slightly nicer-feeling result: + phi = asin(mz2*mz2); + theta = -atan2(mx, my); - phi = asin(mz); } else { @@ -114,12 +121,16 @@ BEGIN_EVENT_TABLE(LightSphere, wxControl) EVT_LEFT_DOWN(LightSphere::OnMouse) END_EVENT_TABLE() -LightControl::LightControl(wxWindow* parent, Observable& environment) +LightControl::LightControl(wxWindow* parent, const wxSize& size, Observable& environment) : wxPanel(parent), m_Environment(environment) { - m_Sphere = new LightSphere(this, this); + wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->SetMinSize(size); + m_Sphere = new LightSphere(this, size, this); m_Sphere->theta = environment.sunrotation; m_Sphere->phi = environment.sunelevation; + sizer->Add(m_Sphere, wxSizerFlags().Expand().Proportion(1)); + SetSizer(sizer); m_Conn = environment.RegisterObserver(0, &LightControl::OnSettingsChange, this); } diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.h index 49f83d2eff..650fd98c5a 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/LightControl.h @@ -10,7 +10,7 @@ class LightSphere; class LightControl : public wxPanel { public: - LightControl(wxWindow* parent, Observable& environment); + LightControl(wxWindow* parent, const wxSize& size, Observable& environment); ~LightControl(); void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& settings); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp index 3a70752b65..396ccf6376 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/PlaceObject.cpp @@ -99,13 +99,7 @@ public: if (wxGetKeyState(WXK_PRIOR)) --dir; // page-up key if (dir) { - float speed = M_PI/2.f; // radians per second - if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL)) - speed /= 64.f; - else if (wxGetKeyState(WXK_CONTROL)) - speed /= 4.f; - else if (wxGetKeyState(WXK_SHIFT)) - speed *= 4.f; + float speed = M_PI/2.f * ScenarioEditor::GetSpeedModifier(); // radians per second g_DefaultAngle += (dir * dt * speed); SendObjectMsg(true); } diff --git a/source/tools/atlas/GameInterface/ActorViewer.cpp b/source/tools/atlas/GameInterface/ActorViewer.cpp new file mode 100644 index 0000000000..a7b3de6b11 --- /dev/null +++ b/source/tools/atlas/GameInterface/ActorViewer.cpp @@ -0,0 +1,190 @@ +#include "precompiled.h" + +#include "ActorViewer.h" + +#include "View.h" + +#include "graphics/Model.h" +#include "graphics/ObjectManager.h" +#include "graphics/Patch.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/GameSetup/Config.h" +#include "renderer/Renderer.h" +#include "renderer/SkyManager.h" + +struct ActorViewerImpl +{ + CUnit* Unit; + CStrW CurrentUnitID; + CStrW CurrentUnitAnim; + float CurrentSpeed; + + CTerrain Terrain; +}; + +ActorViewer::ActorViewer() +: m(*new ActorViewerImpl()) +{ + m.Unit = NULL; + + // Set up the renderer + g_TexMan.LoadTerrainTextures(); + g_ObjMan.LoadObjects(); + g_Renderer.LoadAlphaMaps(); + // (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 (int i = 0; i < PATCH_SIZE; ++i) + { + for (int 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; +} + +void ActorViewer::SetActor(const CStrW& id, const CStrW& animation) +{ + bool needsAnimReload = false; + + 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()); + + if (! m.Unit) + return; + + float angle = PI; + float s = sin(angle); + float c = cos(angle); + CMatrix3D mat; + mat._11 = -c; mat._12 = 0.0f; mat._13 = -s; mat._14 = CELL_SIZE * PATCH_SIZE/2; + mat._21 = 0.0f; mat._22 = 1.0f; mat._23 = 0.0f; mat._24 = 0.0f; + mat._31 = s; mat._32 = 0.0f; mat._33 = -c; mat._34 = CELL_SIZE * PATCH_SIZE/2; + mat._41 = 0.0f; mat._42 = 0.0f; mat._43 = 0.0f; mat._44 = 1.0f; + 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; +} + +// TODO: don't have this duplicated from GameView +void SubmitModelRecursive(CModel* model) +{ + g_Renderer.Submit(model); + + const std::vector& props = model->GetProps(); + for (size_t i = 0; i < props.size(); ++i) + SubmitModelRecursive(props[i].m_Model); +} + +void ActorViewer::Render() +{ + m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR); + + g_Renderer.SetClearColor(0xFFFFFFFFu); + + 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.SetCamera(camera, camera); + + g_Renderer.Submit(m.Terrain.GetPatch(0, 0)); + + if (m.Unit) + SubmitModelRecursive(m.Unit->GetModel()); + + g_Renderer.FlushFrame(); + + g_Renderer.EndFrame(); + + oglCheck(); +} + +void ActorViewer::Update(float dt) +{ + if (m.Unit) + { + m.Unit->GetModel()->Update(dt); + + // Move the model by speed*dt forwards + CMatrix3D mat = m.Unit->GetModel()->GetTransform(); + 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(); + } +} diff --git a/source/tools/atlas/GameInterface/ActorViewer.h b/source/tools/atlas/GameInterface/ActorViewer.h new file mode 100644 index 0000000000..59bde943a9 --- /dev/null +++ b/source/tools/atlas/GameInterface/ActorViewer.h @@ -0,0 +1,22 @@ +#ifndef ACTORVIEWER_H__ +#define ACTORVIEWER_H__ + +struct ActorViewerImpl; + +class ActorViewer +{ +public: + ActorViewer(); + ~ActorViewer(); + + void SetActor(const CStrW& id, const CStrW& animation); + void Render(); + void Update(float dt); + +private: + ActorViewerImpl& m; + + NO_COPY_CTOR(ActorViewer); +}; + +#endif // ACTORVIEWER_H__ diff --git a/source/tools/atlas/GameInterface/Brushes.h b/source/tools/atlas/GameInterface/Brushes.h index b8ea01ed47..6ee5f4ad20 100644 --- a/source/tools/atlas/GameInterface/Brushes.h +++ b/source/tools/atlas/GameInterface/Brushes.h @@ -1,3 +1,6 @@ +#ifndef BRUSHES_H__ +#define BRUSHES_H__ + #include "maths/Vector3D.h" class TerrainOverlay; @@ -33,3 +36,5 @@ private: extern Brush g_CurrentBrush; } + +#endif // BRUSHES_H__ \ No newline at end of file diff --git a/source/tools/atlas/GameInterface/CommandProc.h b/source/tools/atlas/GameInterface/CommandProc.h index 3d197279a0..94035016f2 100644 --- a/source/tools/atlas/GameInterface/CommandProc.h +++ b/source/tools/atlas/GameInterface/CommandProc.h @@ -1,3 +1,6 @@ +#ifndef COMMANDPROC_H__ +#define COMMANDPROC_H__ + #include #include #include @@ -162,3 +165,5 @@ The following macros convert that into: } + +#endif // COMMANDPROC_H__ diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp index 19d693157f..f07e5bc25a 100644 --- a/source/tools/atlas/GameInterface/GameLoop.cpp +++ b/source/tools/atlas/GameInterface/GameLoop.cpp @@ -5,44 +5,33 @@ #include "MessagePasserImpl.h" #include "Messages.h" #include "SharedMemory.h" -#include "Brushes.h" #include "Handlers/MessageHandler.h" +#include "ActorViewer.h" +#include "View.h" #include "InputProcessor.h" +#include "lib/app_hooks.h" #include "lib/sdl.h" -#include "lib/ogl.h" #include "lib/timer.h" #include "lib/res/file/vfs.h" #include "ps/CLogger.h" -#include "ps/GameSetup/GameSetup.h" -#include "ps/Game.h" -#include "ps/World.h" -#include "simulation/Simulation.h" -#include "simulation/EntityManager.h" using namespace AtlasMessage; namespace AtlasMessage { - extern void AtlasRenderSelection(); extern void RegisterHandlers(); } -void AtlasRender() -{ - Render(); - AtlasRenderSelection(); -} - - // Loaded from DLL: -void (*Atlas_StartWindow)(wchar_t* type); +void (*Atlas_StartWindow)(const wchar_t* type); void (*Atlas_SetMessagePasser)(MessagePasser*); void (*Atlas_GLSetCurrent)(void* context); void (*Atlas_GLSwapBuffers)(void* context); void (*Atlas_NotifyEndOfFrame)(); +void (*Atlas_DisplayError)(const wchar_t* text, unsigned int flags); namespace AtlasMessage { void* (*ShareableMallocFptr)(size_t); @@ -60,13 +49,33 @@ static GameLoopState state; GameLoopState* g_GameLoop = &state; -static void* LaunchWindow(void*) +static void* LaunchWindow(void* data) { + const wchar_t* windowName = reinterpret_cast(data); debug_set_thread_name("atlas_window"); - Atlas_StartWindow(L"ScenarioEditor"); + Atlas_StartWindow(windowName); return NULL; } +// Work out which Atlas window to launch, given the command-line arguments +static const wchar_t* FindWindowName(int argc, char* argv[]) +{ + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "-actorviewer") == 0) + return L"ActorViewer"; + } + + return L"ScenarioEditor"; +} + +static ErrorReaction AtlasDisplayError(const wchar_t* text, uint flags) +{ + // TODO: after Atlas has been unloaded, don't do this + Atlas_DisplayError(text, flags); + + return ER_CONTINUE; +} bool BeginAtlas(int argc, char* argv[], void* dll) { @@ -77,6 +86,7 @@ bool BeginAtlas(int argc, char* argv[], void* dll) GET(Atlas_GLSetCurrent); GET(Atlas_GLSwapBuffers); GET(Atlas_NotifyEndOfFrame); + GET(Atlas_DisplayError); #undef GET #define GET(x) *(void**)&x##Fptr = dlsym(dll, #x); debug_assert(x##Fptr); if (! x##Fptr) return false; GET(ShareableMalloc); @@ -90,14 +100,19 @@ bool BeginAtlas(int argc, char* argv[], void* dll) RegisterHandlers(); // Create a new thread, and launch the Atlas window inside that thread - pthread_t gameThread; - pthread_create(&gameThread, NULL, LaunchWindow, NULL); + const wchar_t* windowName = FindWindowName(argc, argv); + pthread_t uiThread; + pthread_create(&uiThread, NULL, LaunchWindow, reinterpret_cast(const_cast(windowName))); + + // Override ah_display_error to pass all errors to the Atlas UI + AppHooks hooks = {0}; + hooks.display_error = AtlasDisplayError; + app_hooks_update(&hooks); state.argc = argc; state.argv = argv; state.running = true; - state.rendering = false; - state.worldloaded = false; + state.view = View::GetView_None(); state.glContext = NULL; double last_activity = get_time(); @@ -108,13 +123,13 @@ bool BeginAtlas(int argc, char* argv[], void* dll) ////////////////////////////////////////////////////////////////////////// // (TODO: Work out why these things have to be in this order (to avoid - // jumps when starting to move, etc) + // jumps when starting to move, etc)) // Calculate frame length { - const double time = get_time(); + double time = get_time(); static double last_time = time; - const float length = (float)(time-last_time); + float length = (float)(time-last_time); last_time = time; debug_assert(length >= 0.0f); // TODO: filter out big jumps, e.g. when having done a lot of slow @@ -181,17 +196,9 @@ bool BeginAtlas(int argc, char* argv[], void* dll) vfs_reload_changed_files(); - if (state.worldloaded) - { - g_EntityManager.updateAll(0); - g_Game->GetSimulation()->Update(0.0); - } + state.view->Update(state.frameLength); - if (state.rendering) - { - AtlasRender(); - Atlas_GLSwapBuffers((void*)state.glContext); - } + state.view->Render(); double time = get_time(); if (recent_activity) @@ -199,13 +206,14 @@ bool BeginAtlas(int argc, char* argv[], void* dll) // Be nice to the processor (by sleeping lots) if we're not doing anything // useful, and nice to the user (by just yielding to other threads) if we are - bool yield = time - last_activity > 0.5; - if ( state.worldloaded ) - { - if ( g_Game->GetView()->GetCinema()->IsPlaying() ) - g_Game->GetView()->GetCinema()->Update(state.frameLength); + bool yield = (time - last_activity > 0.5); + + // But make sure we aren't doing anything interesting right now, where + // the user wants to see the screen updating even though they're not + // interacting with it + if (state.view->WantsHighFramerate()) yield = false; - } + if (yield) // if there was no recent activity... { double sleepUntil = time + 0.5; // only redraw at 2fps @@ -231,7 +239,11 @@ bool BeginAtlas(int argc, char* argv[], void* dll) // TODO: delete all remaining messages, to avoid memory leak warnings - pthread_join(gameThread, NULL); + // Wait for the UI to exit + pthread_join(uiThread, NULL); + + // Clean up + View::DestroyViews(); exit(0); } diff --git a/source/tools/atlas/GameInterface/GameLoop.h b/source/tools/atlas/GameInterface/GameLoop.h index a285de9817..32c5dacb8a 100644 --- a/source/tools/atlas/GameInterface/GameLoop.h +++ b/source/tools/atlas/GameInterface/GameLoop.h @@ -3,13 +3,16 @@ extern void (*Atlas_GLSetCurrent)(void* context); +class View; + struct GameLoopState { int argc; char** argv; - bool running; - bool rendering; - bool worldloaded; + + bool running; // whether the Atlas game loop is still running + View* view; // current 'view' (controls updates, rendering, etc) + const void* glContext; float frameLength; // smoothed to avoid large jumps diff --git a/source/tools/atlas/GameInterface/Handlers/BrushHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/BrushHandlers.cpp index fa3094a65a..cd3cfce8fe 100644 --- a/source/tools/atlas/GameInterface/Handlers/BrushHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/BrushHandlers.cpp @@ -14,7 +14,7 @@ MESSAGEHANDLER(Brush) MESSAGEHANDLER(BrushPreview) { g_CurrentBrush.SetRenderEnabled(msg->enable); - msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre); + g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(); } } diff --git a/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp index d8480f5c3a..f1431eb8f7 100644 --- a/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/CameraCtrlHandlers.cpp @@ -2,6 +2,7 @@ #include "MessageHandler.h" #include "../GameLoop.h" +#include "../View.h" #include "maths/Vector3D.h" #include "maths/Quaternion.h" @@ -16,8 +17,9 @@ namespace AtlasMessage { MESSAGEHANDLER(ScrollConstant) { - if ( g_Game->GetView()->GetCinema()->IsPlaying() ) + if (g_Game->GetView()->GetCinema()->IsPlaying()) return; + if (msg->dir < 0 || msg->dir > 3) { debug_warn("ScrollConstant: invalid direction"); @@ -28,10 +30,14 @@ MESSAGEHANDLER(ScrollConstant) } } +// TODO: change all these g_Game->...GetCamera() bits to use the current View's +// camera instead. + MESSAGEHANDLER(Scroll) { - if ( g_Game->GetView()->GetCinema()->IsPlaying() ) + if (g_Game->GetView()->GetCinema()->IsPlaying()) // TODO: do this better (probably a separate View class for cinematics) return; + static CVector3D targetPos; static float targetDistance = 0.f; @@ -57,7 +63,7 @@ MESSAGEHANDLER(Scroll) if (msg->type == eScrollType::FROM) { - msg->pos->GetWorldSpace(targetPos); + targetPos = msg->pos->GetWorldSpace(); targetDistance = (targetPos - camera.GetTranslation()).GetLength(); } else if (msg->type == eScrollType::TO) @@ -79,15 +85,17 @@ MESSAGEHANDLER(Scroll) MESSAGEHANDLER(SmoothZoom) { - if ( g_Game->GetView()->GetCinema()->IsPlaying() ) + if (g_Game->GetView()->GetCinema()->IsPlaying()) return; + g_GameLoop->input.zoomDelta += msg->amount; } MESSAGEHANDLER(RotateAround) { - if ( g_Game->GetView()->GetCinema()->IsPlaying() ) + if (g_Game->GetView()->GetCinema()->IsPlaying()) return; + static CVector3D focusPos; static float lastX = 0.f, lastY = 0.f; @@ -96,7 +104,7 @@ MESSAGEHANDLER(RotateAround) if (msg->type == eRotateAroundType::FROM) { msg->pos->GetScreenSpace(lastX, lastY); // get mouse position - msg->pos->GetWorldSpace(focusPos); // get point on terrain under mouse + focusPos = msg->pos->GetWorldSpace(); // get point on terrain under mouse } else if (msg->type == eRotateAroundType::TO) { @@ -136,5 +144,33 @@ MESSAGEHANDLER(RotateAround) } } +MESSAGEHANDLER(LookAt) +{ + // TODO: different view depending on + CCamera& camera = View::GetView_Actor()->GetCamera(); + + CVector3D tgt = msg->target->GetWorldSpace(); + CVector3D eye = msg->pos->GetWorldSpace(); + tgt.Y = -tgt.Y; // ??? why is this needed? + eye.Y = -eye.Y; // ??? + + // Based on http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html + CVector3D f = tgt - eye; + f.Normalize(); + CVector3D s = f.Cross(CVector3D(0, 1, 0)); + CVector3D u = s.Cross(f); + CMatrix3D M ( + s[0], s[1], s[2], 0, + u[0], u[1], u[2], 0, + -f[0], -f[1], -f[2], 0, + 0, 0, 0, 1 + ); + + M.GetTranspose(camera.m_Orientation); + camera.m_Orientation.Translate(-eye); + + camera.UpdateFrustum(); +} + } diff --git a/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp index 4f376f3fb6..8bd76ec82e 100644 --- a/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp @@ -102,7 +102,7 @@ BEGIN_COMMAND(AlterElevation) } static CVector3D previousPosition; - msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition); + g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(previousPosition); previousPosition = g_CurrentBrush.m_Centre; int x0, y0; @@ -158,7 +158,7 @@ BEGIN_COMMAND(FlattenElevation) int amount = (int)msg->amount; static CVector3D previousPosition; - msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition); + g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(previousPosition); previousPosition = g_CurrentBrush.m_Centre; int xc, yc; diff --git a/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp index 8f7cf266ba..1a62eee2e9 100644 --- a/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/EnvironmentHandlers.cpp @@ -50,7 +50,10 @@ void SetSettings(const sEnvironmentSettings& s) g_LightEnv.SetRotation(s.sunrotation); g_LightEnv.SetElevation(s.sunelevation); - g_Renderer.GetSkyManager()->SetSkySet(*s.skyset); + CStrW skySet = *s.skyset; + if (skySet.length() == 0) + skySet = L"default"; + g_Renderer.GetSkyManager()->SetSkySet(skySet); #define COLOUR(A, B) B = RGBColor(A->r/255.f, A->g/255.f, A->b/255.f) COLOUR(s.suncolour, g_LightEnv.m_SunColor); diff --git a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp index 80018515af..5415f163fe 100644 --- a/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/GraphicsSetupHandlers.cpp @@ -3,6 +3,8 @@ #include "MessageHandler.h" #include "../GameLoop.h" #include "../CommandProc.h" +#include "../ActorViewer.h" +#include "../View.h" #include "renderer/Renderer.h" #include "graphics/GameView.h" @@ -15,14 +17,12 @@ #include "ps/GameSetup/Config.h" #include "ps/GameSetup/GameSetup.h" - namespace AtlasMessage { - MESSAGEHANDLER(Init) { UNUSED2(msg); - + oglInit(); g_Quickstart = true; @@ -45,9 +45,10 @@ MESSAGEHANDLER(Shutdown) // we kill the EntityManager GetCommandProc().Destroy(); - Shutdown(); + View::DestroyViews(); + g_GameLoop->view = View::GetView_None(); - g_GameLoop->rendering = false; + Shutdown(); } @@ -60,7 +61,16 @@ QUERYHANDLER(Exit) MESSAGEHANDLER(RenderEnable) { - g_GameLoop->rendering = msg->enabled; + if (msg->view == eRenderView::NONE) g_GameLoop->view = View::GetView_None(); + else if (msg->view == eRenderView::GAME) g_GameLoop->view = View::GetView_Game(); + else if (msg->view == eRenderView::ACTOR) g_GameLoop->view = View::GetView_Actor(); + else debug_warn("Invalid view type"); +} + +MESSAGEHANDLER(SetActorViewer) +{ + View::GetView_Actor()->SetSpeedMultiplier(msg->speed); + View::GetView_Actor()->GetActorViewer().SetActor(*msg->id, *msg->animation); } ////////////////////////////////////////////////////////////////////////// @@ -81,18 +91,9 @@ MESSAGEHANDLER(ResizeScreen) SViewPort vp = { 0, 0, g_xres, g_yres }; - if (g_Game) - { - g_Game->GetView()->GetCamera()->SetViewPort(&vp); - g_Game->GetView()->GetCamera()->SetProjection (1, 5000, DEGTORAD(20)); - } - g_Renderer.SetViewport(vp); g_Renderer.Resize(g_xres, g_yres); - if (g_Game) - g_Game->GetView()->GetCamera()->UpdateFrustum(); - g_GUI.UpdateResolution(); g_Console->UpdateScreenSize(g_xres, g_yres); diff --git a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp index 0f7f8b225b..8b259fe362 100644 --- a/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -35,8 +35,6 @@ static void InitGame(std::wstring map) // Initialise the game: g_Game = new CGame(); - - g_GameLoop->worldloaded = true; } static void StartGame() diff --git a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp index 3d92389d13..95228d23f1 100644 --- a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp @@ -7,6 +7,7 @@ #include "graphics/GameView.h" #include "graphics/Model.h" +#include "graphics/ObjectEntry.h" #include "graphics/ObjectManager.h" #include "graphics/Terrain.h" #include "graphics/Unit.h" @@ -18,8 +19,10 @@ #include "ps/Game.h" #include "ps/World.h" #include "simulation/EntityTemplateCollection.h" +#include "simulation/EntityTemplate.h" #include "simulation/Entity.h" #include "simulation/EntityManager.h" +#include "simulation/TerritoryManager.h" #define LOG_CATEGORY "editor" @@ -214,7 +217,7 @@ static float flt_minus_epsilon(float f) static CVector3D GetUnitPos(const Position& pos) { static CVector3D vec; - pos.GetWorldSpace(vec, vec); // if msg->pos is 'Unchanged', use the previous pos + vec = pos.GetWorldSpace(vec); // if msg->pos is 'Unchanged', use the previous pos float xOnMap = clamp(vec.X, 0.f, flt_minus_epsilon((g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide()-1)*CELL_SIZE)); float zOnMap = clamp(vec.Z, 0.f, flt_minus_epsilon((g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide()-1)*CELL_SIZE)); @@ -296,8 +299,7 @@ MESSAGEHANDLER(ObjectPreview) if (msg->usetarget) { // Aim from pos towards msg->target - CVector3D target; - msg->target->GetWorldSpace(target, pos.Y); + CVector3D target = msg->target->GetWorldSpace(pos.Y); CVector2D dir(target.X-pos.X, target.Z-pos.Z); dir = dir.normalize(); s = dir.x; @@ -337,8 +339,7 @@ BEGIN_COMMAND(CreateObject) if (msg->usetarget) { // Aim from m_Pos towards msg->target - CVector3D target; - msg->target->GetWorldSpace(target, m_Pos.Y); + CVector3D target = msg->target->GetWorldSpace(m_Pos.Y); CVector2D dir(target.X-m_Pos.X, target.Z-m_Pos.Z); m_Angle = atan2(dir.x, dir.y); } @@ -388,6 +389,9 @@ BEGIN_COMMAND(CreateObject) { ent->SetPlayer(g_Game->GetPlayer(m_Player)); ent->m_actor->SetID(m_ID); + + if (ent->m_base->m_isTerritoryCentre) + g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate(); } } } @@ -424,7 +428,14 @@ BEGIN_COMMAND(CreateObject) if (unit) { if (unit->GetEntity()) + { + bool wasTerritoryCentre = unit->GetEntity()->m_base->m_isTerritoryCentre; + unit->GetEntity()->kill(); + + if (wasTerritoryCentre) + g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate(); + } else { g_UnitMan.RemoveUnit(unit); @@ -504,6 +515,9 @@ BEGIN_COMMAND(MoveObject) if (unit->GetEntity()) { unit->GetEntity()->m_position = pos; + + if (unit->GetEntity()->m_base->m_isTerritoryCentre) + g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate(); } else { @@ -549,8 +563,7 @@ BEGIN_COMMAND(RotateObject) if (msg->usetarget) { CVector3D& pos = unit->GetEntity()->m_position; - CVector3D target; - msg->target->GetWorldSpace(target, pos.Y); + CVector3D target = msg->target->GetWorldSpace(pos.Y); CVector2D dir(target.X-pos.X, target.Z-pos.Z); m_AngleNew = atan2(dir.x, dir.y); } @@ -568,8 +581,7 @@ BEGIN_COMMAND(RotateObject) float s, c; if (msg->usetarget) { - CVector3D target; - msg->target->GetWorldSpace(target, pos.Y); + CVector3D target = msg->target->GetWorldSpace(pos.Y); CVector2D dir(target.X-pos.X, target.Z-pos.Z); dir = dir.normalize(); s = dir.x; @@ -660,6 +672,10 @@ BEGIN_COMMAND(DeleteObject) { // HACK: I don't know the proper way of undoably deleting entities... unit->GetEntity()->entf_set(ENTF_DESTROYED); + + // TODO: territories don't ignore DESTROYED entities + if (unit->GetEntity()->m_base->m_isTerritoryCentre) + g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate(); } g_UnitMan.RemoveUnit(unit); @@ -669,8 +685,13 @@ BEGIN_COMMAND(DeleteObject) void Undo() { if (m_UnitInLimbo->GetEntity()) + { m_UnitInLimbo->GetEntity()->entf_clear(ENTF_DESTROYED); + if (m_UnitInLimbo->GetEntity()->m_base->m_isTerritoryCentre) + g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate(); + } + g_UnitMan.AddUnit(m_UnitInLimbo); m_UnitInLimbo = NULL; } diff --git a/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp index 6bbe17c9c4..ab7ab952c6 100644 --- a/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/TerrainHandlers.cpp @@ -163,7 +163,7 @@ BEGIN_COMMAND(PaintTerrain) void Do() { - msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre); + g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(); int x0, y0; g_CurrentBrush.GetBottomLeft(x0, y0); diff --git a/source/tools/atlas/GameInterface/InputProcessor.h b/source/tools/atlas/GameInterface/InputProcessor.h index 65d1688ba0..7b9dc8315d 100644 --- a/source/tools/atlas/GameInterface/InputProcessor.h +++ b/source/tools/atlas/GameInterface/InputProcessor.h @@ -1,3 +1,6 @@ +#ifndef INPUTPROCESSOR_H__ +#define INPUTPROCESSOR_H__ + #include "GameLoop.h" class InputProcessor @@ -6,3 +9,5 @@ public: // Returns true if the camera has moved bool ProcessInput(GameLoopState* state); }; + +#endif // INPUTPROCESSOR_H__ diff --git a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp index 9775fdd9ea..7d03792ccf 100644 --- a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp +++ b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp @@ -43,12 +43,13 @@ IMessage* MessagePasserImpl::Retrieve() m_Mutex.Unlock(); -// if (m_Trace && msg) debug_printf("%8.3f retrieved message: %s\n", get_time(), msg->GetType()); + if (m_Trace && msg) + debug_printf("%8.3f retrieved message: %s\n", get_time(), msg->GetName()); return msg; } -void MessagePasserImpl::Query(QueryMessage* qry, void(*timeoutCallback)()) +void MessagePasserImpl::Query(QueryMessage* qry, void(* UNUSED(timeoutCallback) )()) { debug_assert(qry); debug_assert(qry->GetType() == IMessage::Query); @@ -74,32 +75,49 @@ void MessagePasserImpl::Query(QueryMessage* qry, void(*timeoutCallback)()) // Wait until the query handler has handled the query and called sem_post: - // At least on Win32, it is necessary for the UI thread to run its event - // loop to avoid deadlocking the system (particularly when the game - // tries to show a dialog box); so timeoutCallback is called whenever we - // think it's necessary for that to happen. -#if OS_WIN - // On Win32, use MsgWaitForMultipleObjects, which waits on the semaphore - // but is also interrupted by incoming Windows-messages. - while (0 != (err = sem_msgwait_np(&sem))) -#else - // TODO: On non-Win32, I have no idea whether the same problem exists; but - // it might do, so call the callback every few seconds just in case it helps. - struct timespec abs_timeout; - clock_gettime(CLOCK_REALTIME, &abs_timeout); - abs_timeout.tv_sec += 2; - while (0 != (err = sem_timedwait(&sem, &abs_timeout))) -#endif + // The following code was necessary to avoid deadlock, but it still breaks + // in some cases (e.g. when Atlas issues a query before its event loop starts + // running) and doesn't seem to be the simplest possible solution. + // So currently we're trying to not do anything like that at all, and + // just stop the game making windows (which is what seems (from experience) to + // deadlock things) by overriding ah_display_error. Hopefully it'll work like + // that, and the redundant code below/elsewhere can be removed, but it's + // left in here in case it needs to be reinserted in the future to make it + // work. + // (See http://www.wildfiregames.com/forum/index.php?s=&showtopic=10236&view=findpost&p=174617) + +// // At least on Win32, it is necessary for the UI thread to run its event +// // loop to avoid deadlocking the system (particularly when the game +// // tries to show a dialog box); so timeoutCallback is called whenever we +// // think it's necessary for that to happen. +// +// #if OS_WIN +// // On Win32, use MsgWaitForMultipleObjects, which waits on the semaphore +// // but is also interrupted by incoming Windows-messages. +// // while (0 != (err = sem_msgwait_np(&sem))) +// +// while (0 != (err = sem_wait(&sem))) +// #else +// // TODO: On non-Win32, I have no idea whether the same problem exists; but +// // it might do, so call the callback every few seconds just in case it helps. +// struct timespec abs_timeout; +// clock_gettime(CLOCK_REALTIME, &abs_timeout); +// abs_timeout.tv_sec += 2; +// while (0 != (err = sem_timedwait(&sem, &abs_timeout))) +// #endif + + while (0 != (err = sem_wait(&sem))) { // If timed out, call callback and try again - if (errno == ETIMEDOUT) - timeoutCallback(); +// if (errno == ETIMEDOUT) +// timeoutCallback(); +// else // Keep retrying while EINTR, but other errors are probably fatal - else if (errno != EINTR) + if (errno != EINTR) { debug_warn("Semaphore wait failed"); - return; // (leak the semaphore) + return; // (leaks the semaphore) } } diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h index bf22a47c27..3791cbb7d6 100644 --- a/source/tools/atlas/GameInterface/Messages.h +++ b/source/tools/atlas/GameInterface/Messages.h @@ -13,8 +13,11 @@ MESSAGE(Init, ); MESSAGE(Shutdown, ); +struct eRenderView { enum { NONE, GAME, ACTOR }; }; + MESSAGE(RenderEnable, - ((bool, enabled))); + ((int, view)) // eRenderView + ); ////////////////////////////////////////////////////////////////////////// @@ -108,7 +111,7 @@ SHAREABLE_STRUCT(sObjectsListItem); QUERY(GetObjectsList, , // no inputs - ((std::vector, objects)) + ((std::vector, objects)) // sorted by .name ); struct sObjectSettings @@ -123,6 +126,8 @@ struct sObjectSettings }; SHAREABLE_STRUCT(sObjectSettings); +// Preview object in the game world - creates a temporary unit at the given +// position, and removes it when the preview is next changed MESSAGE(ObjectPreview, ((std::wstring, id)) // or empty string => disable ((sObjectSettings, settings)) @@ -141,6 +146,13 @@ COMMAND(CreateObject, NOMERGE, ((float, angle)) ); +// Set an actor to be previewed on its own (i.e. without the game world). +// (Use RenderEnable to make it visible.) +MESSAGE(SetActorViewer, + ((std::wstring, id)) + ((std::wstring, animation)) + ((float, speed)) + ); ////////////////////////////////////////////////////////////////////////// @@ -149,29 +161,38 @@ QUERY(Exit,,); // no inputs nor outputs ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// - struct eScrollConstantDir { enum { FORWARDS, BACKWARDS, LEFT, RIGHT }; }; MESSAGE(ScrollConstant, - ((int, dir)) + ((int, view)) // eRenderView + ((int, dir)) // eScrollConstantDir ((float, speed)) // set speed 0.0f to stop scrolling ); struct eScrollType { enum { FROM, TO }; }; MESSAGE(Scroll, // for scrolling by dragging the mouse FROM somewhere TO elsewhere - ((int, type)) + ((int, view)) // eRenderView + ((int, type)) // eScrollType ((Position, pos)) ); MESSAGE(SmoothZoom, + ((int, view)) // eRenderView ((float, amount)) ); struct eRotateAroundType { enum { FROM, TO }; }; MESSAGE(RotateAround, - ((int, type)) + ((int, view)) // eRenderView + ((int, type)) // eRotateAroundType ((Position, pos)) ); +MESSAGE(LookAt, + ((int, view)) // eRenderView + ((Position, pos)) + ((Position, target)) + ); + ////////////////////////////////////////////////////////////////////////// struct sEnvironmentSettings @@ -225,16 +246,11 @@ struct ePaintTerrainPriority { enum { HIGH, LOW }; }; COMMAND(PaintTerrain, MERGE, ((Position, pos)) ((std::wstring, texture)) - ((int, priority)) + ((int, priority)) // ePaintTerrainPriority ); ////////////////////////////////////////////////////////////////////////// -typedef int ObjectID; -FUNCTION( -inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); } -); - QUERY(PickObject, ((Position, pos)) , @@ -276,64 +292,8 @@ COMMAND(SetObjectSettings, NOMERGE, ////////////////////////////////////////////////////////////////////////// -struct sCinemaSplineNode -{ - Shareable x, y, z, t; -public: - sCinemaSplineNode(float px, float py, float pz) : x(px), y(py), z(pz), t(0.0f){} - sCinemaSplineNode() {} - void SetTime(float _t) { t = _t; } -}; -SHAREABLE_STRUCT(sCinemaSplineNode); - -struct sCinemaPath -{ - Shareable > nodes; - Shareable duration, x, y, z; - Shareable mode, growth, change, style; //change == switch point - - sCinemaPath(float rx, float ry, float rz) : x(rx), y(ry), z(rz), - mode(0), style(0), change(0), growth(0), duration(0) {} - sCinemaPath() : x(0), y(0), z(0), mode(0), style(0), - change(0), growth(0), duration(0) {} - - AtlasMessage::sCinemaPath operator-(const AtlasMessage::sCinemaPath& path) - { - return AtlasMessage::sCinemaPath(x - path.x, y - path.y, - z - path.z); - } - AtlasMessage::sCinemaPath operator+(const AtlasMessage::sCinemaPath& path) - { - return AtlasMessage::sCinemaPath(x + path.x, y + path.y, - z + path.z); - } -}; -SHAREABLE_STRUCT(sCinemaPath); - -struct sCinemaTrack -{ - Shareable name; - Shareable x, y, z, timescale, duration; - Shareable > paths; - -public: - sCinemaTrack(float rx, float ry, float rz, std::wstring track) - : x(rx), y(ry), z(rz), timescale(1.f), duration(0) - { name = track; } - sCinemaTrack() : x(0), y(0), z(0), timescale(1.f), duration(0) {} -}; -SHAREABLE_STRUCT(sCinemaTrack); - -struct eCinemaEventMode { enum { SMOOTH, SELECT, IMMEDIATE_PATH, - IMMEDIATE_TRACK }; }; -struct sCameraInfo -{ - Shareable pX, pY, pZ, rX, rY, rZ; //position and rotation -}; -SHAREABLE_STRUCT(sCameraInfo); - QUERY(GetCinemaTracks, - , //no input + , // no inputs ((std::vector , tracks)) ); diff --git a/source/tools/atlas/GameInterface/MessagesSetup.h b/source/tools/atlas/GameInterface/MessagesSetup.h index 7216d0cf72..867cba012b 100644 --- a/source/tools/atlas/GameInterface/MessagesSetup.h +++ b/source/tools/atlas/GameInterface/MessagesSetup.h @@ -165,8 +165,6 @@ const bool NOMERGE = false; QUERY_WITH_INPUTS) \ (name, in_vals, out_vals) -#define FUNCTION(def) def - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -187,7 +185,6 @@ const bool NOMERGE = false; #undef QUERY_WITHOUT_INPUTS #undef QUERY_WITH_INPUTS #undef QUERY -#undef FUNCTION } diff --git a/source/tools/atlas/GameInterface/Misc.cpp b/source/tools/atlas/GameInterface/Misc.cpp index 501aa436dd..6ff5d0b2f5 100644 --- a/source/tools/atlas/GameInterface/Misc.cpp +++ b/source/tools/atlas/GameInterface/Misc.cpp @@ -8,52 +8,50 @@ #include "ps/Game.h" #include "graphics/GameView.h" -void AtlasMessage::Position::GetWorldSpace(CVector3D& vec) const +CVector3D AtlasMessage::Position::GetWorldSpace() const { switch (type) { case 0: - vec.Set(type0.x, type0.y, type0.z); + return CVector3D(type0.x, type0.y, type0.z); break; case 1: - vec = g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y); + return g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y); break; case 2: debug_warn("Invalid Position acquisition (unchanged without previous)"); - vec.Set(0.f, 0.f, 0.f); + return CVector3D(0.f, 0.f, 0.f); break; default: debug_warn("Invalid Position type"); - vec.Set(0.f, 0.f, 0.f); + return CVector3D(0.f, 0.f, 0.f); } } -void AtlasMessage::Position::GetWorldSpace(CVector3D& vec, float h) const +CVector3D AtlasMessage::Position::GetWorldSpace(float h) const { switch (type) { case 1: - vec = g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y, h); - break; + return g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y, h); default: - GetWorldSpace(vec); + return GetWorldSpace(); } } -void AtlasMessage::Position::GetWorldSpace(CVector3D& vec, const CVector3D& prev) const +CVector3D AtlasMessage::Position::GetWorldSpace(const CVector3D& prev) const { switch (type) { case 2: - vec = prev; - break; + return prev; default: - GetWorldSpace(vec); + return GetWorldSpace(); } } diff --git a/source/tools/atlas/GameInterface/Register.cpp b/source/tools/atlas/GameInterface/Register.cpp index 6537612028..9492f851d3 100644 --- a/source/tools/atlas/GameInterface/Register.cpp +++ b/source/tools/atlas/GameInterface/Register.cpp @@ -35,8 +35,6 @@ extern cmdHandlers& GetCmdHandlers(); extern cmdHandler c##name##_create(); \ GetCmdHandlers().insert(std::pair("c"#name, c##name##_create())); -#define FUNCTION(def) - #undef SHAREABLE_STRUCT #define SHAREABLE_STRUCT(name) diff --git a/source/tools/atlas/GameInterface/Shareable.h b/source/tools/atlas/GameInterface/Shareable.h index 182edd3cbf..1949cc424b 100644 --- a/source/tools/atlas/GameInterface/Shareable.h +++ b/source/tools/atlas/GameInterface/Shareable.h @@ -161,7 +161,7 @@ public: const wrapped_type _Unwrap() const { - return buf ? wrapped_type(buf, buf+length-1) : wrapped_type(); + return (buf && length) ? wrapped_type(buf, buf+length-1) : wrapped_type(); } const wrapped_type operator*() const @@ -173,7 +173,7 @@ public: // without constructing a new std::basic_string then calling c_str on that const C* c_str() const { - return buf ? buf : (C*)empty_str; + return (buf && length) ? buf : (C*)empty_str; } }; diff --git a/source/tools/atlas/GameInterface/SharedTypes.h b/source/tools/atlas/GameInterface/SharedTypes.h index 20d250b5d0..b76a97f9ed 100644 --- a/source/tools/atlas/GameInterface/SharedTypes.h +++ b/source/tools/atlas/GameInterface/SharedTypes.h @@ -39,13 +39,14 @@ struct Position // Only for use in the game, not the UI. // Implementations in Misc.cpp. - void GetWorldSpace(CVector3D& vec) const; - void GetWorldSpace(CVector3D& vec, float h) const; - void GetWorldSpace(CVector3D& vec, const CVector3D& prev) const; + CVector3D GetWorldSpace() const; + CVector3D GetWorldSpace(float h) const; + CVector3D GetWorldSpace(const CVector3D& prev) const; void GetScreenSpace(float& x, float& y) const; }; SHAREABLE_STRUCT(Position); + struct Colour { Colour() @@ -62,6 +63,64 @@ struct Colour }; SHAREABLE_STRUCT(Colour); + +typedef int ObjectID; +inline bool ObjectIDIsValid(ObjectID id) { return (id >= 0); } + + +struct sCinemaSplineNode +{ + Shareable x, y, z, t; +public: + sCinemaSplineNode(float px, float py, float pz) : x(px), y(py), z(pz), t(0.0f) {} + sCinemaSplineNode() {} + void SetTime(float _t) { t = _t; } +}; +SHAREABLE_STRUCT(sCinemaSplineNode); + +struct sCinemaPath +{ + Shareable > nodes; + Shareable duration, x, y, z; + Shareable mode, growth, change, style; // change == switch point + + sCinemaPath(float rx, float ry, float rz) : x(rx), y(ry), z(rz), + mode(0), style(0), change(0), growth(0), duration(0) {} + sCinemaPath() : x(0), y(0), z(0), mode(0), style(0), + change(0), growth(0), duration(0) {} + + AtlasMessage::sCinemaPath operator-(const AtlasMessage::sCinemaPath& path) + { + return AtlasMessage::sCinemaPath(x - path.x, y - path.y, z - path.z); + } + AtlasMessage::sCinemaPath operator+(const AtlasMessage::sCinemaPath& path) + { + return AtlasMessage::sCinemaPath(x + path.x, y + path.y, z + path.z); + } +}; +SHAREABLE_STRUCT(sCinemaPath); + +struct sCinemaTrack +{ + Shareable name; + Shareable x, y, z, timescale, duration; + Shareable > paths; + +public: + sCinemaTrack(float rx, float ry, float rz, std::wstring track) + : x(rx), y(ry), z(rz), timescale(1.f), duration(0), name(track) {} + sCinemaTrack() : x(0), y(0), z(0), timescale(1.f), duration(0) {} +}; +SHAREABLE_STRUCT(sCinemaTrack); + +struct eCinemaEventMode { enum { SMOOTH, SELECT, IMMEDIATE_PATH, IMMEDIATE_TRACK }; }; +struct sCameraInfo +{ + Shareable pX, pY, pZ, rX, rY, rZ; // position and rotation +}; +SHAREABLE_STRUCT(sCameraInfo); + + } #endif // SHAREDTYPES_H__ diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp new file mode 100644 index 0000000000..a16f4901b1 --- /dev/null +++ b/source/tools/atlas/GameInterface/View.cpp @@ -0,0 +1,165 @@ +#include "precompiled.h" + +#include "View.h" + +#include "ActorViewer.h" +#include "GameLoop.h" + +#include "ps/Game.h" +#include "ps/GameSetup/GameSetup.h" +#include "simulation/EntityManager.h" +#include "simulation/Simulation.h" + +extern void (*Atlas_GLSwapBuffers)(void* context); + +extern int g_xres, g_yres; + +////////////////////////////////////////////////////////////////////////// + +class ViewNone : public View +{ +public: + virtual void Update(float) { } + virtual void Render() { } + virtual CCamera& GetCamera() { return dummyCamera; } + virtual bool WantsHighFramerate() { return false; } +private: + CCamera dummyCamera; +}; + +////////////////////////////////////////////////////////////////////////// + +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->glContext); +} + +CCamera& ViewActor::GetCamera() +{ + return m_Camera; +} + +bool ViewActor::WantsHighFramerate() +{ + if (m_SpeedMultiplier != 0.f) + return true; + + return false; +} + +void ViewActor::SetSpeedMultiplier(float speed) +{ + m_SpeedMultiplier = speed; +} + +ActorViewer& ViewActor::GetActorViewer() +{ + return *m_ActorViewer; +} + +////////////////////////////////////////////////////////////////////////// + +namespace AtlasMessage +{ + extern void AtlasRenderSelection(); +} + +ViewGame::ViewGame() +{ + debug_assert(g_Game); +} + +void ViewGame::Update(float frameLength) +{ + g_EntityManager.updateAll(0); + g_Game->GetSimulation()->Update(0.0); + + 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->glContext); +} + +CCamera& ViewGame::GetCamera() +{ + return *g_Game->GetView()->GetCamera(); +} + +bool ViewGame::WantsHighFramerate() +{ + if (g_Game->GetView()->GetCinema()->IsPlaying()) + return true; + + return false; +} + +////////////////////////////////////////////////////////////////////////// + +ViewNone* view_None = NULL; +ViewGame* view_Game = NULL; +ViewActor* view_Actor = NULL; + +View::~View() +{ +} + +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; +} diff --git a/source/tools/atlas/GameInterface/View.h b/source/tools/atlas/GameInterface/View.h new file mode 100644 index 0000000000..27c8be808e --- /dev/null +++ b/source/tools/atlas/GameInterface/View.h @@ -0,0 +1,62 @@ +#ifndef VIEW_H__ +#define VIEW_H__ + +class ViewGame; +class ViewActor; + +class View +{ +public: + virtual ~View(); + virtual void Update(float frameLength) = 0; + virtual void Render() = 0; + virtual CCamera& GetCamera() = 0; + virtual bool WantsHighFramerate() = 0; + + // These always return a valid (not NULL) object + static View* GetView_None(); + static ViewGame* GetView_Game(); + static ViewActor* GetView_Actor(); + + // Invalidates any View objects previously returned by this class + static void DestroyViews(); +}; + +////////////////////////////////////////////////////////////////////////// + +class ActorViewer; + +class ViewGame : public View +{ +public: + ViewGame(); + virtual void Update(float frameLength); + virtual void Render(); + virtual CCamera& GetCamera(); + virtual bool WantsHighFramerate(); + +private: +}; + +class ViewActor : public View +{ +public: + ViewActor(); + ~ViewActor(); + + virtual void Update(float frameLength); + virtual void Render(); + virtual CCamera& GetCamera(); + virtual bool WantsHighFramerate(); + + void SetSpeedMultiplier(float speed); + ActorViewer& GetActorViewer(); + +private: + float m_SpeedMultiplier; + CCamera m_Camera; + ActorViewer* m_ActorViewer; +}; + + +#endif // VIEW_H__