Revert RedFox's changes to Spatial subdivisions in the simplest possible way (hopefully won't cause OOS, but at least we'll get reports). Fixes #2573, Refs #2430 . There probably are opportunities to remove more things.

This was SVN commit r15617.
This commit is contained in:
wraitii 2014-08-06 09:21:00 +00:00
parent c0e7208130
commit e865dc797d
4 changed files with 22 additions and 61 deletions

View File

@ -547,9 +547,9 @@ bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti
CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r); CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r);
CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r); CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r);
SpatialQueryArray unitShapes; std::vector<entity_id_t> unitShapes;
m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax);
for (int i = 0; i < unitShapes.size(); ++i) for (size_t i = 0; i < unitShapes.size(); ++i)
{ {
std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
ENSURE(it != m_UnitShapes.end()); ENSURE(it != m_UnitShapes.end());
@ -563,9 +563,9 @@ bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti
return true; return true;
} }
SpatialQueryArray staticShapes; std::vector<entity_id_t> staticShapes;
m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax); m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax);
for (int i = 0; i < staticShapes.size(); ++i) for (size_t i = 0; i < staticShapes.size(); ++i)
{ {
std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
ENSURE(it != m_StaticShapes.end()); ENSURE(it != m_StaticShapes.end());
@ -885,9 +885,9 @@ void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter
ENSURE(x0 <= x1 && z0 <= z1); ENSURE(x0 <= x1 && z0 <= z1);
SpatialQueryArray 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 (int i = 0; i < unitShapes.size(); ++i) for (size_t i = 0; i < unitShapes.size(); ++i)
{ {
std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]);
ENSURE(it != m_UnitShapes.end()); ENSURE(it != m_UnitShapes.end());
@ -907,9 +907,9 @@ void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter
squares.push_back(s); squares.push_back(s);
} }
SpatialQueryArray 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 (int i = 0; i < staticShapes.size(); ++i) for (size_t i = 0; i < staticShapes.size(); ++i)
{ {
std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]);
ENSURE(it != m_StaticShapes.end()); ENSURE(it != m_StaticShapes.end());

View File

@ -981,10 +981,10 @@ public:
CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+ CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+
CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ; CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ;
// Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange
SpatialQueryArray ents; std::vector<entity_id_t> ents;
m_Subdivision.GetNear(ents, pos, q.maxRange*2); m_Subdivision.GetNear(ents, pos, q.maxRange*2);
for (int i = 0; i < ents.size(); ++i) for (size_t i = 0; i < ents.size(); ++i)
{ {
EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]); EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
ENSURE(it != m_EntityData.end()); ENSURE(it != m_EntityData.end());
@ -1018,10 +1018,10 @@ public:
else else
{ {
// Get a quick list of entities that are potentially in range // Get a quick list of entities that are potentially in range
SpatialQueryArray ents; std::vector<entity_id_t> ents;
m_Subdivision.GetNear(ents, pos, q.maxRange); m_Subdivision.GetNear(ents, pos, q.maxRange);
for (int i = 0; i < ents.size(); ++i) for (size_t i = 0; i < ents.size(); ++i)
{ {
EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]); EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
ENSURE(it != m_EntityData.end()); ENSURE(it != m_EntityData.end());

View File

@ -49,12 +49,12 @@ std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu
CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z)); CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z));
// Get a rough group of entities using our approximated origin. // Get a rough group of entities using our approximated origin.
SpatialQueryArray ents; std::vector<entity_id_t> ents;
cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range)); cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range));
// Filter for relevent entities and calculate precise distances. // Filter for relevent entities and calculate precise distances.
std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs
for (int i = 0; i < ents.size(); ++i) for (size_t i = 0; i < ents.size(); ++i)
{ {
CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]); CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]);
if (!cmpSelectable) if (!cmpSelectable)

View File

@ -20,36 +20,10 @@
#include "simulation2/system/Component.h" #include "simulation2/system/Component.h"
#include "simulation2/serialization/SerializeTemplates.h" #include "simulation2/serialization/SerializeTemplates.h"
#include "ps/CLogger.h"
/**
* A simple fixed-size array that works similar to an std::vector
* but is obviously limited in its max items
*/
struct SpatialQueryArray
{
enum { MAX_COUNT = 2048 };
int count;
uint32_t items[MAX_COUNT];
inline SpatialQueryArray() : count(0) {}
inline const uint32_t& operator[](int index) const { return items[index]; }
inline uint32_t& operator[](int index) { return items[index]; }
inline int size() const { return count; }
inline void clear() { count = 0; }
void make_unique() // removes any duplicate entries
{
if (count)
{
std::sort(items, items + count); // we need a sorted list for std::unique to work
count = int(std::unique(items, items + count) - items);
}
}
};
/** /**
* A very basic subdivision scheme for finding items in ranges. * A very basic subdivision scheme for finding items in ranges.
* Items are stored in lists in fixed-size divisions. * Items are stored in lists in dynamic-sized divisions.
* Items have a size (min/max values of their axis-aligned bounding box) * Items have a size (min/max values of their axis-aligned bounding box)
* and are stored in all divisions overlapping that area. * and are stored in all divisions overlapping that area.
* *
@ -80,23 +54,9 @@ class SpatialSubdivision
items.pop_back(); items.pop_back();
} }
void copy_items(SpatialQueryArray& out) void copy_items_at_end(std::vector<uint32_t>& out)
{ {
if (items.empty()) out.insert(out.end(), items.begin(), items.end());
return; // nothing to copy
int dsti = out.count; // the index in [out] where to start copying
int count = (int)items.size();
if ((dsti + count) > SpatialQueryArray::MAX_COUNT)
{
LOGWARNING(L"SpatialSubdivision Query too large. Results truncated.");
count = SpatialQueryArray::MAX_COUNT - dsti; // don't copy overflowing items
}
uint32_t* dst = &out.items[dsti];
uint32_t* src = &items[0];
for (int i = 0; i < count; ++i) // copy all items
dst[i] = src[i];
out.count += count;
} }
}; };
@ -288,7 +248,7 @@ public:
* Returns a sorted list of unique items that includes all items * Returns a sorted list of unique items that includes all items
* within the given axis-aligned square range. * within the given axis-aligned square range.
*/ */
void GetInRange(SpatialQueryArray& out, CFixedVector2D posMin, CFixedVector2D posMax) void GetInRange(std::vector<uint32_t>& out, CFixedVector2D posMin, CFixedVector2D posMax)
{ {
out.clear(); out.clear();
ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y); ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y);
@ -301,18 +261,19 @@ public:
{ {
for (u32 i = i0; i <= i1; ++i) for (u32 i = i0; i <= i1; ++i)
{ {
m_Divisions[i + j*m_DivisionsW].copy_items(out); m_Divisions[i + j*m_DivisionsW].copy_items_at_end(out);
} }
} }
// some buildings span several tiles, so we need to make it unique // some buildings span several tiles, so we need to make it unique
out.make_unique(); std::sort(out.begin(), out.end());
out.erase(std::unique(out.begin(), out.end()), out.end());
} }
/** /**
* Returns a sorted list of unique items that includes all items * Returns a sorted list of unique items that includes all items
* within the given circular distance of the given point. * within the given circular distance of the given point.
*/ */
void GetNear(SpatialQueryArray& out, CFixedVector2D pos, entity_pos_t range) void GetNear(std::vector<uint32_t>& out, CFixedVector2D pos, entity_pos_t range)
{ {
// TODO: be cleverer and return a circular pattern of divisions, // TODO: be cleverer and return a circular pattern of divisions,
// not this square over-approximation // not this square over-approximation