diff --git a/binaries/data/mods/public/simulation/templates/other/bridge_hele.xml b/binaries/data/mods/public/simulation/templates/other/bridge_hele.xml index 33dcbb3272..f7ae8243b6 100644 --- a/binaries/data/mods/public/simulation/templates/other/bridge_hele.xml +++ b/binaries/data/mods/public/simulation/templates/other/bridge_hele.xml @@ -20,7 +20,9 @@ - + + + 72 true diff --git a/binaries/data/mods/public/simulation/templates/other/bridge_wooden.xml b/binaries/data/mods/public/simulation/templates/other/bridge_wooden.xml index 7021a4fd36..514ff7153e 100644 --- a/binaries/data/mods/public/simulation/templates/other/bridge_wooden.xml +++ b/binaries/data/mods/public/simulation/templates/other/bridge_wooden.xml @@ -20,7 +20,9 @@ - + + + 72 true diff --git a/binaries/data/mods/public/simulation/templates/special/territory_block.xml b/binaries/data/mods/public/simulation/templates/special/territory_block.xml index d63567770d..52432b26b4 100644 --- a/binaries/data/mods/public/simulation/templates/special/territory_block.xml +++ b/binaries/data/mods/public/simulation/templates/special/territory_block.xml @@ -21,7 +21,9 @@ false 6.0 - + + + 64 false diff --git a/binaries/data/mods/public/simulation/templates/special/territory_pull.xml b/binaries/data/mods/public/simulation/templates/special/territory_pull.xml index ebc95e2971..bd8c4acafe 100644 --- a/binaries/data/mods/public/simulation/templates/special/territory_pull.xml +++ b/binaries/data/mods/public/simulation/templates/special/territory_pull.xml @@ -21,7 +21,9 @@ false 6.0 - + + + 0 false diff --git a/binaries/data/mods/public/simulation/templates/template_entity_quasi.xml b/binaries/data/mods/public/simulation/templates/template_entity_quasi.xml index f85ed76bae..5f702c5086 100644 --- a/binaries/data/mods/public/simulation/templates/template_entity_quasi.xml +++ b/binaries/data/mods/public/simulation/templates/template_entity_quasi.xml @@ -8,4 +8,7 @@ false 6.0 + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml index 51f170307e..e979c8ed9b 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml @@ -16,7 +16,9 @@ 200 food.fruit - + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml index d0018d15da..bb74672b0f 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml @@ -15,7 +15,9 @@ 200 wood.tree - + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml index c190a98b21..f3a147ae96 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml @@ -15,7 +15,9 @@ 1000 metal.ore - + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml index 4f419c05d4..a9542935e5 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml @@ -15,7 +15,9 @@ 1000 stone.rock - + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml b/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml index 6af1b86399..86037bbc57 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml @@ -22,5 +22,7 @@ 500 stone.ruins - + + + diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml b/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml index 6a734878ae..cb45f0a093 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml @@ -22,5 +22,7 @@ 300 treasure.metal - + + + diff --git a/source/graphics/UnitManager.cpp b/source/graphics/UnitManager.cpp index 11a460cc44..7d866eb683 100644 --- a/source/graphics/UnitManager.cpp +++ b/source/graphics/UnitManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -85,42 +85,6 @@ void CUnitManager::DeleteAll() m_Units.clear(); } - -/////////////////////////////////////////////////////////////////////////////// -// PickUnit: iterate through units testing given ray against bounds of each -// unit; return the closest unit, or null if everything missed -CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) const -{ - // closest object found so far - CUnit* hit = 0; - // closest approach offset (easier to pick small stuff in forests than standard ScEd style selection) - float minrel = FLT_MAX; - - for (size_t i=0; iGetModel().GetSelectionBox(); - if (selectionBox.RayIntersect(origin, dir, tmin, tmax)) - { - // Point of closest approach - // TODO: this next bit is virtually identical to Selection::PickEntitiesAtPoint; might be useful to factor it out and - // reuse it - CVector3D delta = selectionBox.m_Center - origin; - float distance = delta.Dot(dir); - CVector3D closest = origin + dir * distance; - CVector3D offset = selectionBox.m_Center - closest; - - float rel = offset.Length(); - if (rel < minrel) { - hit = unit; - minrel = rel; - } - } - } - return hit; -} - /////////////////////////////////////////////////////////////////////////////// // CreateUnit: create a new unit and add it to the world CUnit* CUnitManager::CreateUnit(const CStrW& actorName, uint32_t seed, const std::set& selections) diff --git a/source/graphics/UnitManager.h b/source/graphics/UnitManager.h index 7bbcc7c4b8..2b5252c1df 100644 --- a/source/graphics/UnitManager.h +++ b/source/graphics/UnitManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -55,10 +55,6 @@ public: // return the units const std::vector& GetUnits() const { return m_Units; } - // iterate through units testing given ray against bounds of each unit; - // return the closest unit, or null if everything missed - CUnit* PickUnit(const CVector3D& origin, const CVector3D& dir) const; - void SetObjectManager(CObjectManager& objectManager) { m_ObjectManager = &objectManager; } private: diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 38ad32224a..bd4b30fe8e 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -128,17 +128,17 @@ void PostNetworkCommand(void* cbdata, CScriptVal cmd) std::vector PickEntitiesAtPoint(void* UNUSED(cbdata), int x, int y) { - return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID()); + return EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, g_Game->GetPlayerID(), false); } std::vector PickFriendlyEntitiesInRect(void* UNUSED(cbdata), int x0, int y0, int x1, int y1, int player) { - return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player); + return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player, false); } std::vector PickSimilarFriendlyEntities(void* UNUSED(cbdata), std::string templateName, bool includeOffScreen, bool matchRank) { - return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), includeOffScreen, matchRank); + return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), includeOffScreen, matchRank, false); } CFixedVector3D GetTerrainAtPoint(void* UNUSED(cbdata), int x, int y) diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index 48d2de8a33..5dcefd47cb 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -99,6 +99,10 @@ #include "ps/GameSetup/CmdLineArgs.h" #include "ps/GameSetup/HWDetect.h" +#include "tools/atlas/GameInterface/GameLoop.h" +#include "tools/atlas/GameInterface/View.h" + + #if !(OS_WIN || OS_MACOSX || OS_ANDROID) // assume all other platforms use X11 for wxWidgets #define MUST_INIT_X11 1 #include @@ -232,6 +236,13 @@ void Render() ogl_WarnIfError(); + // If we're in Atlas game view, render special overlays (e.g. editor bandbox) + if (g_GameLoop && g_GameLoop->view) + { + g_GameLoop->view->DrawOverlays(); + ogl_WarnIfError(); + } + // Text: glDisable(GL_DEPTH_TEST); diff --git a/source/simulation2/components/CCmpSelectable.cpp b/source/simulation2/components/CCmpSelectable.cpp index fdf715897c..a936d91daf 100644 --- a/source/simulation2/components/CCmpSelectable.cpp +++ b/source/simulation2/components/CCmpSelectable.cpp @@ -48,6 +48,7 @@ public: SOverlayLine m_Overlay; SOverlayLine* m_DebugBoundingBoxOverlay; SOverlayLine* m_DebugSelectionBoxOverlay; + bool m_EditorOnly; CCmpSelectable() : m_DebugBoundingBoxOverlay(NULL), m_DebugSelectionBoxOverlay(NULL) @@ -66,11 +67,16 @@ public: return "Allows this entity to be selected by the player." "" - ""; + "" + "" + "" + "" + ""; } - virtual void Init(const CParamNode& UNUSED(paramNode)) + virtual void Init(const CParamNode& paramNode) { + m_EditorOnly = paramNode.GetChild("EditorOnly").IsOk(); } virtual void Deinit() @@ -112,6 +118,11 @@ public: } } + virtual bool IsEditorOnly() + { + return m_EditorOnly; + } + virtual void SetSelectionHighlight(CColor color) { m_Overlay.m_Color = color; diff --git a/source/simulation2/components/CCmpTemplateManager.cpp b/source/simulation2/components/CCmpTemplateManager.cpp index cfa7bc7593..d5129342f4 100644 --- a/source/simulation2/components/CCmpTemplateManager.cpp +++ b/source/simulation2/components/CCmpTemplateManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -369,9 +369,9 @@ void CCmpTemplateManager::ConstructTemplateActor(const std::string& actorName, C // Copy the actor template out = m_TemplateFileData[templateName]; - // Initialise the actor's name + // Initialise the actor's name and make it an Atlas selectable entity. std::string name = utf8_from_wstring(CParamNode::EscapeXMLString(wstring_from_utf8(actorName))); - std::string xml = "" + name + ""; + std::string xml = "" + name + ""; CParamNode::LoadXMLString(out, xml.c_str()); } diff --git a/source/simulation2/components/ICmpSelectable.h b/source/simulation2/components/ICmpSelectable.h index b8b55d0c26..c7c8ec2436 100644 --- a/source/simulation2/components/ICmpSelectable.h +++ b/source/simulation2/components/ICmpSelectable.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -25,6 +25,11 @@ struct CColor; class ICmpSelectable : public IComponent { public: + /** + * Returns true if the entity is only selectable in Atlas editor, e.g. a decorative visual actor. + */ + virtual bool IsEditorOnly() = 0; + /** * Set the color of the selection highlight (typically a circle/square * around the unit). Set a = 0 to disable. diff --git a/source/simulation2/helpers/Selection.cpp b/source/simulation2/helpers/Selection.cpp index 84077508e3..28ea73640b 100644 --- a/source/simulation2/helpers/Selection.cpp +++ b/source/simulation2/helpers/Selection.cpp @@ -28,7 +28,7 @@ #include "simulation2/components/ICmpSelectable.h" #include "simulation2/components/ICmpVisual.h" -std::vector EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, int player) +std::vector EntitySelection::PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables) { CVector3D origin, dir; camera.BuildCameraRay(screenX, screenY, origin, dir); @@ -43,6 +43,10 @@ std::vector EntitySelection::PickEntitiesAtPoint(CSimulation2& simu { entity_id_t ent = it->first; + // Check if this entity is only selectable in Atlas + if (static_cast(it->second)->IsEditorOnly() && !allowEditorSelectables) + continue; + // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld) if (cmpRangeManager->GetLosVisibility(ent, player) == ICmpRangeManager::VIS_HIDDEN) continue; @@ -51,18 +55,39 @@ std::vector EntitySelection::PickEntitiesAtPoint(CSimulation2& simu if (!cmpVisual) continue; + CVector3D center; + float tmin, tmax; + CBoundingBoxOriented selectionBox = cmpVisual->GetSelectionBox(); if (selectionBox.IsEmpty()) - continue; + { + if (!allowEditorSelectables) + continue; - float tmin, tmax; - if (!selectionBox.RayIntersect(origin, dir, tmin, tmax)) - continue; + // Fall back to using old AABB selection method for decals + // see: http://trac.wildfiregames.com/ticket/1032 + CBoundingBoxAligned aABBox = cmpVisual->GetBounds(); + if (aABBox.IsEmpty()) + continue; + + if (!aABBox.RayIntersect(origin, dir, tmin, tmax)) + continue; + + aABBox.GetCentre(center); + } + else + { + if (!selectionBox.RayIntersect(origin, dir, tmin, tmax)) + continue; + + center = selectionBox.m_Center; + } // Find the perpendicular distance from the object's centre to the picker ray - CVector3D closest = origin + dir * (selectionBox.m_Center - origin).Dot(dir); - float dist2 = (closest - selectionBox.m_Center).LengthSquared(); + float dist2; + CVector3D closest = origin + dir * (center - origin).Dot(dir); + dist2 = (closest - center).LengthSquared(); hits.push_back(std::make_pair(dist2, ent)); } @@ -78,7 +103,7 @@ std::vector EntitySelection::PickEntitiesAtPoint(CSimulation2& simu return hitEnts; } -std::vector EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner) +std::vector EntitySelection::PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables) { // Make sure sx0 <= sx1, and sy0 <= sy1 if (sx0 > sx1) @@ -96,13 +121,17 @@ std::vector EntitySelection::PickEntitiesInRect(CSimulation2& simul { entity_id_t ent = it->first; + // Check if this entity is only selectable in Atlas + if (static_cast(it->second)->IsEditorOnly() && !allowEditorSelectables) + continue; + // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld) if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN) continue; // Ignore entities not owned by 'owner' CmpPtr cmpOwnership(simulation.GetSimContext(), ent); - if (!cmpOwnership || cmpOwnership->GetOwner() != owner) + if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner)) continue; // Find the current interpolated model position. @@ -132,7 +161,7 @@ std::vector EntitySelection::PickEntitiesInRect(CSimulation2& simul return hitEnts; } -std::vector EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, const std::string& templateName, int owner, bool includeOffScreen, bool matchRank) +std::vector EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank, bool allowEditorSelectables) { CmpPtr cmpTemplateManager(simulation, SYSTEM_ENTITY); CmpPtr cmpRangeManager(simulation, SYSTEM_ENTITY); @@ -144,6 +173,10 @@ std::vector EntitySelection::PickSimilarEntities(CSimulation2& simu { entity_id_t ent = it->first; + // Check if this entity is only selectable in Atlas + if (static_cast(it->second)->IsEditorOnly() && !allowEditorSelectables) + continue; + if (matchRank) { // Exact template name matching @@ -156,14 +189,14 @@ std::vector EntitySelection::PickSimilarEntities(CSimulation2& simu if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN) continue; - // Ignore entities not owned by 'owner' - CmpPtr cmpOwnership(simulation.GetSimContext(), ent); - if (!cmpOwnership || cmpOwnership->GetOwner() != owner) - continue; + // Ignore entities not owned by 'owner' + CmpPtr cmpOwnership(simulation.GetSimContext(), ent); + if (owner != INVALID_PLAYER && (!cmpOwnership || cmpOwnership->GetOwner() != owner)) + continue; // Ignore off screen entities - if (!includeOffScreen) - { + if (!includeOffScreen) + { // Find the current interpolated model position. CmpPtr cmpVisual(simulation.GetSimContext(), ent); if (!cmpVisual) @@ -173,7 +206,7 @@ std::vector EntitySelection::PickSimilarEntities(CSimulation2& simu // Reject if it's not on-screen (e.g. it's behind the camera) if (!camera.GetFrustum().IsPointVisible(position)) continue; - } + } if (!matchRank) { diff --git a/source/simulation2/helpers/Selection.h b/source/simulation2/helpers/Selection.h index 16688bf14c..54a700f557 100644 --- a/source/simulation2/helpers/Selection.h +++ b/source/simulation2/helpers/Selection.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,7 @@ */ #include "simulation2/system/Entity.h" +#include "Player.h" #include @@ -37,24 +38,33 @@ namespace EntitySelection * Finds all selectable entities under the given screen coordinates. * Returns list ordered by closeness of picking, closest first. * Restricted to entities in the LOS of @p player, but with any owner. + * (For Atlas selections this value is ignored as the whole map is revealed). + * If @p allowEditorSelectables then all entities with the IID_Selectable interface + * will be selected, else only selectable entities without the EditorOnly flag set. */ -std::vector PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, int player); +std::vector PickEntitiesAtPoint(CSimulation2& simulation, const CCamera& camera, int screenX, int screenY, player_id_t player, bool allowEditorSelectables); /** * Finds all selectable entities within the given screen coordinate rectangle, * that belong to player @p owner. + * If @p owner is INVALID_PLAYER then ownership is ignored. + * If @p allowEditorSelectables then all entities with the IID_Selectable interface + * will be selected, else only selectable entities without the EditorOnly flag set. * Returns unordered list. */ -std::vector PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner); +std::vector PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, player_id_t owner, bool allowEditorSelectables); /** * Finds all entities with the given entity template name, that belong to player @p owner. + * If @p owner is INVALID_PLAYER then ownership is ignored. * If @p includeOffScreen then all entities visible in the world will be selected, * else only entities visible on the screen will be selected. * If @p matchRank then only entities that exactly match @p templateName will be selected, * else entities with matching SelectionGroupName will be selected. + * If @p allowEditorSelectables then all entities with the IID_Selectable interface + * will be selected, else only selectable entities without the EditorOnly flag set. */ -std::vector PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, const std::string& templateName, int owner, bool includeOffScreen, bool matchRank); +std::vector PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, const std::string& templateName, player_id_t owner, bool includeOffScreen, bool matchRank, bool allowEditorSelectables); } // namespace diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp index e33236345d..7b1c645632 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,9 +31,16 @@ class TransformObject : public StateDrivenTool DECLARE_DYNAMIC_CLASS(TransformObject); int m_dx, m_dy; + AtlasMessage::ObjectID m_lastSelected; + wxPoint m_startPoint; + + // TODO: If we don't plan to change hotkeys, just replace with evt.ShiftDown(), etc. + static const wxKeyCode SELECTION_ADD_HOTKEY = WXK_SHIFT; + static const wxKeyCode SELECTION_REMOVE_HOTKEY = WXK_CONTROL; // COMMAND on Macs + static const wxKeyCode SELECTION_ACTORS_HOTKEY = WXK_ALT; public: - TransformObject() + TransformObject() : m_lastSelected(0) { SetState(&Waiting); } @@ -52,37 +59,77 @@ public: { bool OnMouse(TransformObject* obj, wxMouseEvent& evt) { - if (evt.LeftDown()) + if (evt.LeftDClick() && AtlasMessage::ObjectIDIsValid(obj->m_lastSelected)) { + SET_STATE(SelectSimilar); + return true; + } + else if (evt.LeftDown()) + { + bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY); + bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY); + bool selectionActors = wxGetKeyState(SELECTION_ACTORS_HOTKEY); + // New selection - never merge with movements of other objects ScenarioEditor::GetCommandProc().FinaliseLastCommand(); // Select the object clicked on: - AtlasMessage::qPickObject qry(Position(evt.GetPosition())); + AtlasMessage::qPickObject qry(Position(evt.GetPosition()), selectionActors); qry.Post(); - // TODO: handle multiple selections - g_SelectedObjects.clear(); - // Check they actually clicked on a valid object if (AtlasMessage::ObjectIDIsValid(qry.id)) { - g_SelectedObjects.push_back(qry.id); - // Remember the screen-space offset of the mouse from the - // object's centre, so we can add that back when moving it - // (instead of just moving the object's centre to directly - // beneath the mouse) - obj->m_dx = qry.offsetx; - obj->m_dy = qry.offsety; - SET_STATE(Dragging); + std::vector::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), qry.id); + bool objectIsSelected = (it != g_SelectedObjects.end()); + + if (selectionRemove) + { + // Remove from selection + if (objectIsSelected) + g_SelectedObjects.erase(it); + } + else if (!objectIsSelected) + { + // Add to selection + if (!selectionAdd) + g_SelectedObjects.clear(); + + g_SelectedObjects.push_back(qry.id); + } + + obj->m_lastSelected = qry.id; + + // If we're selecting the whole group + if (!selectionAdd && !selectionRemove && !g_SelectedObjects.empty()) + { + // Remember the screen-space offset of the mouse from the + // object's centre, so we can add that back when moving it + // (instead of just moving the object's centre to directly + // beneath the mouse) + obj->m_dx = qry.offsetx; + obj->m_dy = qry.offsety; + SET_STATE(Dragging); + } + + g_SelectedObjects.NotifyObservers(); + POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); } - g_SelectedObjects.NotifyObservers(); - POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); + else + { + // Bandboxing + obj->m_lastSelected = 0; + obj->m_startPoint = evt.GetPosition(); + SET_STATE(Bandboxing); + } + return true; } - else if ((evt.Dragging() && evt.RightIsDown()) || evt.RightDown()) + else if (g_SelectedObjects.size() == 1 && ((evt.Dragging() && evt.RightIsDown()) || evt.RightDown())) { + // TODO: Rotation of selections with multiple objects? + // Dragging with right mouse button -> rotate objects to look // at mouse Position pos (evt.GetPosition()); @@ -91,6 +138,12 @@ public: return true; } + else if (evt.Moving()) + { + // Prevent certain events from reaching game UI in this mode + // to prevent selection ring confusion + return true; + } else return false; } @@ -132,8 +185,23 @@ public: else if (evt.Dragging()) { Position pos (evt.GetPosition() + wxPoint(obj->m_dx, obj->m_dy)); - for (size_t i = 0; i < g_SelectedObjects.size(); ++i) - POST_COMMAND(MoveObject, (g_SelectedObjects[i], pos)); + + POST_COMMAND(MoveObjects, (g_SelectedObjects, obj->m_lastSelected, pos)); + return true; + } + else + return false; + } + + bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type) + { + if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE) + { + // Cancel move action + ScenarioEditor::GetCommandProc().FinaliseLastCommand(); + ScenarioEditor::GetCommandProc().Undo(); + SET_STATE(Waiting); + return true; } else @@ -141,6 +209,132 @@ public: } } Dragging; + + struct sBandboxing : public State + { + bool OnMouse(TransformObject* obj, wxMouseEvent& evt) + { + if (evt.LeftIsDown() && evt.Dragging()) + { + // Update bandbox overlay + POST_MESSAGE(SetBandbox, (true, obj->m_startPoint.x, obj->m_startPoint.y, evt.GetPosition().x, evt.GetPosition().y)); + return true; + } + else if (evt.LeftUp()) + { + bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY); + bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY); + bool selectionActors = wxGetKeyState(SELECTION_ACTORS_HOTKEY); + + // Now we have both corners of the box, pick objects + AtlasMessage::qPickObjectsInRect qry(Position(obj->m_startPoint), Position(evt.GetPosition()), selectionActors); + qry.Post(); + + std::vector ids = *qry.ids; + + if (!selectionAdd && !selectionRemove) + { + // Just copy new selections (clears list if no selections) + g_SelectedObjects = ids; + } + else + { + for (size_t i = 0; i < ids.size(); ++i) + { + std::vector::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), ids[i]); + bool objectIsSelected = (it != g_SelectedObjects.end()); + if (selectionRemove) + { + // Remove from selection + if (objectIsSelected) + g_SelectedObjects.erase(it); + } + else if (!objectIsSelected) + { + // Add to selection + g_SelectedObjects.push_back(ids[i]); + } + } + } + + POST_MESSAGE(SetBandbox, (false, 0, 0, 0, 0)); + + g_SelectedObjects.NotifyObservers(); + POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); + + SET_STATE(Waiting); + return true; + } + else + return false; + } + + bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type) + { + if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE) + { + // Clear bandbox and return to waiting state + POST_MESSAGE(SetBandbox, (false, 0, 0, 0, 0)); + SET_STATE(Waiting); + return true; + } + else + return false; + } + } + Bandboxing; + + struct sSelectSimilar : public State + { + bool OnMouse(TransformObject* obj, wxMouseEvent& evt) + { + if (evt.LeftUp()) + { + bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY); + bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY); + + // Select similar objects + AtlasMessage::qPickSimilarObjects qry(obj->m_lastSelected); + qry.Post(); + + std::vector ids = *qry.ids; + + if (!selectionAdd && !selectionRemove) + { + // Just copy new selections (clears list if no selections) + g_SelectedObjects = ids; + } + else + { + for (size_t i = 0; i < ids.size(); ++i) + { + std::vector::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), ids[i]); + bool objectIsSelected = (it != g_SelectedObjects.end()); + if (selectionRemove) + { + // Remove from selection + if (objectIsSelected) + g_SelectedObjects.erase(it); + } + else if (!objectIsSelected) + { + // Add to selection + g_SelectedObjects.push_back(ids[i]); + } + } + } + + g_SelectedObjects.NotifyObservers(); + POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); + + SET_STATE(Waiting); + return true; + } + else + return false; + } + } + SelectSimilar; }; IMPLEMENT_DYNAMIC_CLASS(TransformObject, StateDrivenTool); diff --git a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp index 1a0bb6b788..1eb46be19c 100644 --- a/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp +++ b/source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp @@ -18,6 +18,7 @@ #include "precompiled.h" #include +#include #include "MessageHandler.h" #include "../CommandProc.h" @@ -31,7 +32,6 @@ #include "graphics/ObjectManager.h" #include "graphics/Terrain.h" #include "graphics/Unit.h" -#include "graphics/UnitManager.h" #include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Matrix3D.h" @@ -43,8 +43,11 @@ #include "simulation2/Simulation2.h" #include "simulation2/components/ICmpOwnership.h" #include "simulation2/components/ICmpPosition.h" +#include "simulation2/components/ICmpPlayer.h" +#include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/components/ICmpSelectable.h" #include "simulation2/components/ICmpTemplateManager.h" +#include "simulation2/helpers/Selection.h" namespace AtlasMessage { @@ -55,22 +58,6 @@ namespace { return wcscmp(a.name.c_str(), b.name.c_str()) < 0; } - - bool IsFloating(const CUnit* unit) - { - if (! unit) - return false; - - CmpPtr cmpPosition(*g_Game->GetSimulation2(), unit->GetID()); - if (!cmpPosition) - return false; - return cmpPosition->IsFloating(); - } - - CUnitManager& GetUnitManager() - { - return g_Game->GetWorld()->GetUnitManager(); - } } QUERYHANDLER(GetObjectsList) @@ -111,20 +98,57 @@ static std::vector g_Selection; MESSAGEHANDLER(SetSelectionPreview) { + CSimulation2& sim = *g_Game->GetSimulation2(); + + // Cache player colours for performance + typedef std::map PlayerColourMap; + PlayerColourMap playerColours; + + CmpPtr cmpPlayerManager(sim, SYSTEM_ENTITY); + + // Clear old selection rings for (size_t i = 0; i < g_Selection.size(); ++i) { - CmpPtr cmpSelectable(*g_Game->GetSimulation2(), g_Selection[i]); + CmpPtr cmpSelectable(sim, g_Selection[i]); if (cmpSelectable) cmpSelectable->SetSelectionHighlight(CColor(1, 1, 1, 0)); } g_Selection = *msg->ids; + // Set new selection rings for (size_t i = 0; i < g_Selection.size(); ++i) { - CmpPtr cmpSelectable(*g_Game->GetSimulation2(), g_Selection[i]); - if (cmpSelectable) - cmpSelectable->SetSelectionHighlight(CColor(1, 1, 1, 1)); + entity_id_t ent = g_Selection[i]; + CmpPtr cmpSelectable(sim, ent); + if (!cmpSelectable) + continue; + + // Default to white for ownerless entities + CColor colour(1.0f, 1.0f, 1.0f, 1.0f); + + CmpPtr cmpOwnership(sim, ent); + if (cmpOwnership && cmpPlayerManager) + { + player_id_t owner = cmpOwnership->GetOwner(); + if (playerColours.find(owner) != playerColours.end()) + { + colour = playerColours[owner]; + } + else + { + // Add colour to cache + entity_id_t playerEnt = cmpPlayerManager->GetPlayerByID(owner); + CmpPtr cmpPlayer(sim, playerEnt); + if (cmpPlayer) + { + colour = cmpPlayer->GetColour(); + playerColours[owner] = colour; + } + } + } + + cmpSelectable->SetSelectionHighlight(colour); } } @@ -401,71 +425,129 @@ QUERYHANDLER(PickObject) float x, y; msg->pos->GetScreenSpace(x, y); - CVector3D rayorigin, raydir; - g_Game->GetView()->GetCamera()->BuildCameraRay((int)x, (int)y, rayorigin, raydir); + // Normally this function would be called with a player ID to check LOS, + // but in Atlas the entire map is revealed, so just pass INVALID_PLAYER + std::vector ents = EntitySelection::PickEntitiesAtPoint(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x, y, INVALID_PLAYER, msg->selectActors); - CUnit* target = GetUnitManager().PickUnit(rayorigin, raydir); - - if (target) - msg->id = target->GetID(); - else - msg->id = INVALID_ENTITY; - - if (target) + // Multiple entities may have been picked, but they are sorted by distance, + // so only take the first one + if (!ents.empty()) { - // Get screen coordinates of the point on the ground underneath the - // object's model-centre, so that callers know the offset to use when - // working out the screen coordinates to move the object to. - - CVector3D centre = target->GetModel().GetTransform().GetTranslation(); + msg->id = ents[0]; - centre.Y = g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel(centre.X, centre.Z); - if (IsFloating(target)) - centre.Y = std::max(centre.Y, g_Renderer.GetWaterManager()->m_WaterHeight); + // Calculate offset of object from original mouse click position + // so it gets moved by that offset + CmpPtr cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)ents[0]); + if (!cmpPosition || !cmpPosition->IsInWorld()) + { + // error + msg->offsetx = msg->offsety = 0; + } + else + { + CFixedVector3D fixed = cmpPosition->GetPosition(); + CVector3D centre = CVector3D(fixed.X.ToFloat(), fixed.Y.ToFloat(), fixed.Z.ToFloat()); - float cx, cy; - g_Game->GetView()->GetCamera()->GetScreenCoordinates(centre, cx, cy); + float cx, cy; + g_Game->GetView()->GetCamera()->GetScreenCoordinates(centre, cx, cy); - msg->offsetx = (int)(cx - x); - msg->offsety = (int)(cy - y); + msg->offsetx = (int)(cx - x); + msg->offsety = (int)(cy - y); + } } else { - msg->offsetx = msg->offsety = 0; + // No entity picked + msg->id = INVALID_ENTITY; } } -BEGIN_COMMAND(MoveObject) +QUERYHANDLER(PickObjectsInRect) { - CVector3D m_PosOld, m_PosNew; + float x0, y0, x1, y1; + msg->start->GetScreenSpace(x0, y0); + msg->end->GetScreenSpace(x1, y1); + + // Since owner selections are meaningless in Atlas, use INVALID_PLAYER + msg->ids = EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, INVALID_PLAYER, msg->selectActors); +} + + +QUERYHANDLER(PickSimilarObjects) +{ + CmpPtr cmpTemplateManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY); + ENSURE(cmpTemplateManager); + std::string templateName = cmpTemplateManager->GetCurrentTemplateName((entity_id_t)msg->id); + + // Since owner selections are meaningless in Atlas, use INVALID_PLAYER + msg->ids = EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, INVALID_PLAYER, false, true, true); +} + + +BEGIN_COMMAND(MoveObjects) +{ + // Mapping from object to position + typedef std::map ObjectPositionMap; + ObjectPositionMap m_PosOld, m_PosNew; void Do() { - CmpPtr cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)msg->id); - if (!cmpPosition) - { - // error - m_PosOld = m_PosNew = CVector3D(0, 0, 0); - } - else - { - m_PosNew = GetUnitPos(msg->pos, cmpPosition->IsFloating()); + std::vector ids = *msg->ids; - CFixedVector3D pos = cmpPosition->GetPosition(); - m_PosOld = CVector3D(pos.X.ToFloat(), pos.Y.ToFloat(), pos.Z.ToFloat()); + // All selected objects move relative to a pivot object, + // so get its position and whether it's floating + CVector3D pivotPos(0, 0, 0); + bool pivotFloating = false; + + CmpPtr cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)msg->pivot); + if (cmpPosition && cmpPosition->IsInWorld()) + { + pivotFloating = cmpPosition->IsFloating(); + CFixedVector3D pivotFixed = cmpPosition->GetPosition(); + pivotPos = CVector3D(pivotFixed.X.ToFloat(), pivotFixed.Y.ToFloat(), pivotFixed.Z.ToFloat()); + } + + // Calculate directional vector of movement for pivot object, + // we apply the same movement to all objects + CVector3D targetPos = GetUnitPos(msg->pos, pivotFloating); + CVector3D dir = targetPos - pivotPos; + + for (size_t i = 0; i < ids.size(); ++i) + { + entity_id_t id = (entity_id_t)ids[i]; + CmpPtr cmpPosition(*g_Game->GetSimulation2(), id); + if (!cmpPosition || !cmpPosition->IsInWorld()) + { + // error + m_PosOld[id] = m_PosNew[id] = CVector3D(0, 0, 0); + } + else + { + // Calculate this object's position + CFixedVector3D posFixed = cmpPosition->GetPosition(); + CVector3D pos = CVector3D(posFixed.X.ToFloat(), posFixed.Y.ToFloat(), posFixed.Z.ToFloat()); + m_PosNew[id] = pos + dir; + m_PosOld[id] = pos; + } } SetPos(m_PosNew); } - void SetPos(CVector3D& pos) + void SetPos(ObjectPositionMap& map) { - CmpPtr cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)msg->id); - if (!cmpPosition) - return; + ObjectPositionMap::iterator it; + for (it = map.begin(); it != map.end(); ++it) + { + CmpPtr cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)it->first); + if (!cmpPosition) + return; - cmpPosition->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z)); + // Set 2D position, ignoring height + CVector3D pos = it->second; + cmpPosition->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z)); + } } void Redo() @@ -478,14 +560,14 @@ BEGIN_COMMAND(MoveObject) SetPos(m_PosOld); } - void MergeIntoPrevious(cMoveObject* prev) + void MergeIntoPrevious(cMoveObjects* prev) { - // TODO: do something valid if prev unit != this unit - ENSURE(prev->msg->id == msg->id); + // TODO: do something valid if prev selection != this selection + ENSURE(*(prev->msg->ids) == *(msg->ids)); prev->m_PosNew = m_PosNew; } }; -END_COMMAND(MoveObject) +END_COMMAND(MoveObjects) BEGIN_COMMAND(RotateObject) @@ -645,4 +727,9 @@ QUERYHANDLER(GetPlayerObjects) msg->ids = ids; } +MESSAGEHANDLER(SetBandbox) +{ + View::GetView_Game()->SetBandbox(msg->show, (float)msg->sx0, (float)msg->sy0, (float)msg->sx1, (float)msg->sy1); +} + } diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h index 307529a039..f507d7ae11 100644 --- a/source/tools/atlas/GameInterface/Messages.h +++ b/source/tools/atlas/GameInterface/Messages.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -484,15 +484,31 @@ COMMAND(FillTerrain, NOMERGE, ////////////////////////////////////////////////////////////////////////// QUERY(PickObject, - ((Position, pos)) - , - ((ObjectID, id)) - ((int, offsetx)) // offset of object centre from input position - ((int, offsety)) // - ); - -COMMAND(MoveObject, MERGE, + ((Position, pos)) + ((bool, selectActors)) + , ((ObjectID, id)) + ((int, offsetx)) // offset of object centre from input position + ((int, offsety)) // + ); + +QUERY(PickObjectsInRect, + ((Position, start)) + ((Position, end)) + ((bool, selectActors)) + , + ((std::vector, ids)) + ); + +QUERY(PickSimilarObjects, + ((ObjectID, id)) + , + ((std::vector, ids)) + ); + +COMMAND(MoveObjects, MERGE, + ((std::vector, ids)) + ((ObjectID, pivot)) ((Position, pos)) ); @@ -512,11 +528,11 @@ MESSAGE(SetSelectionPreview, ); QUERY(GetObjectSettings, - ((int, view)) // eRenderView - ((ObjectID, id)) - , - ((sObjectSettings, settings)) - ); + ((int, view)) // eRenderView + ((ObjectID, id)) + , + ((sObjectSettings, settings)) + ); COMMAND(SetObjectSettings, NOMERGE, ((int, view)) // eRenderView @@ -530,6 +546,14 @@ QUERY(GetPlayerObjects, ((std::vector, ids)) ); +MESSAGE(SetBandbox, + ((bool, show)) + ((int, sx0)) + ((int, sy0)) + ((int, sx1)) + ((int, sy1)) + ); + ////////////////////////////////////////////////////////////////////////// QUERY(GetCinemaPaths, diff --git a/source/tools/atlas/GameInterface/SharedTypes.h b/source/tools/atlas/GameInterface/SharedTypes.h index 757f6a7f1f..1d5c22c732 100644 --- a/source/tools/atlas/GameInterface/SharedTypes.h +++ b/source/tools/atlas/GameInterface/SharedTypes.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -84,7 +84,7 @@ SHAREABLE_STRUCT(Colour); typedef size_t ObjectID; -inline bool ObjectIDIsValid(ObjectID id) { return (id != ~(size_t)0); } +inline bool ObjectIDIsValid(ObjectID id) { return (id != 0); } struct sCinemaSplineNode diff --git a/source/tools/atlas/GameInterface/View.cpp b/source/tools/atlas/GameInterface/View.cpp index 3970b9aa1e..c2e256a972 100644 --- a/source/tools/atlas/GameInterface/View.cpp +++ b/source/tools/atlas/GameInterface/View.cpp @@ -166,7 +166,7 @@ static void delete_pair_2nd(std::pair v) } ViewGame::ViewGame() -: m_SpeedMultiplier(0.f) + : m_SpeedMultiplier(0.f) { ENSURE(g_Game); } @@ -262,6 +262,49 @@ void ViewGame::Render() Atlas_GLSwapBuffers((void*)g_GameLoop->glCanvas); } +void ViewGame::DrawOverlays() +{ +#if CONFIG2_GLES +#warning TODO: implement Atlas game overlays for GLES +#else + // Set up transform for overlays + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + CMatrix3D transform; + transform.SetIdentity(); + transform.Scale(1.0f, -1.f, 1.0f); + transform.Translate(0.0f, (float)g_yres, -1000.0f); + CMatrix3D proj; + proj.SetOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f); + transform = proj * transform; + glLoadMatrixf(&transform._11); + + if (m_BandboxArray.size() > 0) + { + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + + // Render bandbox as array of lines + glVertexPointer(2, GL_FLOAT, sizeof(SBandboxVertex), &m_BandboxArray[0].x); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SBandboxVertex), &m_BandboxArray[0].r); + + glDrawArrays(GL_LINES, 0, m_BandboxArray.size()); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +#endif +} + void ViewGame::SetParam(const std::wstring& name, bool value) { if (name == L"priorities") @@ -353,6 +396,39 @@ std::wstring ViewGame::DumpState(bool binary) } } +void ViewGame::SetBandbox(bool visible, float x0, float y0, float x1, float y1) +{ + m_BandboxArray.clear(); + + if (visible) + { + // Make sure corners are arranged in correct order + if (x0 > x1) + std::swap(x0, x1); + if (y0 > y1) + std::swap(y0, y1); + + // Bandbox is draw as lines comprising two rectangles + SBandboxVertex vert[] = { + // Black - outer rectangle + SBandboxVertex(x0, y0, 0, 0, 0, 255), SBandboxVertex(x1, y0, 0, 0, 0, 255), SBandboxVertex(x1, y1, 0, 0, 0, 255), SBandboxVertex(x0, y1, 0, 0, 0, 255), + // White - inner rectangle + SBandboxVertex(x0+1.0f, y0+1.0f, 255, 255, 255, 255), SBandboxVertex(x1-1.0f, y0+1.0f, 255, 255, 255, 255), SBandboxVertex(x1-1.0f, y1-1.0f, 255, 255, 255, 255), SBandboxVertex(x0+1.0f, y1-1.0f, 255, 255, 255, 255) + }; + + for (size_t i = 0; i < 4; ++i) + { + m_BandboxArray.push_back(vert[i]); + m_BandboxArray.push_back(vert[(i+1)%4]); + } + for (size_t i = 0; i < 4; ++i) + { + m_BandboxArray.push_back(vert[i+4]); + m_BandboxArray.push_back(vert[(i+1)%4+4]); + } + } +} + ////////////////////////////////////////////////////////////////////////// ViewNone* view_None = NULL; diff --git a/source/tools/atlas/GameInterface/View.h b/source/tools/atlas/GameInterface/View.h index fec883fad3..766cf59c9f 100644 --- a/source/tools/atlas/GameInterface/View.h +++ b/source/tools/atlas/GameInterface/View.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2012 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -37,6 +37,7 @@ public: virtual ~View(); virtual void Update(float UNUSED(frameLength)) { }; virtual void Render() { }; + virtual void DrawOverlays() { }; virtual CCamera& GetCamera() = 0; virtual CSimulation2* GetSimulation2() { return NULL; } virtual entity_id_t GetEntityId(AtlasMessage::ObjectID obj) { return (entity_id_t)obj; } @@ -76,6 +77,7 @@ public: virtual ~ViewGame(); virtual void Update(float frameLength); virtual void Render(); + virtual void DrawOverlays(); virtual CCamera& GetCamera(); virtual CSimulation2* GetSimulation2(); virtual bool WantsHighFramerate(); @@ -87,11 +89,21 @@ public: void SaveState(const std::wstring& label); void RestoreState(const std::wstring& label); std::wstring DumpState(bool binary); + void SetBandbox(bool visible, float x0, float y0, float x1, float y1); private: float m_SpeedMultiplier; std::map m_SavedStates; std::string m_DisplayPassability; + + typedef struct SBandboxVertex + { + SBandboxVertex(float x, float y, u8 r, u8 g, u8 b, u8 a) : x(x), y(y), r(r), g(g), b(b), a(a) {} + u8 r, g, b, a; + float x, y; + } SBandboxVertex; + + std::vector m_BandboxArray; }; class ActorViewer;