Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,504 @@
|
||||
#include "physics_world.h"
|
||||
#include <vec2.h>
|
||||
#include <math.h>
|
||||
#include "threads.h"
|
||||
#include "obj/object.h"
|
||||
#include "empire.h"
|
||||
#include "network/message.h"
|
||||
#include "util/save_file.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include "main/references.h"
|
||||
#include "main/logging.h"
|
||||
|
||||
#include "compat/intrin.h"
|
||||
|
||||
#define SPLIT_COUNT 16
|
||||
#define REBALANCE_RATIO 4
|
||||
#define MAX_DEPTH 8
|
||||
|
||||
PhysicsWorld::PhysicsWorld(double GridSize, double GridFuzz, unsigned GridCount)
|
||||
: gridSize(GridSize), halfGridSize(GridSize * 0.5), gridFuzz(GridFuzz), gridCount(GridCount)
|
||||
{
|
||||
while(gridCount > 200) {
|
||||
gridCount = (gridCount + 1)/2;
|
||||
gridSize *= 2.0;
|
||||
halfGridSize *= 2.0;
|
||||
}
|
||||
|
||||
outside.bound.reset(AABBoxd::fromCircle(vec3d(),1.0e12));
|
||||
outside.fuzzBound = outside.bound;
|
||||
outside.itemCount = 0;
|
||||
|
||||
grid = new PhysicsGrid[gridCount*gridCount];
|
||||
for(unsigned x = 0; x < gridCount; ++x) {
|
||||
for(unsigned y = 0; y < gridCount; ++y) {
|
||||
auto& zone = grid[x*gridCount + y];
|
||||
zone.itemCount = 0;
|
||||
|
||||
for(unsigned i = 0; i < 32; ++i)
|
||||
zone.groups[i].fuzz = gridFuzz;
|
||||
|
||||
vec2d pos = vec2d(vec2i(x,y) - vec2i(gridCount / 2)) * gridSize;
|
||||
|
||||
zone.bound.reset(vec3d(pos.x,-100000.0,pos.y));
|
||||
zone.bound.addPoint(vec3d(pos.x+gridSize,100000.0,pos.y+gridSize));
|
||||
|
||||
zone.fuzzBound.reset(zone.bound.minimum - vec3d(gridFuzz));
|
||||
zone.fuzzBound.addPoint(zone.bound.maximum + vec3d(gridFuzz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PhysicsWorld::~PhysicsWorld() {
|
||||
delete[] grid;
|
||||
}
|
||||
|
||||
//Gets the grid index for x
|
||||
unsigned PhysicsWorld::getBox(double x) const {
|
||||
int index = int(floor(x / gridSize)) + int(gridCount / 2);
|
||||
if(index <= 0)
|
||||
return 0;
|
||||
if(index >= (int)gridCount-1)
|
||||
return gridCount-1;
|
||||
return index;
|
||||
}
|
||||
|
||||
//Gets the smallest grid index that could contain x
|
||||
unsigned PhysicsWorld::getLowerBound(double x) const {
|
||||
double dIndex = floor(x / gridSize);
|
||||
double pct = (x / gridSize) - dIndex;
|
||||
|
||||
int index = int(dIndex) + int(gridCount / 2);
|
||||
if(pct < gridFuzz / gridSize)
|
||||
index -= 1;
|
||||
|
||||
if(index <= 0)
|
||||
return 0;
|
||||
if(index >= (int)gridCount-1)
|
||||
return gridCount-1;
|
||||
return index;
|
||||
}
|
||||
|
||||
//Gets the largest grid index that could contain x
|
||||
unsigned PhysicsWorld::getUpperBound(double x) const {
|
||||
double dIndex = floor(x / gridSize);
|
||||
double pct = (x / gridSize) - dIndex;
|
||||
|
||||
int index = int(dIndex) + int(gridCount / 2);
|
||||
if(pct > 1.0 - (gridFuzz / gridSize))
|
||||
index += 1;
|
||||
|
||||
if(index <= 0)
|
||||
return 0;
|
||||
if(index >= (int)gridCount-1)
|
||||
return gridCount-1;
|
||||
return index;
|
||||
}
|
||||
|
||||
void PhysBisect::findInBox(const AABBoxd& box, const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask) const {
|
||||
if(!items.empty()) {
|
||||
auto* pItems = &items.front();
|
||||
for(auto* end = pItems + items.size(), *next = pItems + 1; pItems != end; pItems = next, ++next) {
|
||||
auto& item = **pItems;
|
||||
//Prefetch all 3 cache lines that the next item's bound occupies
|
||||
if(next != end) {
|
||||
auto* pNextItem = *next;
|
||||
PREFETCH((const char*)pNextItem + offsetof(PhysicsItem,bound));
|
||||
PREFETCH((const char*)pNextItem + offsetof(PhysicsItem,bound) + (2 * sizeof(double)));
|
||||
PREFETCH((const char*)pNextItem + offsetof(PhysicsItem,bound) + (4 * sizeof(double)));
|
||||
}
|
||||
if(box.overlaps(item.bound))
|
||||
callback(item);
|
||||
}
|
||||
}
|
||||
|
||||
if(a) {
|
||||
int dir = classify(box);
|
||||
|
||||
if(dir != 1)
|
||||
a->findInBox(box, callback, ownerMask);
|
||||
if(dir != -1)
|
||||
b->findInBox(box, callback, ownerMask);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysBisect::fuse() {
|
||||
if(!a)
|
||||
return;
|
||||
|
||||
a->fuse(items);
|
||||
b->fuse(items);
|
||||
a = b = 0;
|
||||
childrenA = childrenB = 0;
|
||||
}
|
||||
|
||||
void PhysBisect::fuse(std::vector<PhysicsItem*>& into) {
|
||||
if(a) {
|
||||
a->fuse(into);
|
||||
b->fuse(into);
|
||||
}
|
||||
|
||||
into.insert(into.end(), items.begin(), items.end());
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PhysBisect::split() {
|
||||
if(depth == MAX_DEPTH)
|
||||
return;
|
||||
a = new PhysBisect();
|
||||
b = new PhysBisect();
|
||||
|
||||
a->fuzz = b->fuzz = fuzz * 0.5;
|
||||
a->depth = b->depth = depth + 1;
|
||||
|
||||
a->parent = b->parent = this;
|
||||
a->xSplit = b->xSplit = !xSplit;
|
||||
|
||||
if(xSplit) {
|
||||
//Estimate a median value to split around
|
||||
double values[10];
|
||||
if(items.size() <= 10) {
|
||||
for(unsigned i = 0, cnt = (unsigned)items.size(); i < cnt; ++i) {
|
||||
auto* item = items[i];
|
||||
values[i] = (item->bound.minimum.x + item->bound.maximum.x) * 0.5;
|
||||
}
|
||||
std::sort(values, values + items.size());
|
||||
dimSplit = values[items.size() / 2];
|
||||
}
|
||||
else {
|
||||
unsigned step = (unsigned)items.size() / 10;
|
||||
for(unsigned i = 0; i < 10; ++i) {
|
||||
auto* item = items[i * step];
|
||||
values[i] = (item->bound.minimum.x + item->bound.maximum.x) * 0.5;
|
||||
}
|
||||
std::sort(values, values + 10);
|
||||
dimSplit = values[5];
|
||||
}
|
||||
|
||||
for(int i = (int)items.size() - 1; i >= 0; --i) {
|
||||
PhysicsItem* item = items[i];
|
||||
int location = classifyContainer(item->bound);
|
||||
if(location == -1) {
|
||||
a->items.push_back(item);
|
||||
items.erase(items.begin() + i);
|
||||
childrenA++;
|
||||
}
|
||||
else if(location == 1) {
|
||||
b->items.push_back(item);
|
||||
items.erase(items.begin() + i);
|
||||
childrenB++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
double values[10];
|
||||
if(items.size() <= 10) {
|
||||
for(unsigned i = 0, cnt = (unsigned)items.size(); i < cnt; ++i) {
|
||||
auto* item = items[i];
|
||||
values[i] = (item->bound.minimum.z + item->bound.maximum.z) * 0.5;
|
||||
}
|
||||
std::sort(values, values + items.size());
|
||||
dimSplit = values[items.size() / 2];
|
||||
}
|
||||
else {
|
||||
unsigned step = (unsigned)items.size() / 10;
|
||||
for(unsigned i = 0; i < 10; ++i) {
|
||||
auto* item = items[i * step];
|
||||
values[i] = (item->bound.minimum.z + item->bound.maximum.z) * 0.5;
|
||||
}
|
||||
std::sort(values, values + 10);
|
||||
dimSplit = values[5];
|
||||
}
|
||||
|
||||
for(int i = (int)items.size() - 1; i >= 0; --i) {
|
||||
PhysicsItem* item = items[i];
|
||||
int location = classifyContainer(item->bound);
|
||||
if(location == -1) {
|
||||
a->items.push_back(item);
|
||||
items.erase(items.begin() + i);
|
||||
childrenA++;
|
||||
}
|
||||
else if(location == 1) {
|
||||
b->items.push_back(item);
|
||||
items.erase(items.begin() + i);
|
||||
childrenB++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(a->items.size() > SPLIT_COUNT)
|
||||
a->split();
|
||||
if(b->items.size() > SPLIT_COUNT)
|
||||
b->split();
|
||||
}
|
||||
|
||||
void PhysicsWorld::findInBoxInZone(const PhysicsGrid& zone, const AABBoxd& box,
|
||||
const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask) {
|
||||
threads::ReadLock lock(zone.mutex);
|
||||
//if(ownerMask == ~0u) {
|
||||
//findInBoxInZone(zone, box, callback);
|
||||
// zone.findInBox(box, callback, ~0);
|
||||
// return;
|
||||
//}
|
||||
|
||||
for(unsigned i = 0; i < 32; ++i)
|
||||
if(ownerMask & (1 << i))
|
||||
zone.groups[i].findInBox(box, callback, 0);
|
||||
}
|
||||
|
||||
void PhysicsWorld::findInBox(const AABBoxd& box, const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask) {
|
||||
//double start = devices.driver->getAccurateTime();
|
||||
unsigned fromX = getLowerBound(box.minimum.x), toX = getUpperBound(box.maximum.x);
|
||||
unsigned fromY = getLowerBound(box.minimum.z), toY = getUpperBound(box.maximum.z);
|
||||
|
||||
for(unsigned x = fromX; x <= toX; ++x) {
|
||||
for(unsigned y = fromY; y <= toY; ++y) {
|
||||
const PhysicsGrid& zone = grid[x * gridCount + y];
|
||||
if(!zone.empty() && box.overlaps(zone.fuzzBound))
|
||||
findInBoxInZone(zone, box, callback, ownerMask);
|
||||
}
|
||||
}
|
||||
|
||||
if(!outside.empty())
|
||||
findInBoxInZone(outside, box, callback, ownerMask);
|
||||
//double end = devices.driver->getAccurateTime();
|
||||
//error("%d\n", (int)((end - start) * 1e6));
|
||||
}
|
||||
|
||||
bool PhysicsGrid::empty() const {
|
||||
return itemCount == 0;
|
||||
}
|
||||
|
||||
void PhysicsGrid::removeItem(PhysicsItem* item) {
|
||||
mutex.writeLock();
|
||||
itemCount -= 1;
|
||||
PhysBisect* bisect = &groups[item->maskID];
|
||||
while(bisect->a) {
|
||||
int location = bisect->classifyContainer(item->bound);
|
||||
if(location == -1) {
|
||||
bisect->childrenA--;
|
||||
bisect = bisect->a;
|
||||
}
|
||||
else if(location == 1) {
|
||||
bisect->childrenB--;
|
||||
bisect = bisect->b;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
bool itemRemoved = false;
|
||||
|
||||
for(auto i = bisect->items.begin(), end = bisect->items.end(); i != end; ++i) {
|
||||
if((*i) == item) {
|
||||
itemRemoved = true;
|
||||
bisect->items.erase(i);
|
||||
|
||||
while(bisect->items.empty() && bisect->parent && bisect->a == 0) {
|
||||
auto parent = bisect->parent;
|
||||
parent->fuse();
|
||||
if(parent->items.size() > SPLIT_COUNT)
|
||||
parent->split();
|
||||
bisect = parent;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex.release();
|
||||
|
||||
if(!itemRemoved)
|
||||
throw "Unable to locate physics item";
|
||||
}
|
||||
|
||||
void PhysicsGrid::addItem(PhysicsItem* item) {
|
||||
mutex.writeLock();
|
||||
itemCount += 1;
|
||||
PhysBisect* bisect = &groups[item->maskID];
|
||||
while(bisect->a) {
|
||||
int location = bisect->classifyContainer(item->bound);
|
||||
if(location == -1) {
|
||||
bisect->childrenA++;
|
||||
bisect = bisect->a;
|
||||
}
|
||||
else if(location == 1) {
|
||||
bisect->childrenB++;
|
||||
bisect = bisect->b;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
bisect->items.push_back(item);
|
||||
if(bisect->a) {
|
||||
PhysBisect* refuse = 0;
|
||||
while(bisect->childrenA > REBALANCE_RATIO * bisect->childrenB || bisect->childrenB > REBALANCE_RATIO * bisect->childrenA) {
|
||||
refuse = bisect;
|
||||
bisect = bisect->parent;
|
||||
if(bisect == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(refuse) {
|
||||
refuse->fuse();
|
||||
if(refuse->items.size() > SPLIT_COUNT)
|
||||
refuse->split();
|
||||
}
|
||||
}
|
||||
else if(bisect->items.size() > SPLIT_COUNT) {
|
||||
bisect->split();
|
||||
}
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
void PhysicsGrid::updateItem(PhysicsItem* item, const AABBoxd& newBound) {
|
||||
unsigned maskID = 1;
|
||||
if(item->type == PIT_Object)
|
||||
maskID = (item->object->owner ? item->object->owner->id : 1);
|
||||
if(maskID >= 32)
|
||||
maskID = 0;
|
||||
|
||||
if(maskID == item->maskID) {
|
||||
PhysBisect* bisect = &groups[item->maskID];
|
||||
|
||||
bool sameLocation = true;
|
||||
|
||||
mutex.readLock();
|
||||
while(bisect->a) {
|
||||
int location = bisect->classifyContainer(item->bound);
|
||||
int newLoc = bisect->classifyContainer(newBound);
|
||||
if(location != newLoc) {
|
||||
sameLocation = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(location == -1)
|
||||
bisect = bisect->a;
|
||||
else if(location == 1)
|
||||
bisect = bisect->b;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(sameLocation) {
|
||||
item->bound = newBound;
|
||||
mutex.release();
|
||||
return;
|
||||
}
|
||||
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
//Container has changed
|
||||
mutex.writeLock();
|
||||
|
||||
removeItem(item);
|
||||
item->bound = newBound;
|
||||
item->maskID = maskID;
|
||||
addItem(item);
|
||||
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
//TODO: Handle things too big for the grid, or outside the grid
|
||||
void PhysicsWorld::updateItem(PhysicsItem& item, const AABBoxd& newBox) {
|
||||
if(newBox.isWithin(item.gridLocation->fuzzBound)) {
|
||||
//TODO: Handle transition back from 'outside' if it is now able to be positioned in the grid
|
||||
item.gridLocation->updateItem(&item, newBox);
|
||||
}
|
||||
else {
|
||||
item.gridLocation->removeItem(&item);
|
||||
|
||||
vec3d center = newBox.getCenter();
|
||||
unsigned x = getBox(center.x), y = getBox(center.z);
|
||||
item.bound = newBox;
|
||||
|
||||
PhysicsGrid* newGrid = &grid[x*gridCount + y];
|
||||
if(!newBox.isWithin(newGrid->fuzzBound))
|
||||
newGrid = &outside;
|
||||
item.gridLocation = newGrid;
|
||||
newGrid->addItem(&item);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsWorld::registerItem(PhysicsItem& item) {
|
||||
assert((item.type & PIT_Object) == 0 || item.object);
|
||||
|
||||
vec3d center = item.bound.getCenter();
|
||||
unsigned x = getBox(center.x), y = getBox(center.z);
|
||||
|
||||
PhysicsGrid* newGrid = &grid[x*gridCount + y];
|
||||
if(!item.bound.isWithin(newGrid->fuzzBound))
|
||||
newGrid = &outside;
|
||||
|
||||
item.gridLocation = newGrid;
|
||||
newGrid->addItem(&item);
|
||||
}
|
||||
|
||||
PhysicsItem* PhysicsWorld::registerItem(const AABBoxd& bounds, Object* obj) {
|
||||
PhysicsItem* item = new PhysicsItem;
|
||||
item->bound = bounds;
|
||||
item->object = obj;
|
||||
item->type = PIT_Object;
|
||||
|
||||
unsigned maskID = (obj->owner ? obj->owner->id : 1);
|
||||
if(maskID >= 32)
|
||||
maskID = 0;
|
||||
item->maskID = maskID;
|
||||
|
||||
registerItem(*item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
PhysicsItem* PhysicsWorld::registerItem(const AABBoxd& bounds, scene::Node* node) {
|
||||
PhysicsItem* item = new PhysicsItem;
|
||||
item->bound = bounds;
|
||||
item->node = node;
|
||||
item->type = PIT_Node;
|
||||
item->maskID = 0;
|
||||
|
||||
registerItem(*item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void PhysicsWorld::unregisterItem(PhysicsItem& item) {
|
||||
item.gridLocation->removeItem(&item);
|
||||
}
|
||||
|
||||
PhysicsWorld* PhysicsWorld::fromMessage(net::Message& msg) {
|
||||
double gridSize, gridFuzz;
|
||||
unsigned gridCount;
|
||||
|
||||
msg >> gridSize;
|
||||
msg >> gridFuzz;
|
||||
msg >> gridCount;
|
||||
|
||||
return new PhysicsWorld(gridSize, gridFuzz, gridCount);
|
||||
}
|
||||
|
||||
PhysicsWorld* PhysicsWorld::fromSave(SaveFile& file) {
|
||||
double gridSize, gridFuzz;
|
||||
unsigned gridCount;
|
||||
|
||||
file >> gridSize;
|
||||
file >> gridFuzz;
|
||||
file >> gridCount;
|
||||
|
||||
return new PhysicsWorld(gridSize, gridFuzz, gridCount);
|
||||
}
|
||||
|
||||
void PhysicsWorld::writeSetup(net::Message& msg) {
|
||||
msg << gridSize;
|
||||
msg << gridFuzz;
|
||||
msg << gridCount;
|
||||
}
|
||||
|
||||
void PhysicsWorld::writeSetup(SaveFile& file) {
|
||||
file << gridSize;
|
||||
file << gridFuzz;
|
||||
file << gridCount;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
#include "aabbox.h"
|
||||
#include "util/refcount.h"
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
enum PhysItemType {
|
||||
PIT_Object = 0x01,
|
||||
PIT_Node = 0x02,
|
||||
//A group is both the type of PIT_Group, and the type of objects in the group
|
||||
PIT_Group = 0x80,
|
||||
};
|
||||
|
||||
class Object;
|
||||
struct PhysicsGrid;
|
||||
struct PhysicsItem;
|
||||
struct PhysicsGroup;
|
||||
class SaveFile;
|
||||
|
||||
namespace scene {
|
||||
class Node;
|
||||
};
|
||||
|
||||
namespace net {
|
||||
struct Message;
|
||||
};
|
||||
|
||||
struct PhysicsItem {
|
||||
AABBoxd bound;
|
||||
union {
|
||||
Object* object;
|
||||
scene::Node* node;
|
||||
PhysicsGroup* group;
|
||||
};
|
||||
unsigned maskID;
|
||||
PhysItemType type;
|
||||
PhysicsGrid* gridLocation;
|
||||
};
|
||||
|
||||
struct PhysicsGroup {
|
||||
unsigned itemCount;
|
||||
PhysicsItem* items;
|
||||
};
|
||||
|
||||
struct PhysBisect {
|
||||
std::vector<PhysicsItem*> items;
|
||||
PhysBisect *a, *b, *parent;
|
||||
unsigned childrenA, childrenB;
|
||||
bool xSplit;
|
||||
double dimSplit, fuzz;
|
||||
unsigned depth;
|
||||
|
||||
PhysBisect() : a(0), b(0), parent(0), depth(0), childrenA(0), childrenB(0), xSplit(true) {}
|
||||
|
||||
inline int classify(const AABBoxd& box) const {
|
||||
if(xSplit) {
|
||||
if(box.maximum.x < dimSplit - fuzz)
|
||||
return -1;
|
||||
if(box.minimum.x > dimSplit + fuzz)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if(box.maximum.z < dimSplit - fuzz)
|
||||
return -1;
|
||||
if(box.minimum.z > dimSplit + fuzz)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int classifyContainer(const AABBoxd& box) const {
|
||||
if(xSplit) {
|
||||
double center = (box.minimum.x + box.maximum.x) * 0.5;
|
||||
if(center >= dimSplit && box.minimum.x > dimSplit - fuzz)
|
||||
return 1;
|
||||
else if(center < dimSplit && box.maximum.x < dimSplit + fuzz)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
double center = (box.minimum.z + box.maximum.z) * 0.5;
|
||||
if(center >= dimSplit && box.minimum.z > dimSplit - fuzz)
|
||||
return 1;
|
||||
else if(center < dimSplit && box.maximum.z < dimSplit + fuzz)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void findInBox(const AABBoxd& box, const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask) const;
|
||||
|
||||
void split();
|
||||
void fuse();
|
||||
void fuse(std::vector<PhysicsItem*>& into);
|
||||
};
|
||||
|
||||
struct PhysicsGrid {
|
||||
PhysBisect groups[32];
|
||||
mutable threads::ReadWriteMutex mutex;
|
||||
AABBoxd bound, fuzzBound;
|
||||
unsigned itemCount;
|
||||
|
||||
void removeItem(PhysicsItem* item);
|
||||
void addItem(PhysicsItem* item);
|
||||
void updateItem(PhysicsItem* item, const AABBoxd& newBound);
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
class PhysicsWorld : public AtomicRefCounted {
|
||||
//Physical space that items exist withing
|
||||
PhysicsGrid* grid;
|
||||
//Catch-all for items that do not exist within the grid, or can't fit inside the grid
|
||||
PhysicsGrid outside;
|
||||
|
||||
//Access mutex
|
||||
threads::ReadWriteMutex mutex;
|
||||
|
||||
//Size of a grid square
|
||||
double gridSize, halfGridSize;
|
||||
//Grid fuzz margin
|
||||
double gridFuzz;
|
||||
//Number of grid squares on a side
|
||||
unsigned gridCount;
|
||||
|
||||
unsigned getBox(double x) const;
|
||||
unsigned getLowerBound(double x) const;
|
||||
unsigned getUpperBound(double x) const;
|
||||
|
||||
void findInBoxInZone(const PhysicsGrid& zone, const AABBoxd& box, const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask);
|
||||
public:
|
||||
PhysicsWorld(double GridSize = 3000.0, double GridFuzz = 350.0, unsigned GridCount = 60);
|
||||
~PhysicsWorld();
|
||||
|
||||
//Calls <callback> for each of the PhysicsItems within the box
|
||||
//Optionally filters by owner of the item (Mask 1 permits unowned objects)
|
||||
void findInBox(const AABBoxd& box, const std::function<void(const PhysicsItem&)>& callback, unsigned ownerMask = 0xffffffff);
|
||||
|
||||
void updateItem(PhysicsItem& item, const AABBoxd& newBox);
|
||||
PhysicsItem* registerItem(const AABBoxd& bounds, Object* obj);
|
||||
PhysicsItem* registerItem(const AABBoxd& bounds, scene::Node* node);
|
||||
void registerItem(PhysicsItem& item);
|
||||
void unregisterItem(PhysicsItem& item);
|
||||
|
||||
void writeSetup(net::Message& msg);
|
||||
void writeSetup(SaveFile& file);
|
||||
static PhysicsWorld* fromMessage(net::Message& msg);
|
||||
static PhysicsWorld* fromSave(SaveFile& file);
|
||||
};
|
||||
Reference in New Issue
Block a user