Core/Grid:
- Simplified CellArea calculation (Original author: SilverIce) - Removed unused code in Cell class (Original author: SilverIce) - Improve some Visit functions.
This commit is contained in:
@@ -29,88 +29,34 @@
|
||||
class Map;
|
||||
class WorldObject;
|
||||
|
||||
enum District
|
||||
{
|
||||
UPPER_DISTRICT = 1,
|
||||
LOWER_DISTRICT = 1 << 1,
|
||||
LEFT_DISTRICT = 1 << 2,
|
||||
RIGHT_DISTRICT = 1 << 3,
|
||||
CENTER_DISTRICT = 1 << 4,
|
||||
UPPER_LEFT_DISTRICT = (UPPER_DISTRICT | LEFT_DISTRICT),
|
||||
UPPER_RIGHT_DISTRICT = (UPPER_DISTRICT | RIGHT_DISTRICT),
|
||||
LOWER_LEFT_DISTRICT = (LOWER_DISTRICT | LEFT_DISTRICT),
|
||||
LOWER_RIGHT_DISTRICT = (LOWER_DISTRICT | RIGHT_DISTRICT),
|
||||
ALL_DISTRICT = (UPPER_DISTRICT | LOWER_DISTRICT | LEFT_DISTRICT | RIGHT_DISTRICT | CENTER_DISTRICT)
|
||||
};
|
||||
|
||||
struct CellArea
|
||||
{
|
||||
CellArea() : right_offset(0), left_offset(0), upper_offset(0), lower_offset(0) {}
|
||||
CellArea(int right, int left, int upper, int lower) : right_offset(right), left_offset(left), upper_offset(upper), lower_offset(lower) {}
|
||||
bool operator!() const { return !right_offset && !left_offset && !upper_offset && !lower_offset; }
|
||||
CellArea() {}
|
||||
CellArea(CellCoord low, CellCoord high) : low_bound(low), high_bound(high) {}
|
||||
|
||||
bool operator!() const { return low_bound == high_bound; }
|
||||
|
||||
void ResizeBorders(CellCoord& begin_cell, CellCoord& end_cell) const
|
||||
{
|
||||
begin_cell.dec_x(left_offset);
|
||||
begin_cell.dec_y(lower_offset);
|
||||
end_cell.inc_x(right_offset);
|
||||
end_cell.inc_y(upper_offset);
|
||||
begin_cell = low_bound;
|
||||
end_cell = high_bound;
|
||||
}
|
||||
|
||||
int right_offset;
|
||||
int left_offset;
|
||||
int upper_offset;
|
||||
int lower_offset;
|
||||
CellCoord low_bound;
|
||||
CellCoord high_bound;
|
||||
};
|
||||
|
||||
struct Cell
|
||||
{
|
||||
Cell() { data.All = 0; }
|
||||
Cell(const Cell &cell) { data.All = cell.data.All; }
|
||||
Cell(Cell const& cell) { data.All = cell.data.All; }
|
||||
explicit Cell(CellCoord const& p);
|
||||
explicit Cell(float x, float y);
|
||||
|
||||
void operator|=(Cell &cell)
|
||||
{
|
||||
data.Part.reserved = 0;
|
||||
cell.data.Part.reserved = 0;
|
||||
uint32 x, y, old_x, old_y;
|
||||
Compute(x, y);
|
||||
cell.Compute(old_x, old_y);
|
||||
|
||||
if (std::abs(int(x-old_x)) > 1 || std::abs(int(y-old_y)) > 1)
|
||||
{
|
||||
data.Part.reserved = ALL_DISTRICT;
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (x < old_x)
|
||||
{
|
||||
data.Part.reserved |= LEFT_DISTRICT;
|
||||
cell.data.Part.reserved |= RIGHT_DISTRICT;
|
||||
}
|
||||
else if (old_x < x)
|
||||
{
|
||||
data.Part.reserved |= RIGHT_DISTRICT;
|
||||
cell.data.Part.reserved |= LEFT_DISTRICT;
|
||||
}
|
||||
if (y < old_y)
|
||||
{
|
||||
data.Part.reserved |= UPPER_DISTRICT;
|
||||
cell.data.Part.reserved |= LOWER_DISTRICT;
|
||||
}
|
||||
else if (old_y < y)
|
||||
{
|
||||
data.Part.reserved |= LOWER_DISTRICT;
|
||||
cell.data.Part.reserved |= UPPER_DISTRICT;
|
||||
}
|
||||
}
|
||||
|
||||
void Compute(uint32 &x, uint32 &y) const
|
||||
{
|
||||
x = data.Part.grid_x*MAX_NUMBER_OF_CELLS + data.Part.cell_x;
|
||||
y = data.Part.grid_y*MAX_NUMBER_OF_CELLS + data.Part.cell_y;
|
||||
x = data.Part.grid_x * MAX_NUMBER_OF_CELLS + data.Part.cell_x;
|
||||
y = data.Part.grid_y * MAX_NUMBER_OF_CELLS + data.Part.cell_y;
|
||||
}
|
||||
|
||||
bool DiffCell(const Cell &cell) const
|
||||
@@ -135,18 +81,18 @@ struct Cell
|
||||
CellCoord GetCellCoord() const
|
||||
{
|
||||
return CellCoord(
|
||||
data.Part.grid_x*MAX_NUMBER_OF_CELLS+data.Part.cell_x,
|
||||
data.Part.grid_y*MAX_NUMBER_OF_CELLS+data.Part.cell_y);
|
||||
data.Part.grid_x * MAX_NUMBER_OF_CELLS+data.Part.cell_x,
|
||||
data.Part.grid_y * MAX_NUMBER_OF_CELLS+data.Part.cell_y);
|
||||
}
|
||||
|
||||
Cell& operator=(const Cell &cell)
|
||||
Cell& operator=(Cell const& cell)
|
||||
{
|
||||
this->data.All = cell.data.All;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (const Cell &cell) const { return (data.All == cell.data.All); }
|
||||
bool operator != (const Cell &cell) const { return !operator == (cell); }
|
||||
bool operator == (Cell const& cell) const { return (data.All == cell.data.All); }
|
||||
bool operator != (Cell const& cell) const { return !operator == (cell); }
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -161,15 +107,13 @@ struct Cell
|
||||
uint32 All;
|
||||
} data;
|
||||
|
||||
template<class T, class CONTAINER> void Visit(const CellCoord&, TypeContainerVisitor<T, CONTAINER> &visitor, Map &) const;
|
||||
template<class T, class CONTAINER> void Visit(const CellCoord&, TypeContainerVisitor<T, CONTAINER> &visitor, Map &, const WorldObject&, float) const;
|
||||
template<class T, class CONTAINER> void Visit(const CellCoord&, TypeContainerVisitor<T, CONTAINER> &visitor, Map &, float, float, float) const;
|
||||
template<class T, class CONTAINER> void Visit(CellCoord const&, TypeContainerVisitor<T, CONTAINER>& visitor, Map &, WorldObject const&, float) const;
|
||||
template<class T, class CONTAINER> void Visit(CellCoord const&, TypeContainerVisitor<T, CONTAINER>& visitor, Map &, float, float, float) const;
|
||||
|
||||
static CellArea CalculateCellArea(const WorldObject &obj, float radius);
|
||||
static CellArea CalculateCellArea(float x, float y, float radius);
|
||||
|
||||
private:
|
||||
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER> &, Map &, const CellCoord&, const CellCoord&) const;
|
||||
template<class T, class CONTAINER> void VisitCircle(TypeContainerVisitor<T, CONTAINER> &, Map &, CellCoord const&, CellCoord const&) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,140 +46,22 @@ inline Cell::Cell(float x, float y)
|
||||
data.Part.reserved = 0;
|
||||
}
|
||||
|
||||
template<class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m) const
|
||||
{
|
||||
if (!standing_cell.IsCoordValid())
|
||||
return;
|
||||
|
||||
uint16 district = (District)this->data.Part.reserved;
|
||||
if (district == CENTER_DISTRICT)
|
||||
{
|
||||
m.Visit(*this, visitor);
|
||||
return;
|
||||
}
|
||||
|
||||
// set up the cell range based on the district
|
||||
CellCoord begin_cell = standing_cell;
|
||||
CellCoord end_cell = standing_cell;
|
||||
|
||||
switch (district)
|
||||
{
|
||||
case ALL_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
|
||||
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
|
||||
break;
|
||||
}
|
||||
case UPPER_LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
|
||||
break;
|
||||
}
|
||||
case UPPER_RIGHT_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_y(1); // up
|
||||
end_cell.inc_x(1); // right
|
||||
break;
|
||||
}
|
||||
case LOWER_LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); // left
|
||||
end_cell.inc_y(1); // down
|
||||
break;
|
||||
}
|
||||
case LOWER_RIGHT_DISTRICT:
|
||||
{
|
||||
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
|
||||
break;
|
||||
}
|
||||
case LEFT_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_y(1); // up
|
||||
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
|
||||
break;
|
||||
}
|
||||
case RIGHT_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
|
||||
end_cell.inc_y(1); // down
|
||||
break;
|
||||
}
|
||||
case UPPER_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); begin_cell.dec_y(1); // upper left
|
||||
end_cell.inc_x(1); // right
|
||||
break;
|
||||
}
|
||||
case LOWER_DISTRICT:
|
||||
{
|
||||
begin_cell.dec_x(1); // left
|
||||
end_cell.inc_x(1); end_cell.inc_y(1); // lower right
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// loop the cell range
|
||||
for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
|
||||
{
|
||||
for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
|
||||
{
|
||||
CellCoord cellCoord(x, y);
|
||||
Cell r_zone(cellCoord);
|
||||
r_zone.data.Part.nocreate = this->data.Part.nocreate;
|
||||
m.Visit(r_zone, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline int CellHelper(const float radius)
|
||||
{
|
||||
if (radius < 1.0f)
|
||||
return 0;
|
||||
|
||||
return (int)ceilf(radius/SIZE_OF_GRID_CELL);
|
||||
}
|
||||
|
||||
inline CellArea Cell::CalculateCellArea(const WorldObject &obj, float radius)
|
||||
{
|
||||
return Cell::CalculateCellArea(obj.GetPositionX(), obj.GetPositionY(), radius);
|
||||
}
|
||||
|
||||
inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
|
||||
{
|
||||
if (radius <= 0.0f)
|
||||
return CellArea();
|
||||
{
|
||||
CellCoord center = Trinity::ComputeCellCoord(x, y).normalize();
|
||||
return CellArea(center, center);
|
||||
}
|
||||
|
||||
//lets calculate object coord offsets from cell borders.
|
||||
//TODO: add more correct/generic method for this task
|
||||
const float x_offset = (x - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
|
||||
const float y_offset = (y - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
|
||||
CellCoord centerX = Trinity::ComputeCellCoord(x - radius, y - radius).normalize();
|
||||
CellCoord centerY = Trinity::ComputeCellCoord(x + radius, y + radius).normalize();
|
||||
|
||||
const float x_val = floor(x_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
const float y_val = floor(y_offset + CENTER_GRID_CELL_ID + 0.5f);
|
||||
|
||||
const float x_off = (x_offset - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
const float y_off = (y_offset - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
|
||||
|
||||
const float tmp_diff = radius - CENTER_GRID_CELL_OFFSET;
|
||||
//lets calculate upper/lower/right/left corners for cell search
|
||||
int right = CellHelper(tmp_diff + x_off);
|
||||
int left = CellHelper(tmp_diff - x_off);
|
||||
int upper = CellHelper(tmp_diff + y_off);
|
||||
int lower = CellHelper(tmp_diff - y_off);
|
||||
|
||||
return CellArea(right, left, upper, lower);
|
||||
return CellArea(centerX, centerY);
|
||||
}
|
||||
|
||||
template<class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, float radius, float x_off, float y_off) const
|
||||
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float radius, float x_off, float y_off) const
|
||||
{
|
||||
if (!standing_cell.IsCoordValid())
|
||||
return;
|
||||
@@ -189,7 +71,7 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
|
||||
//maybe it is better to just return when radius <= 0.0f?
|
||||
if (radius <= 0.0f)
|
||||
{
|
||||
m.Visit(*this, visitor);
|
||||
map.Visit(*this, visitor);
|
||||
return;
|
||||
}
|
||||
//lets limit the upper value for search radius
|
||||
@@ -201,32 +83,28 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
|
||||
//if radius fits inside standing cell
|
||||
if (!area)
|
||||
{
|
||||
m.Visit(*this, visitor);
|
||||
map.Visit(*this, visitor);
|
||||
return;
|
||||
}
|
||||
|
||||
CellCoord begin_cell = standing_cell;
|
||||
CellCoord end_cell = standing_cell;
|
||||
|
||||
area.ResizeBorders(begin_cell, end_cell);
|
||||
//visit all cells, found in CalculateCellArea()
|
||||
//if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle
|
||||
//currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values
|
||||
//there are nothing to optimize because SIZE_OF_GRID_CELL is too big...
|
||||
if (((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4))
|
||||
if (((area.high_bound.x_coord - area.low_bound.x_coord) > 4) && ((area.high_bound.y_coord - area.low_bound.y_coord) > 4))
|
||||
{
|
||||
VisitCircle(visitor, m, begin_cell, end_cell);
|
||||
VisitCircle(visitor, map, area.low_bound, area.high_bound);
|
||||
return;
|
||||
}
|
||||
|
||||
//ALWAYS visit standing cell first!!! Since we deal with small radiuses
|
||||
//it is very essential to call visitor for standing cell firstly...
|
||||
m.Visit(*this, visitor);
|
||||
map.Visit(*this, visitor);
|
||||
|
||||
// loop the cell range
|
||||
for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
|
||||
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
|
||||
{
|
||||
for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
|
||||
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
|
||||
{
|
||||
CellCoord cellCoord(x, y);
|
||||
//lets skip standing cell since we already visited it
|
||||
@@ -234,24 +112,22 @@ Cell::Visit(const CellCoord& standing_cell, TypeContainerVisitor<T, CONTAINER> &
|
||||
{
|
||||
Cell r_zone(cellCoord);
|
||||
r_zone.data.Part.nocreate = this->data.Part.nocreate;
|
||||
m.Visit(r_zone, visitor);
|
||||
map.Visit(r_zone, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::Visit(const CellCoord& l, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const WorldObject &obj, float radius) const
|
||||
inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, WorldObject const& obj, float radius) const
|
||||
{
|
||||
//we should increase search radius by object's radius, otherwise
|
||||
//we could have problems with huge creatures, which won't attack nearest players etc
|
||||
Visit(l, visitor, m, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY());
|
||||
Visit(standing_cell, visitor, map, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY());
|
||||
}
|
||||
|
||||
template<class T, class CONTAINER>
|
||||
inline void
|
||||
Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const CellCoord& begin_cell, const CellCoord& end_cell) const
|
||||
inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, CellCoord const& begin_cell, CellCoord const& end_cell) const
|
||||
{
|
||||
//here is an algorithm for 'filling' circum-squared octagon
|
||||
uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f);
|
||||
@@ -267,7 +143,7 @@ Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const Cel
|
||||
CellCoord cellCoord(x, y);
|
||||
Cell r_zone(cellCoord);
|
||||
r_zone.data.Part.nocreate = this->data.Part.nocreate;
|
||||
m.Visit(r_zone, visitor);
|
||||
map.Visit(r_zone, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,13 +167,13 @@ Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const Cel
|
||||
CellCoord cellCoord_left(x_start - step, y);
|
||||
Cell r_zone_left(cellCoord_left);
|
||||
r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
|
||||
m.Visit(r_zone_left, visitor);
|
||||
map.Visit(r_zone_left, visitor);
|
||||
|
||||
//right trapezoid cell visit
|
||||
CellCoord cellCoord_right(x_end + step, y);
|
||||
Cell r_zone_right(cellCoord_right);
|
||||
r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
|
||||
m.Visit(r_zone_right, visitor);
|
||||
map.Visit(r_zone_right, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,13 @@ struct CoordPair
|
||||
return x_coord < LIMIT && y_coord < LIMIT;
|
||||
}
|
||||
|
||||
CoordPair& normalize()
|
||||
{
|
||||
x_coord = std::min(x_coord, LIMIT - 1);
|
||||
y_coord = std::min(y_coord, LIMIT - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32 x_coord;
|
||||
uint32 y_coord;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user