From 35e91718c50521fc31b931ce4811186ec067c054 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Mon, 28 Aug 2006 17:36:42 +0000 Subject: [PATCH] # Added tool for viewing models and animations outside the game. Atlas: Added ActorViewer. Moved GL canvas into separate class for shared use. Disabled message-handling callback while blocked on the game, and stopped creating dialog boxes inside the game thread in order to avoid deadlocks (hopefully). Support multiple Views (for independent sets of camera/update/render code). Recalculate territory boundaries when necessary. Changed default list of animations to match those currently used by actors. # Tidied up more code. Moved some more #includes out of .h files, to minimise unnecessary compilation. MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2 (use PI/2), MAX3, ABS (use abs)). ObjectManager: Removed some ScEd-specific things. Unit: Moved creation out of UnitManager, so units can be created without adding to the manager. Changed CStr8 to the more conventional CStr. app_hooks: Removed warning for setting multiple times. win: Restored SEH catcher. GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do what it says it does ("force renderer to load everything") since we're loading-on-demand most stuff and it doesn't seem especially useful since we'd prefer to minimise loading times (but feel free to correct me if I'm wrong). (And because it crashes when things need to be initialised in a different order, so it's easier to remove than to understand and fix it.) PatchRData, Renderer: Work sensibly when there's no game (hence no LOS manager, water, etc). LOSManager: Use entity position instead of actor position when possible. TerritoryManager: Allow delayed recalculations (so Atlas can issue lots of move+recalculate commands per frame). Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to be deleted manually. This was SVN commit r4261. --- binaries/data/tools/atlas/lists.xml | 29 +- binaries/system/ActorViewer.bat | 1 + build/premake/premake.lua | 2 + source/graphics/GameView.cpp | 26 -- source/graphics/GameView.h | 4 - source/graphics/MapReader.cpp | 42 +-- source/graphics/MapWriter.cpp | 2 +- source/graphics/ObjectManager.cpp | 9 +- source/graphics/ObjectManager.h | 15 +- source/graphics/Unit.cpp | 31 +- source/graphics/Unit.h | 30 +- source/graphics/UnitManager.cpp | 21 +- source/graphics/UnitManager.h | 2 +- source/lib/app_hooks.cpp | 1 - source/lib/res/sound/snd_mgr.cpp | 2 +- source/lib/sysdep/win/win.cpp | 4 +- source/main.cpp | 3 + source/maths/MathUtil.h | 30 +- source/maths/Noise.cpp | 2 +- source/ps/GameSetup/GameSetup.cpp | 115 +++---- source/ps/GameSetup/GameSetup.h | 1 + source/ps/Interact.cpp | 28 +- source/ps/KeyName.cpp | 1 - source/renderer/PatchRData.cpp | 62 ++-- source/renderer/Renderer.cpp | 17 +- source/renderer/SkyManager.cpp | 2 +- source/renderer/TerrainRenderer.cpp | 8 +- source/scripting/ScriptGlue.cpp | 1 + source/scripting/ScriptableComplex.h | 8 +- source/scripting/ScriptableComplex.inl | 1 + source/simulation/Collision.cpp | 1 + source/simulation/Entity.cpp | 64 ++-- source/simulation/Entity.h | 7 +- source/simulation/EntityManager.cpp | 1 + source/simulation/EntityManager.h | 3 +- source/simulation/EntityStateProcessing.cpp | 3 +- source/simulation/EntitySupport.h | 1 - source/simulation/EntityTemplate.h | 5 +- .../simulation/EntityTemplateCollection.cpp | 1 + source/simulation/EntityTemplateCollection.h | 6 +- source/simulation/LOSManager.cpp | 14 +- source/simulation/PathfindEngine.cpp | 1 + source/simulation/TerritoryManager.cpp | 23 +- source/simulation/TerritoryManager.h | 6 +- .../atlas/AtlasUI/ActorViewer/ActorViewer.cpp | 299 ++++++++++++++++++ .../atlas/AtlasUI/ActorViewer/ActorViewer.h | 29 ++ .../AtlasUI/CustomControls/Canvas/Canvas.cpp | 88 ++++++ .../AtlasUI/CustomControls/Canvas/Canvas.h | 24 ++ .../atlas/AtlasUI/General/AtlasEventLoop.cpp | 4 + .../atlas/AtlasUI/General/AtlasEventLoop.h | 5 + .../tools/atlas/AtlasUI/General/Observable.h | 1 + .../tools/atlas/AtlasUI/Misc/DLLInterface.cpp | 41 ++- .../tools/atlas/AtlasUI/Misc/DLLInterface.h | 4 +- .../AtlasUI/ScenarioEditor/ScenarioEditor.cpp | 233 +++++--------- .../AtlasUI/ScenarioEditor/ScenarioEditor.h | 2 + .../Sections/Cinematic/Cinematic.cpp | 22 +- .../Sections/Environment/Environment.cpp | 23 +- .../Sections/Environment/Environment.h | 2 +- .../Sections/Environment/LightControl.cpp | 25 +- .../Sections/Environment/LightControl.h | 2 +- .../ScenarioEditor/Tools/PlaceObject.cpp | 8 +- .../tools/atlas/GameInterface/ActorViewer.cpp | 190 +++++++++++ .../tools/atlas/GameInterface/ActorViewer.h | 22 ++ source/tools/atlas/GameInterface/Brushes.h | 5 + .../tools/atlas/GameInterface/CommandProc.h | 5 + source/tools/atlas/GameInterface/GameLoop.cpp | 96 +++--- source/tools/atlas/GameInterface/GameLoop.h | 9 +- .../GameInterface/Handlers/BrushHandlers.cpp | 2 +- .../Handlers/CameraCtrlHandlers.cpp | 48 ++- .../Handlers/ElevationHandlers.cpp | 4 +- .../Handlers/EnvironmentHandlers.cpp | 5 +- .../Handlers/GraphicsSetupHandlers.cpp | 31 +- .../GameInterface/Handlers/MapHandlers.cpp | 2 - .../GameInterface/Handlers/ObjectHandlers.cpp | 39 ++- .../Handlers/TerrainHandlers.cpp | 2 +- .../atlas/GameInterface/InputProcessor.h | 5 + .../atlas/GameInterface/MessagePasserImpl.cpp | 62 ++-- source/tools/atlas/GameInterface/Messages.h | 98 ++---- .../tools/atlas/GameInterface/MessagesSetup.h | 3 - source/tools/atlas/GameInterface/Misc.cpp | 24 +- source/tools/atlas/GameInterface/Register.cpp | 2 - source/tools/atlas/GameInterface/Shareable.h | 4 +- .../tools/atlas/GameInterface/SharedTypes.h | 65 +++- source/tools/atlas/GameInterface/View.cpp | 165 ++++++++++ source/tools/atlas/GameInterface/View.h | 62 ++++ 85 files changed, 1665 insertions(+), 733 deletions(-) create mode 100644 binaries/system/ActorViewer.bat create mode 100644 source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.cpp create mode 100644 source/tools/atlas/AtlasUI/ActorViewer/ActorViewer.h create mode 100644 source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.cpp create mode 100644 source/tools/atlas/AtlasUI/CustomControls/Canvas/Canvas.h create mode 100644 source/tools/atlas/GameInterface/ActorViewer.cpp create mode 100644 source/tools/atlas/GameInterface/ActorViewer.h create mode 100644 source/tools/atlas/GameInterface/View.cpp create mode 100644 source/tools/atlas/GameInterface/View.h 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__