Changeset View
Standalone View
source/simulation2/components/CCmpObstructionManager.cpp
/* Copyright (C) 2020 Wildfire Games. | /* Copyright (C) 2021 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 15 Lines | |||||
#include "simulation2/MessageTypes.h" | #include "simulation2/MessageTypes.h" | ||||
#include "simulation2/helpers/Geometry.h" | #include "simulation2/helpers/Geometry.h" | ||||
#include "simulation2/helpers/Grid.h" | #include "simulation2/helpers/Grid.h" | ||||
#include "simulation2/helpers/Rasterize.h" | #include "simulation2/helpers/Rasterize.h" | ||||
#include "simulation2/helpers/Render.h" | #include "simulation2/helpers/Render.h" | ||||
#include "simulation2/helpers/Spatial.h" | #include "simulation2/helpers/Spatial.h" | ||||
#include "simulation2/serialization/SerializedTypes.h" | #include "simulation2/serialization/SerializedTypes.h" | ||||
#include "simulation2/system/SimSynchronization.h" | |||||
#include "graphics/Overlay.h" | #include "graphics/Overlay.h" | ||||
#include "graphics/Terrain.h" | #include "graphics/Terrain.h" | ||||
#include "maths/MathUtil.h" | #include "maths/MathUtil.h" | ||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "renderer/Scene.h" | |||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "renderer/Scene.h" | |||||
// Externally, tags are opaque non-zero positive integers. | // Externally, tags are opaque non-zero positive integers. | ||||
// Internally, they are tagged (by shape) indexes into shape lists. | // Internally, they are tagged (by shape) indexes into shape lists. | ||||
wraitii: forgot to remove these. | |||||
// idx must be non-zero. | // idx must be non-zero. | ||||
#define TAG_IS_VALID(tag) ((tag).valid()) | #define TAG_IS_VALID(tag) ((tag).valid()) | ||||
#define TAG_IS_UNIT(tag) (((tag).n & 1) == 0) | #define TAG_IS_UNIT(tag) (((tag).n & 1) == 0) | ||||
#define TAG_IS_STATIC(tag) (((tag).n & 1) == 1) | #define TAG_IS_STATIC(tag) (((tag).n & 1) == 1) | ||||
#define UNIT_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 0) | #define UNIT_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 0) | ||||
#define STATIC_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 1) | #define STATIC_INDEX_TO_TAG(idx) tag_t(((idx) << 1) | 1) | ||||
#define TAG_TO_INDEX(tag) ((tag).n >> 1) | #define TAG_TO_INDEX(tag) ((tag).n >> 1) | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | public: | ||||
DEFAULT_COMPONENT_ALLOCATOR(ObstructionManager) | DEFAULT_COMPONENT_ALLOCATOR(ObstructionManager) | ||||
bool m_DebugOverlayEnabled; | bool m_DebugOverlayEnabled; | ||||
bool m_DebugOverlayDirty; | bool m_DebugOverlayDirty; | ||||
std::vector<SOverlayLine> m_DebugOverlayLines; | std::vector<SOverlayLine> m_DebugOverlayLines; | ||||
SpatialSubdivision m_UnitSubdivision; | SpatialSubdivision m_UnitSubdivision; | ||||
SpatialSubdivision m_StaticSubdivision; | SpatialSubdivision m_StaticSubdivision; | ||||
Not Done Inline ActionsIf it's protected by the single guard, why you don't move it in a separate class with a proper protection? vladislavbelov: If it's protected by the single guard, why you don't move it in a separate class with a proper… | |||||
// TODO: using std::map is a bit inefficient; is there a better way to store these? | // TODO: using std::map is a bit inefficient; is there a better way to store these? | ||||
std::map<u32, UnitShape> m_UnitShapes; | std::map<u32, UnitShape> m_UnitShapes; | ||||
std::map<u32, StaticShape> m_StaticShapes; | std::map<u32, StaticShape> m_StaticShapes; | ||||
u32 m_UnitShapeNext; // next allocated id | u32 m_UnitShapeNext; // next allocated id | ||||
u32 m_StaticShapeNext; | u32 m_StaticShapeNext; | ||||
entity_pos_t m_MaxClearance; | entity_pos_t m_MaxClearance; | ||||
Not Done Inline ActionsStill accurate? Stan: Still accurate? | |||||
Not Done Inline Actionsyes wraitii: yes | |||||
Not Done Inline ActionsShould be near to the std::map type usage and not the variable declaration. vladislavbelov: Should be near to the `std::map` type usage and not the variable declaration. | |||||
bool m_PassabilityCircular; | bool m_PassabilityCircular; | ||||
entity_pos_t m_WorldX0; | entity_pos_t m_WorldX0; | ||||
entity_pos_t m_WorldZ0; | entity_pos_t m_WorldZ0; | ||||
entity_pos_t m_WorldX1; | entity_pos_t m_WorldX1; | ||||
entity_pos_t m_WorldZ1; | entity_pos_t m_WorldZ1; | ||||
u16 m_TerrainTiles; | u16 m_TerrainTiles; | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// NB: on deserialization, this function is not called after the component is reset. | // NB: on deserialization, this function is not called after the component is reset. | ||||
// So anything that happens here should be safely serialized. | // So anything that happens here should be safely serialized. | ||||
virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) | virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
m_WorldX0 = x0; | m_WorldX0 = x0; | ||||
m_WorldZ0 = z0; | m_WorldZ0 = z0; | ||||
m_WorldX1 = x1; | m_WorldX1 = x1; | ||||
m_WorldZ1 = z1; | m_WorldZ1 = z1; | ||||
MakeDirtyAll(); | MakeDirtyAll(); | ||||
// Subdivision system bounds: | // Subdivision system bounds: | ||||
ENSURE(x0.IsZero() && z0.IsZero()); // don't bother implementing non-zero offsets yet | ENSURE(x0.IsZero() && z0.IsZero()); // don't bother implementing non-zero offsets yet | ||||
ResetSubdivisions(x1, z1); | ResetSubdivisions(x1, z1); | ||||
CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); | CmpPtr<ICmpTerrain> cmpTerrain(GetSystemEntity()); | ||||
if (!cmpTerrain) | if (!cmpTerrain) | ||||
return; | return; | ||||
m_TerrainTiles = cmpTerrain->GetTilesPerSide(); | m_TerrainTiles = cmpTerrain->GetTilesPerSide(); | ||||
m_UpdateInformations.dirtinessGrid = Grid<u8>(m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE, m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE); | m_UpdateInformations.dirtinessGrid = Grid<u8>(m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE, m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE); | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | ||||
if (cmpPathfinder) | if (cmpPathfinder) | ||||
m_MaxClearance = cmpPathfinder->GetMaximumClearance(); | m_MaxClearance = cmpPathfinder->GetMaximumClearance(); | ||||
} | } | ||||
void ResetSubdivisions(entity_pos_t x1, entity_pos_t z1) | void ResetSubdivisions(entity_pos_t x1, entity_pos_t z1) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
Not Done Inline ActionsIt seems that this method will be acquiring/releasing locks frequently, wouldn't it be more efficient to have one global lock during its execution ? kilobug: It seems that this method will be acquiring/releasing locks frequently, wouldn't it be more… | |||||
Not Done Inline Actions@Kuba386 can you run some profiling to see if it's better/worse? Stan: @Kuba386 can you run some profiling to see if it's better/worse? | |||||
Not Done Inline ActionsWe hardly ever reset the subdivisions, so it should be fine. wraitii: We hardly ever reset the subdivisions, so it should be fine. | |||||
// Use 8x8 tile subdivisions | // Use 8x8 tile subdivisions | ||||
// (TODO: find the optimal number instead of blindly guessing) | // (TODO: find the optimal number instead of blindly guessing) | ||||
m_UnitSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); | m_UnitSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); | ||||
m_StaticSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); | m_StaticSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); | ||||
Not Done Inline ActionsPassing (lock) to each variable seems odd. vladislavbelov: Passing `(lock)` to each variable seems odd. | |||||
for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it) | for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it) | ||||
Not Done Inline ActionsCan the iterator be const? Stan: Can the iterator be const? | |||||
Done Inline ActionsIt could be I guess Kuba386: It could be I guess | |||||
{ | { | ||||
CFixedVector2D center(it->second.x, it->second.z); | CFixedVector2D center(it->second.x, it->second.z); | ||||
CFixedVector2D halfSize(it->second.clearance, it->second.clearance); | CFixedVector2D halfSize(it->second.clearance, it->second.clearance); | ||||
m_UnitSubdivision.Add(it->first, center - halfSize, center + halfSize); | m_UnitSubdivision.Add(it->first, center - halfSize, center + halfSize); | ||||
} | } | ||||
for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it) | for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it) | ||||
Not Done Inline ActionsSame here Stan: Same here | |||||
{ | { | ||||
CFixedVector2D center(it->second.x, it->second.z); | CFixedVector2D center(it->second.x, it->second.z); | ||||
CFixedVector2D bbHalfSize = Geometry::GetHalfBoundingBox(it->second.u, it->second.v, CFixedVector2D(it->second.hw, it->second.hh)); | CFixedVector2D bbHalfSize = Geometry::GetHalfBoundingBox(it->second.u, it->second.v, CFixedVector2D(it->second.hw, it->second.hh)); | ||||
m_StaticSubdivision.Add(it->first, center - bbHalfSize, center + bbHalfSize); | m_StaticSubdivision.Add(it->first, center - bbHalfSize, center + bbHalfSize); | ||||
} | } | ||||
} | } | ||||
virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance, flags_t flags, entity_id_t group) | virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance, flags_t flags, entity_id_t group) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
Not Done Inline ActionsLocking the mutex for each unit addition seems overhead, especially in case you know time bounds of the obstructions lock. vladislavbelov: Locking the mutex for each unit addition seems overhead, especially in case you know time… | |||||
UnitShape shape = { ent, x, z, clearance, flags, group }; | UnitShape shape = { ent, x, z, clearance, flags, group }; | ||||
u32 id = m_UnitShapeNext++; | u32 id = m_UnitShapeNext++; | ||||
m_UnitShapes[id] = shape; | m_UnitShapes[id] = shape; | ||||
m_UnitSubdivision.Add(id, CFixedVector2D(x - clearance, z - clearance), CFixedVector2D(x + clearance, z + clearance)); | m_UnitSubdivision.Add(id, CFixedVector2D(x - clearance, z - clearance), CFixedVector2D(x + clearance, z + clearance)); | ||||
MakeDirtyUnit(flags, id, shape); | MakeDirtyUnit(flags, id, shape); | ||||
return UNIT_INDEX_TO_TAG(id); | return UNIT_INDEX_TO_TAG(id); | ||||
} | } | ||||
virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 /* = INVALID_ENTITY */) | virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 /* = INVALID_ENTITY */) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
fixed s, c; | fixed s, c; | ||||
sincos_approx(a, s, c); | sincos_approx(a, s, c); | ||||
CFixedVector2D u(c, -s); | CFixedVector2D u(c, -s); | ||||
CFixedVector2D v(s, c); | CFixedVector2D v(s, c); | ||||
StaticShape shape = { ent, x, z, u, v, w/2, h/2, flags, group, group2 }; | StaticShape shape = { ent, x, z, u, v, w/2, h/2, flags, group, group2 }; | ||||
u32 id = m_StaticShapeNext++; | u32 id = m_StaticShapeNext++; | ||||
m_StaticShapes[id] = shape; | m_StaticShapes[id] = shape; | ||||
Show All 23 Lines | virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) const | ||||
CFixedVector2D v(s, c); | CFixedVector2D v(s, c); | ||||
ObstructionSquare o = { x, z, u, v, w/2, h/2 }; | ObstructionSquare o = { x, z, u, v, w/2, h/2 }; | ||||
return o; | return o; | ||||
} | } | ||||
virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) | virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
ENSURE(TAG_IS_VALID(tag)); | ENSURE(TAG_IS_VALID(tag)); | ||||
if (TAG_IS_UNIT(tag)) | if (TAG_IS_UNIT(tag)) | ||||
{ | { | ||||
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | ||||
MakeDirtyUnit(shape.flags, TAG_TO_INDEX(tag), shape); // dirty the old shape region | MakeDirtyUnit(shape.flags, TAG_TO_INDEX(tag), shape); // dirty the old shape region | ||||
Show All 33 Lines | else | ||||
shape.v = v; | shape.v = v; | ||||
MakeDirtyStatic(shape.flags, TAG_TO_INDEX(tag), shape); // dirty the new shape region | MakeDirtyStatic(shape.flags, TAG_TO_INDEX(tag), shape); // dirty the new shape region | ||||
} | } | ||||
} | } | ||||
virtual void SetUnitMovingFlag(tag_t tag, bool moving) | virtual void SetUnitMovingFlag(tag_t tag, bool moving) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); | ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); | ||||
if (TAG_IS_UNIT(tag)) | if (TAG_IS_UNIT(tag)) | ||||
{ | { | ||||
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | ||||
if (moving) | if (moving) | ||||
shape.flags |= FLAG_MOVING; | shape.flags |= FLAG_MOVING; | ||||
else | else | ||||
shape.flags &= (flags_t)~FLAG_MOVING; | shape.flags &= (flags_t)~FLAG_MOVING; | ||||
MakeDirtyDebug(); | MakeDirtyDebug(); | ||||
} | } | ||||
} | } | ||||
virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) | virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); | ENSURE(TAG_IS_VALID(tag) && TAG_IS_UNIT(tag)); | ||||
if (TAG_IS_UNIT(tag)) | if (TAG_IS_UNIT(tag)) | ||||
{ | { | ||||
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | ||||
shape.group = group; | shape.group = group; | ||||
} | } | ||||
} | } | ||||
virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) | virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
ENSURE(TAG_IS_VALID(tag) && TAG_IS_STATIC(tag)); | ENSURE(TAG_IS_VALID(tag) && TAG_IS_STATIC(tag)); | ||||
if (TAG_IS_STATIC(tag)) | if (TAG_IS_STATIC(tag)) | ||||
{ | { | ||||
StaticShape& shape = m_StaticShapes[TAG_TO_INDEX(tag)]; | StaticShape& shape = m_StaticShapes[TAG_TO_INDEX(tag)]; | ||||
shape.group = group; | shape.group = group; | ||||
shape.group2 = group2; | shape.group2 = group2; | ||||
} | } | ||||
} | } | ||||
virtual void RemoveShape(tag_t tag) | virtual void RemoveShape(tag_t tag) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
ENSURE(TAG_IS_VALID(tag)); | ENSURE(TAG_IS_VALID(tag)); | ||||
if (TAG_IS_UNIT(tag)) | if (TAG_IS_UNIT(tag)) | ||||
{ | { | ||||
UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | UnitShape& shape = m_UnitShapes[TAG_TO_INDEX(tag)]; | ||||
m_UnitSubdivision.Remove(TAG_TO_INDEX(tag), | m_UnitSubdivision.Remove(TAG_TO_INDEX(tag), | ||||
CFixedVector2D(shape.x - shape.clearance, shape.z - shape.clearance), | CFixedVector2D(shape.x - shape.clearance, shape.z - shape.clearance), | ||||
CFixedVector2D(shape.x + shape.clearance, shape.z + shape.clearance)); | CFixedVector2D(shape.x + shape.clearance, shape.z + shape.clearance)); | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | public: | ||||
virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | ||||
virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | ||||
virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const; | ||||
virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter, bool strict = false) const; | virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter, bool strict = false) const; | ||||
virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter) const; | virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter) const; | ||||
virtual void SetPassabilityCircular(bool enabled) | virtual void SetPassabilityCircular(bool enabled) | ||||
{ | { | ||||
ENSURE(!GetSimContext().GetSynchronizationData().m_ComputingPaths); | |||||
m_PassabilityCircular = enabled; | m_PassabilityCircular = enabled; | ||||
MakeDirtyAll(); | MakeDirtyAll(); | ||||
CMessageObstructionMapShapeChanged msg; | CMessageObstructionMapShapeChanged msg; | ||||
GetSimContext().GetComponentManager().BroadcastMessage(msg); | GetSimContext().GetComponentManager().BroadcastMessage(msg); | ||||
} | } | ||||
virtual bool GetPassabilityCircular() const | virtual bool GetPassabilityCircular() const | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if (flags & (FLAG_BLOCK_PATHFINDING | FLAG_BLOCK_FOUNDATION)) | ||||
// We are going to invalidate the region of the grid corresponding to the modified shape plus its clearance, | // We are going to invalidate the region of the grid corresponding to the modified shape plus its clearance, | ||||
// and we need to get the shapes whose clearance can overlap this area. So we need to extend the search area | // and we need to get the shapes whose clearance can overlap this area. So we need to extend the search area | ||||
// by two times the maximum clearance. | // by two times the maximum clearance. | ||||
CFixedVector2D center(shape.x, shape.z); | CFixedVector2D center(shape.x, shape.z); | ||||
std::vector<u32> staticsNear; | std::vector<u32> staticsNear; | ||||
m_StaticSubdivision.GetNear(staticsNear, center, shape.clearance + m_MaxClearance*2); | m_StaticSubdivision.GetNear(staticsNear, center, shape.clearance + m_MaxClearance*2); | ||||
for (u32& staticId : staticsNear) | for (u32& staticId : staticsNear) | ||||
Not Done Inline Actions& useless ? Stan: & useless ? | |||||
if (std::find(m_DirtyStaticShapes.begin(), m_DirtyStaticShapes.end(), staticId) == m_DirtyStaticShapes.end()) | if (std::find(m_DirtyStaticShapes.begin(), m_DirtyStaticShapes.end(), staticId) == m_DirtyStaticShapes.end()) | ||||
m_DirtyStaticShapes.push_back(staticId); | m_DirtyStaticShapes.push_back(staticId); | ||||
std::vector<u32> unitsNear; | std::vector<u32> unitsNear; | ||||
m_UnitSubdivision.GetNear(unitsNear, center, shape.clearance + m_MaxClearance*2); | m_UnitSubdivision.GetNear(unitsNear, center, shape.clearance + m_MaxClearance*2); | ||||
for (u32& unitId : unitsNear) | for (u32& unitId : unitsNear) | ||||
Not Done Inline Actions& useless ? Stan: & useless ? | |||||
if (std::find(m_DirtyUnitShapes.begin(), m_DirtyUnitShapes.end(), unitId) == m_DirtyUnitShapes.end()) | if (std::find(m_DirtyUnitShapes.begin(), m_DirtyUnitShapes.end(), unitId) == m_DirtyUnitShapes.end()) | ||||
m_DirtyUnitShapes.push_back(unitId); | m_DirtyUnitShapes.push_back(unitId); | ||||
MarkDirtinessGrid(shape.x, shape.z, shape.clearance + m_MaxClearance); | MarkDirtinessGrid(shape.x, shape.z, shape.clearance + m_MaxClearance); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const | ||||
// actual radius used for unit-unit collisions. If relaxClearanceForUnits, will be smaller to allow more overlap. | // actual radius used for unit-unit collisions. If relaxClearanceForUnits, will be smaller to allow more overlap. | ||||
entity_pos_t unitUnitRadius = r; | entity_pos_t unitUnitRadius = r; | ||||
if (relaxClearanceForUnits) | if (relaxClearanceForUnits) | ||||
unitUnitRadius -= entity_pos_t::FromInt(1)/2; | unitUnitRadius -= entity_pos_t::FromInt(1)/2; | ||||
std::vector<entity_id_t> unitShapes; | std::vector<entity_id_t> unitShapes; | ||||
m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | ||||
for (const entity_id_t& shape : unitShapes) | for (const entity_id_t& shape : unitShapes) | ||||
Not Done Inline Actionsfor (entity_id_t shape : staticShapes) https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than-const-int Stan: for (entity_id_t shape : staticShapes)
https://stackoverflow.com/questions/9637856/why-is… | |||||
Not Done Inline ActionsErr too much copy paste unitShapes for (entity_id_t shape : unitShapes) Stan: Err too much copy paste unitShapes
```
for (entity_id_t shape : unitShapes)
``` | |||||
{ | { | ||||
std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | ||||
ENSURE(it != m_UnitShapes.end()); | ENSURE(it != m_UnitShapes.end()); | ||||
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | ||||
continue; | continue; | ||||
CFixedVector2D center(it->second.x, it->second.z); | CFixedVector2D center(it->second.x, it->second.z); | ||||
CFixedVector2D halfSize(it->second.clearance + unitUnitRadius, it->second.clearance + unitUnitRadius); | CFixedVector2D halfSize(it->second.clearance + unitUnitRadius, it->second.clearance + unitUnitRadius); | ||||
if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize)) | if (Geometry::TestRayAASquare(CFixedVector2D(x0, z0) - center, CFixedVector2D(x1, z1) - center, halfSize)) | ||||
return true; | return true; | ||||
} | } | ||||
std::vector<entity_id_t> staticShapes; | std::vector<entity_id_t> staticShapes; | ||||
m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax); | m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax); | ||||
for (const entity_id_t& shape : staticShapes) | for (const entity_id_t& shape : staticShapes) | ||||
Not Done Inline Actionsfor (entity_id_t shape : staticShapes) https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than-const-int Stan: ```
for (entity_id_t shape : staticShapes)
```
https://stackoverflow. | |||||
{ | { | ||||
std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(shape); | std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(shape); | ||||
ENSURE(it != m_StaticShapes.end()); | ENSURE(it != m_StaticShapes.end()); | ||||
if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2)) | if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2)) | ||||
continue; | continue; | ||||
CFixedVector2D center(it->second.x, it->second.z); | CFixedVector2D center(it->second.x, it->second.z); | ||||
Show All 35 Lines | bool CCmpObstructionManager::TestStaticShape(const IObstructionTestFilter& filter, | ||||
fixed bbHalfWidth = std::max(corner1.X.Absolute(), corner2.X.Absolute()); | fixed bbHalfWidth = std::max(corner1.X.Absolute(), corner2.X.Absolute()); | ||||
fixed bbHalfHeight = std::max(corner1.Y.Absolute(), corner2.Y.Absolute()); | fixed bbHalfHeight = std::max(corner1.Y.Absolute(), corner2.Y.Absolute()); | ||||
CFixedVector2D posMin(x - bbHalfWidth, z - bbHalfHeight); | CFixedVector2D posMin(x - bbHalfWidth, z - bbHalfHeight); | ||||
CFixedVector2D posMax(x + bbHalfWidth, z + bbHalfHeight); | CFixedVector2D posMax(x + bbHalfWidth, z + bbHalfHeight); | ||||
std::vector<entity_id_t> unitShapes; | std::vector<entity_id_t> unitShapes; | ||||
m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | ||||
for (entity_id_t& shape : unitShapes) | for (entity_id_t& shape : unitShapes) | ||||
Not Done Inline ActionsI guess the & is useless there Stan: I guess the & is useless there | |||||
{ | { | ||||
std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | ||||
ENSURE(it != m_UnitShapes.end()); | ENSURE(it != m_UnitShapes.end()); | ||||
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | ||||
continue; | continue; | ||||
CFixedVector2D center1(it->second.x, it->second.z); | CFixedVector2D center1(it->second.x, it->second.z); | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | bool CCmpObstructionManager::TestUnitShape(const IObstructionTestFilter& filter, | ||||
} | } | ||||
CFixedVector2D center(x, z); | CFixedVector2D center(x, z); | ||||
CFixedVector2D posMin(x - clearance, z - clearance); | CFixedVector2D posMin(x - clearance, z - clearance); | ||||
CFixedVector2D posMax(x + clearance, z + clearance); | CFixedVector2D posMax(x + clearance, z + clearance); | ||||
std::vector<entity_id_t> unitShapes; | std::vector<entity_id_t> unitShapes; | ||||
m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); | ||||
for (const entity_id_t& shape : unitShapes) | for (const entity_id_t& shape : unitShapes) | ||||
Not Done Inline ActionsStan: That's a int right? https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than… | |||||
Done Inline ActionsWow, didn't know about that.. Kuba386: Wow, didn't know about that.. | |||||
{ | { | ||||
std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(shape); | ||||
ENSURE(it != m_UnitShapes.end()); | ENSURE(it != m_UnitShapes.end()); | ||||
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | ||||
continue; | continue; | ||||
entity_pos_t c1 = it->second.clearance; | entity_pos_t c1 = it->second.clearance; | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | void CCmpObstructionManager::Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) | ||||
RasterizeHelper(grid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask); | RasterizeHelper(grid, FLAG_BLOCK_FOUNDATION, fullUpdate, foundationMask); | ||||
m_DirtyStaticShapes.clear(); | m_DirtyStaticShapes.clear(); | ||||
m_DirtyUnitShapes.clear(); | m_DirtyUnitShapes.clear(); | ||||
} | } | ||||
void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance) const | void CCmpObstructionManager::RasterizeHelper(Grid<NavcellData>& grid, ICmpObstructionManager::flags_t requireMask, bool fullUpdate, pass_class_t appliedMask, entity_pos_t clearance) const | ||||
{ | { | ||||
for (auto& pair : m_StaticShapes) | for (auto& pair : m_StaticShapes) | ||||
Not Done Inline ActionsWas any decision reached on the usage of auto ? Stan: Was any decision reached on the usage of auto ? | |||||
Not Done Inline Actionsauto should be replaced by the type. Stan: auto should be replaced by the type.
Shouldn't staticShapes be taken out of the loop in case… | |||||
Done Inline ActionsMaybe my knowledge of how c++ range loops are compiled is missing here, but I don't think that moving this out of the loop is necessary. Kuba386: Maybe my knowledge of how c++ range loops are compiled is missing here, but I don't think that… | |||||
{ | { | ||||
const StaticShape& shape = pair.second; | const StaticShape& shape = pair.second; | ||||
if (!(shape.flags & requireMask)) | if (!(shape.flags & requireMask)) | ||||
continue; | continue; | ||||
if (!fullUpdate && std::find(m_DirtyStaticShapes.begin(), m_DirtyStaticShapes.end(), pair.first) == m_DirtyStaticShapes.end()) | if (!fullUpdate && std::find(m_DirtyStaticShapes.begin(), m_DirtyStaticShapes.end(), pair.first) == m_DirtyStaticShapes.end()) | ||||
continue; | continue; | ||||
// TODO: it might be nice to rasterize with rounded corners for large 'expand' values. | // TODO: it might be nice to rasterize with rounded corners for large 'expand' values. | ||||
ObstructionSquare square = { shape.x, shape.z, shape.u, shape.v, shape.hw, shape.hh }; | ObstructionSquare square = { shape.x, shape.z, shape.u, shape.v, shape.hw, shape.hh }; | ||||
SimRasterize::Spans spans; | SimRasterize::Spans spans; | ||||
SimRasterize::RasterizeRectWithClearance(spans, square, clearance, Pathfinding::NAVCELL_SIZE); | SimRasterize::RasterizeRectWithClearance(spans, square, clearance, Pathfinding::NAVCELL_SIZE); | ||||
for (SimRasterize::Span& span : spans) | for (SimRasterize::Span& span : spans) | ||||
{ | { | ||||
i16 j = Clamp(span.j, (i16)0, (i16)(grid.m_H-1)); | i16 j = Clamp(span.j, (i16)0, (i16)(grid.m_H-1)); | ||||
i16 i0 = std::max(span.i0, (i16)0); | i16 i0 = std::max(span.i0, (i16)0); | ||||
i16 i1 = std::min(span.i1, (i16)grid.m_W); | i16 i1 = std::min(span.i1, (i16)grid.m_W); | ||||
for (i16 i = i0; i < i1; ++i) | for (i16 i = i0; i < i1; ++i) | ||||
grid.set(i, j, grid.get(i, j) | appliedMask); | grid.set(i, j, grid.get(i, j) | appliedMask); | ||||
} | } | ||||
} | } | ||||
for (auto& pair : m_UnitShapes) | for (auto& pair : m_UnitShapes) | ||||
Not Done Inline ActionsSame as above Stan: Same as above | |||||
Not Done Inline ActionsStill up to date. Stan: Still up to date. | |||||
{ | { | ||||
if (!(pair.second.flags & requireMask)) | if (!(pair.second.flags & requireMask)) | ||||
continue; | continue; | ||||
if (!fullUpdate && std::find(m_DirtyUnitShapes.begin(), m_DirtyUnitShapes.end(), pair.first) == m_DirtyUnitShapes.end()) | if (!fullUpdate && std::find(m_DirtyUnitShapes.begin(), m_DirtyUnitShapes.end(), pair.first) == m_DirtyUnitShapes.end()) | ||||
continue; | continue; | ||||
CFixedVector2D center(pair.second.x, pair.second.z); | CFixedVector2D center(pair.second.x, pair.second.z); | ||||
Show All 17 Lines | |||||
void CCmpObstructionManager::GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const | void CCmpObstructionManager::GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const | ||||
{ | { | ||||
PROFILE("GetObstructionsInRange"); | PROFILE("GetObstructionsInRange"); | ||||
ENSURE(x0 <= x1 && z0 <= z1); | ENSURE(x0 <= x1 && z0 <= z1); | ||||
std::vector<entity_id_t> unitShapes; | std::vector<entity_id_t> unitShapes; | ||||
m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); | m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); | ||||
for (entity_id_t& unitShape : unitShapes) | for (entity_id_t& unitShape : unitShapes) | ||||
Not Done Inline ActionsStan: That's a int right? https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than… | |||||
{ | { | ||||
std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(unitShape); | std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(unitShape); | ||||
ENSURE(it != m_UnitShapes.end()); | ENSURE(it != m_UnitShapes.end()); | ||||
if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | if (!filter.TestShape(UNIT_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, INVALID_ENTITY)) | ||||
continue; | continue; | ||||
entity_pos_t c = it->second.clearance; | entity_pos_t c = it->second.clearance; | ||||
Show All 11 Lines | |||||
void CCmpObstructionManager::GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const | void CCmpObstructionManager::GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const | ||||
{ | { | ||||
PROFILE("GetObstructionsInRange"); | PROFILE("GetObstructionsInRange"); | ||||
ENSURE(x0 <= x1 && z0 <= z1); | ENSURE(x0 <= x1 && z0 <= z1); | ||||
std::vector<entity_id_t> staticShapes; | std::vector<entity_id_t> staticShapes; | ||||
m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); | m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); | ||||
for (entity_id_t& staticShape : staticShapes) | for (entity_id_t& staticShape : staticShapes) | ||||
Not Done Inline ActionsStan: That's a int right? https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than… | |||||
{ | { | ||||
std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(staticShape); | std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(staticShape); | ||||
ENSURE(it != m_StaticShapes.end()); | ENSURE(it != m_StaticShapes.end()); | ||||
if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2)) | if (!filter.TestShape(STATIC_INDEX_TO_TAG(it->first), it->second.flags, it->second.group, it->second.group2)) | ||||
continue; | continue; | ||||
entity_pos_t r = it->second.hw + it->second.hh; // overestimate the max dist of an edge from the center | entity_pos_t r = it->second.hw + it->second.hh; // overestimate the max dist of an edge from the center | ||||
Show All 20 Lines | void CCmpObstructionManager::GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter, bool strict) const | ||||
CFixedVector2D center(square.x, square.z); | CFixedVector2D center(square.x, square.z); | ||||
CFixedVector2D expandedBox = | CFixedVector2D expandedBox = | ||||
Geometry::GetHalfBoundingBox(square.u, square.v, CFixedVector2D(square.hw, square.hh)) + | Geometry::GetHalfBoundingBox(square.u, square.v, CFixedVector2D(square.hw, square.hh)) + | ||||
CFixedVector2D(m_MaxClearance, m_MaxClearance); | CFixedVector2D(m_MaxClearance, m_MaxClearance); | ||||
m_UnitSubdivision.GetInRange(unitShapes, center - expandedBox, center + expandedBox); | m_UnitSubdivision.GetInRange(unitShapes, center - expandedBox, center + expandedBox); | ||||
std::map<entity_pos_t, SimRasterize::Spans> rasterizedRects; | std::map<entity_pos_t, SimRasterize::Spans> rasterizedRects; | ||||
for (const u32& unitShape : unitShapes) | for (const u32& unitShape : unitShapes) | ||||
Not Done Inline ActionsStan: https://stackoverflow.com/questions/9637856/why-is-const-int-faster-than-const-int | |||||
{ | { | ||||
std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(unitShape); | std::map<u32, UnitShape>::const_iterator it = m_UnitShapes.find(unitShape); | ||||
ENSURE(it != m_UnitShapes.end()); | ENSURE(it != m_UnitShapes.end()); | ||||
const UnitShape& shape = it->second; | const UnitShape& shape = it->second; | ||||
if (!filter.TestShape(UNIT_INDEX_TO_TAG(unitShape), shape.flags, shape.group, INVALID_ENTITY)) | if (!filter.TestShape(UNIT_INDEX_TO_TAG(unitShape), shape.flags, shape.group, INVALID_ENTITY)) | ||||
continue; | continue; | ||||
Show All 36 Lines | |||||
{ | { | ||||
PROFILE("GetStaticObstructionsOnObstruction"); | PROFILE("GetStaticObstructionsOnObstruction"); | ||||
std::vector<entity_id_t> staticShapes; | std::vector<entity_id_t> staticShapes; | ||||
CFixedVector2D center(square.x, square.z); | CFixedVector2D center(square.x, square.z); | ||||
CFixedVector2D expandedBox = Geometry::GetHalfBoundingBox(square.u, square.v, CFixedVector2D(square.hw, square.hh)); | CFixedVector2D expandedBox = Geometry::GetHalfBoundingBox(square.u, square.v, CFixedVector2D(square.hw, square.hh)); | ||||
m_StaticSubdivision.GetInRange(staticShapes, center - expandedBox, center + expandedBox); | m_StaticSubdivision.GetInRange(staticShapes, center - expandedBox, center + expandedBox); | ||||
for (const u32& staticShape : staticShapes) | for (const u32& staticShape : staticShapes) | ||||
Not Done Inline ActionsHere as well Stan: Here as well | |||||
{ | { | ||||
std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(staticShape); | std::map<u32, StaticShape>::const_iterator it = m_StaticShapes.find(staticShape); | ||||
ENSURE(it != m_StaticShapes.end()); | ENSURE(it != m_StaticShapes.end()); | ||||
const StaticShape& shape = it->second; | const StaticShape& shape = it->second; | ||||
if (!filter.TestShape(STATIC_INDEX_TO_TAG(staticShape), shape.flags, shape.group, shape.group2)) | if (!filter.TestShape(STATIC_INDEX_TO_TAG(staticShape), shape.flags, shape.group, shape.group2)) | ||||
continue; | continue; | ||||
Show All 28 Lines | if (m_DebugOverlayDirty) | ||||
m_DebugOverlayLines.clear(); | m_DebugOverlayLines.clear(); | ||||
m_DebugOverlayLines.push_back(SOverlayLine()); | m_DebugOverlayLines.push_back(SOverlayLine()); | ||||
m_DebugOverlayLines.back().m_Color = boundsColor; | m_DebugOverlayLines.back().m_Color = boundsColor; | ||||
SimRender::ConstructSquareOnGround(GetSimContext(), | SimRender::ConstructSquareOnGround(GetSimContext(), | ||||
(m_WorldX0+m_WorldX1).ToFloat()/2.f, (m_WorldZ0+m_WorldZ1).ToFloat()/2.f, | (m_WorldX0+m_WorldX1).ToFloat()/2.f, (m_WorldZ0+m_WorldZ1).ToFloat()/2.f, | ||||
(m_WorldX1-m_WorldX0).ToFloat(), (m_WorldZ1-m_WorldZ0).ToFloat(), | (m_WorldX1-m_WorldX0).ToFloat(), (m_WorldZ1-m_WorldZ0).ToFloat(), | ||||
0, m_DebugOverlayLines.back(), true); | 0, m_DebugOverlayLines.back(), true); | ||||
Not Done Inline Actionsrange based loop? const iterator? Stan: range based loop? const iterator? | |||||
for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it) | for (std::map<u32, UnitShape>::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it) | ||||
{ | { | ||||
m_DebugOverlayLines.push_back(SOverlayLine()); | m_DebugOverlayLines.push_back(SOverlayLine()); | ||||
m_DebugOverlayLines.back().m_Color = ((it->second.flags & FLAG_MOVING) ? movingColor : defaultColor); | m_DebugOverlayLines.back().m_Color = ((it->second.flags & FLAG_MOVING) ? movingColor : defaultColor); | ||||
SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.clearance.ToFloat(), it->second.clearance.ToFloat(), 0, m_DebugOverlayLines.back(), true); | SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.clearance.ToFloat(), it->second.clearance.ToFloat(), 0, m_DebugOverlayLines.back(), true); | ||||
} | } | ||||
for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it) | for (std::map<u32, StaticShape>::iterator it = m_StaticShapes.begin(); it != m_StaticShapes.end(); ++it) | ||||
Not Done Inline Actionsrange based loop? const iterator? Stan: range based loop? const iterator? | |||||
{ | { | ||||
m_DebugOverlayLines.push_back(SOverlayLine()); | m_DebugOverlayLines.push_back(SOverlayLine()); | ||||
m_DebugOverlayLines.back().m_Color = defaultColor; | m_DebugOverlayLines.back().m_Color = defaultColor; | ||||
float a = atan2f(it->second.v.X.ToFloat(), it->second.v.Y.ToFloat()); | float a = atan2f(it->second.v.X.ToFloat(), it->second.v.Y.ToFloat()); | ||||
SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.hw.ToFloat()*2, it->second.hh.ToFloat()*2, a, m_DebugOverlayLines.back(), true); | SimRender::ConstructSquareOnGround(GetSimContext(), it->second.x.ToFloat(), it->second.z.ToFloat(), it->second.hw.ToFloat()*2, it->second.hh.ToFloat()*2, a, m_DebugOverlayLines.back(), true); | ||||
} | } | ||||
m_DebugOverlayDirty = false; | m_DebugOverlayDirty = false; | ||||
} | } | ||||
for (size_t i = 0; i < m_DebugOverlayLines.size(); ++i) | for (size_t i = 0; i < m_DebugOverlayLines.size(); ++i) | ||||
collector.Submit(&m_DebugOverlayLines[i]); | collector.Submit(&m_DebugOverlayLines[i]); | ||||
} | } |
forgot to remove these.