mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 14:16:31 +00:00
Project restructuring [PART.3]
This commit is contained in:
264
modules/worldengine/lib-collision/src/RegularGrid.h
Normal file
264
modules/worldengine/lib-collision/src/RegularGrid.h
Normal file
@@ -0,0 +1,264 @@
|
||||
#ifndef _REGULAR_GRID_H
|
||||
#define _REGULAR_GRID_H
|
||||
|
||||
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Table.h>
|
||||
#include <G3D/BoundsTrait.h>
|
||||
#include <G3D/PositionTrait.h>
|
||||
|
||||
#include "Errors.h"
|
||||
|
||||
template <class Node>
|
||||
class NodeArray
|
||||
{
|
||||
public:
|
||||
explicit NodeArray() { memset(&_nodes, 0, sizeof(_nodes)); }
|
||||
void AddNode(Node* n)
|
||||
{
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
if (_nodes[i] == 0)
|
||||
{
|
||||
_nodes[i] = n;
|
||||
return;
|
||||
}
|
||||
else if (_nodes[i] == n)
|
||||
return;
|
||||
}
|
||||
Node* _nodes[9];
|
||||
};
|
||||
|
||||
template<class Node>
|
||||
struct NodeCreator{
|
||||
static Node * makeNode(int /*x*/, int /*y*/) { return new Node();}
|
||||
};
|
||||
|
||||
template<class T,
|
||||
class Node,
|
||||
class NodeCreatorFunc = NodeCreator<Node>,
|
||||
/*class BoundsFunc = BoundsTrait<T>,*/
|
||||
class PositionFunc = PositionTrait<T>
|
||||
>
|
||||
class RegularGrid2D
|
||||
{
|
||||
public:
|
||||
|
||||
enum{
|
||||
CELL_NUMBER = 64,
|
||||
};
|
||||
|
||||
#define HGRID_MAP_SIZE (533.33333f * 64.f) // shouldn't be changed
|
||||
#define CELL_SIZE float(HGRID_MAP_SIZE/(float)CELL_NUMBER)
|
||||
|
||||
typedef G3D::Table<const T*, NodeArray<Node> > MemberTable;
|
||||
|
||||
MemberTable memberTable;
|
||||
Node* nodes[CELL_NUMBER][CELL_NUMBER];
|
||||
|
||||
RegularGrid2D(){
|
||||
memset(nodes, 0, sizeof(nodes));
|
||||
}
|
||||
|
||||
~RegularGrid2D(){
|
||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||
delete nodes[x][y];
|
||||
}
|
||||
|
||||
void insert(const T& value)
|
||||
{
|
||||
G3D::Vector3 pos[9];
|
||||
pos[0] = value.getBounds().corner(0);
|
||||
pos[1] = value.getBounds().corner(1);
|
||||
pos[2] = value.getBounds().corner(2);
|
||||
pos[3] = value.getBounds().corner(3);
|
||||
pos[4] = (pos[0] + pos[1])/2.0f;
|
||||
pos[5] = (pos[1] + pos[2])/2.0f;
|
||||
pos[6] = (pos[2] + pos[3])/2.0f;
|
||||
pos[7] = (pos[3] + pos[0])/2.0f;
|
||||
pos[8] = (pos[0] + pos[2])/2.0f;
|
||||
|
||||
NodeArray<Node> na;
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
Cell c = Cell::ComputeCell(pos[i].x, pos[i].y);
|
||||
if (!c.isValid())
|
||||
continue;
|
||||
Node& node = getGridFor(pos[i].x, pos[i].y);
|
||||
na.AddNode(&node);
|
||||
}
|
||||
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
if (na._nodes[i])
|
||||
na._nodes[i]->insert(value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
memberTable.set(&value, na);
|
||||
}
|
||||
|
||||
void remove(const T& value)
|
||||
{
|
||||
NodeArray<Node>& na = memberTable[&value];
|
||||
for (uint8 i=0; i<9; ++i)
|
||||
{
|
||||
if (na._nodes[i])
|
||||
na._nodes[i]->remove(value);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the member
|
||||
memberTable.remove(&value);
|
||||
}
|
||||
|
||||
void balance()
|
||||
{
|
||||
for (int x = 0; x < CELL_NUMBER; ++x)
|
||||
for (int y = 0; y < CELL_NUMBER; ++y)
|
||||
if (Node* n = nodes[x][y])
|
||||
n->balance();
|
||||
}
|
||||
|
||||
bool contains(const T& value) const { return memberTable.containsKey(&value); }
|
||||
int size() const { return memberTable.size(); }
|
||||
|
||||
struct Cell
|
||||
{
|
||||
int x, y;
|
||||
bool operator == (const Cell& c2) const { return x == c2.x && y == c2.y;}
|
||||
|
||||
static Cell ComputeCell(float fx, float fy)
|
||||
{
|
||||
Cell c = { int(fx * (1.f/CELL_SIZE) + (CELL_NUMBER/2)), int(fy * (1.f/CELL_SIZE) + (CELL_NUMBER/2)) };
|
||||
return c;
|
||||
}
|
||||
|
||||
bool isValid() const { return x >= 0 && x < CELL_NUMBER && y >= 0 && y < CELL_NUMBER;}
|
||||
};
|
||||
|
||||
|
||||
Node& getGridFor(float fx, float fy)
|
||||
{
|
||||
Cell c = Cell::ComputeCell(fx, fy);
|
||||
return getGrid(c.x, c.y);
|
||||
}
|
||||
|
||||
Node& getGrid(int x, int y)
|
||||
{
|
||||
ASSERT(x < CELL_NUMBER && y < CELL_NUMBER);
|
||||
if (!nodes[x][y])
|
||||
nodes[x][y] = NodeCreatorFunc::makeNode(x, y);
|
||||
return *nodes[x][y];
|
||||
}
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float max_dist, bool stopAtFirstHit)
|
||||
{
|
||||
intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist, stopAtFirstHit);
|
||||
}
|
||||
|
||||
template<typename RayCallback>
|
||||
void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist, const G3D::Vector3& end, bool stopAtFirstHit)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
|
||||
Cell last_cell = Cell::ComputeCell(end.x, end.y);
|
||||
|
||||
if (cell == last_cell)
|
||||
{
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||
return;
|
||||
}
|
||||
|
||||
float voxel = (float)CELL_SIZE;
|
||||
float kx_inv = ray.invDirection().x, bx = ray.origin().x;
|
||||
float ky_inv = ray.invDirection().y, by = ray.origin().y;
|
||||
|
||||
int stepX, stepY;
|
||||
float tMaxX, tMaxY;
|
||||
if (kx_inv >= 0)
|
||||
{
|
||||
stepX = 1;
|
||||
float x_border = (cell.x+1) * voxel;
|
||||
tMaxX = (x_border - bx) * kx_inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepX = -1;
|
||||
float x_border = (cell.x-1) * voxel;
|
||||
tMaxX = (x_border - bx) * kx_inv;
|
||||
}
|
||||
|
||||
if (ky_inv >= 0)
|
||||
{
|
||||
stepY = 1;
|
||||
float y_border = (cell.y+1) * voxel;
|
||||
tMaxY = (y_border - by) * ky_inv;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepY = -1;
|
||||
float y_border = (cell.y-1) * voxel;
|
||||
tMaxY = (y_border - by) * ky_inv;
|
||||
}
|
||||
|
||||
//int Cycles = std::max((int)ceilf(max_dist/tMaxX),(int)ceilf(max_dist/tMaxY));
|
||||
//int i = 0;
|
||||
|
||||
float tDeltaX = voxel * fabs(kx_inv);
|
||||
float tDeltaY = voxel * fabs(ky_inv);
|
||||
do
|
||||
{
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
{
|
||||
//float enterdist = max_dist;
|
||||
node->intersectRay(ray, intersectCallback, max_dist, stopAtFirstHit);
|
||||
}
|
||||
if (cell == last_cell)
|
||||
break;
|
||||
if (tMaxX < tMaxY)
|
||||
{
|
||||
tMaxX += tDeltaX;
|
||||
cell.x += stepX;
|
||||
}
|
||||
else
|
||||
{
|
||||
tMaxY += tDeltaY;
|
||||
cell.y += stepY;
|
||||
}
|
||||
//++i;
|
||||
} while (cell.isValid());
|
||||
}
|
||||
|
||||
template<typename IsectCallback>
|
||||
void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(point.x, point.y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectPoint(point, intersectCallback);
|
||||
}
|
||||
|
||||
// Optimized verson of intersectRay function for rays with vertical directions
|
||||
template<typename RayCallback>
|
||||
void intersectZAllignedRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist)
|
||||
{
|
||||
Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y);
|
||||
if (!cell.isValid())
|
||||
return;
|
||||
if (Node* node = nodes[cell.x][cell.y])
|
||||
node->intersectRay(ray, intersectCallback, max_dist, false);
|
||||
}
|
||||
};
|
||||
|
||||
#undef CELL_SIZE
|
||||
#undef HGRID_MAP_SIZE
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user