192 lines
5.9 KiB
C++
Executable file
192 lines
5.9 KiB
C++
Executable file
#ifndef _FMOD_OCTREE_H
|
|
#define _FMOD_OCTREE_H
|
|
|
|
// This is a compramise between an octree and an axis alligned bounding box tree.
|
|
// Basicaly an octree which splits space exactly in 8 equal quadrents each time,
|
|
// except that only the splits that are needed to seperate the objects are actually stored.
|
|
|
|
#include "fmod_settings.h"
|
|
|
|
#ifdef FMOD_SUPPORT_GEOMETRY
|
|
|
|
//#define FMOD_GEOMETRY_DEBUGGING
|
|
//#define FMOD_23TREE
|
|
|
|
#include "fmod.hpp"
|
|
|
|
namespace FMOD
|
|
{
|
|
|
|
struct FMOD_AABB
|
|
{
|
|
float xMin;
|
|
float xMax;
|
|
float yMin;
|
|
float yMax;
|
|
float zMin;
|
|
float zMax;
|
|
};
|
|
enum OctreeFlags
|
|
{
|
|
OCTREE_FLAG_X_SPLIT = 0x000,
|
|
OCTREE_FLAG_Y_SPLIT = 0x001,
|
|
OCTREE_FLAG_Z_SPLIT = 0x002,
|
|
OCTREE_FLAG_SPLIT_MASK = 0x003,
|
|
OCTREE_FLAG_LEAF = 0x004,
|
|
OCTREE_FLAG_CALCULATED_AABB = 0x008,
|
|
OCTREE_FLAG_EXTRA_NODE = 0x010,
|
|
OCTREE_FLAG_FREE = 0x020,
|
|
OCTREE_FLAG_INSERTED = 0x040,
|
|
OCTREE_FLAG_23LEAF = 0x080,
|
|
OCTREE_FLAG_23ROOT = 0x100,
|
|
OCTREE_FLAG_23NODE = 0x200,
|
|
OCTREE_FLAG_INTERNAL_NODE = 0x400,
|
|
};
|
|
|
|
struct OctreeNode
|
|
{
|
|
FMOD_AABB aabb;
|
|
int flags;
|
|
unsigned int splitLevel;
|
|
unsigned int pos[3];
|
|
|
|
OctreeNode *parent;
|
|
OctreeNode *hi;
|
|
OctreeNode *lo;
|
|
OctreeNode *nextItem;
|
|
};
|
|
|
|
class Octree
|
|
{
|
|
public:
|
|
// data stucture for the recursive testLine to save on extra
|
|
// parameters on the stack.
|
|
struct RecursionData
|
|
{
|
|
bool (*octreeLineTestCallback)(OctreeNode* item, void* data);
|
|
void *data;
|
|
bool exit;
|
|
};
|
|
|
|
// see setMaxSize for description of maxSize
|
|
Octree(float maxSize);
|
|
~Octree();
|
|
|
|
OctreeNode* mRoot;
|
|
FMOD_VECTOR mCenter;
|
|
float mScale;
|
|
OctreeNode* mFreeList;
|
|
|
|
// Inserting / deleting and updating items
|
|
void insertItem(OctreeNode* item);
|
|
void deleteItem(OctreeNode* item);
|
|
void updateItem(OctreeNode* item);
|
|
|
|
// For update optimzation
|
|
bool needsReinsert(OctreeNode* item);
|
|
void updateItemAABB(OctreeNode* item) { adjustAABBs(item); }
|
|
|
|
// Get the Axis Aligned Bounding Box that bounds the entire tree
|
|
void getAABB(FMOD_AABB* aabb);
|
|
|
|
// Internal nodes.
|
|
// A memory pool for internal tree nodes.
|
|
// The user is responsible for providing enough internal nodes.
|
|
// The maximum number of internal nodes necessery is equal to the number of
|
|
// leaf nodes added with insertItem.
|
|
void addInternalNode(OctreeNode* item);
|
|
void removeInternalNode(OctreeNode* item);
|
|
|
|
// Debugging functions
|
|
#if defined(_DEBUG) && defined(FMOD_GEOMETRY_DEBUGGING)
|
|
void checkTree(OctreeNode* node);
|
|
void calculateAverageNodeElements();
|
|
void checkNodeIsContained(OctreeNode* node);
|
|
void calculateAverageNodeElements(OctreeNode* node);
|
|
#endif
|
|
|
|
// same maxSize as passed as a parameter to the constructor.
|
|
// sets the maximum range in x,y and z for the tree.
|
|
// If the range is too large the tree will loose precision and
|
|
// if the range is too small, dimensions may wrap and items
|
|
// may end up in the top node. In both cases, the tree
|
|
// will still return all desired intersecting nodes, but may
|
|
// be very slow.
|
|
void setMaxSize(float maxSize);
|
|
|
|
// test a line for collision with the tree
|
|
bool testLine(bool (*octreeLineTestCallback)(OctreeNode* item, void* data), void* data, const FMOD_VECTOR& a, const FMOD_VECTOR& b);
|
|
|
|
#if defined(FMOD_GEOMETRY_DEBUGGING)
|
|
void renderTree(void (*renderBox)(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax));
|
|
void renderTreeInternal(OctreeNode* node, void (*renderBox)(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax));
|
|
#endif
|
|
|
|
#if defined(FMOD_23TREE)
|
|
// Use a 2-3-tree for to keep a sorted list of elements in each node.
|
|
// This could be used to speed up the pathalogical case where there
|
|
// are many AABBs in the one node. However, it may be slower in the
|
|
// average case.
|
|
// remove23Tree not implemented yet.
|
|
void insert23Tree(OctreeNode* parent, OctreeNode** pParent, OctreeNode* item);
|
|
void split23Tree(OctreeNode* node, OctreeNode* item);
|
|
void remove23Tree(OctreeNode* item);
|
|
void check23Tree(OctreeNode* parent, OctreeNode** pParent);
|
|
void check23TreeRecursive(OctreeNode* node);
|
|
int unsigned findLowest(OctreeNode* node);
|
|
#endif
|
|
|
|
|
|
static unsigned int ftoint(float f)
|
|
{
|
|
unsigned int i;
|
|
|
|
#if (defined(PLATFORM_WINDOWS) && !defined(__MINGW32__) || defined(PLATFORM_XBOX)) && defined(PLATFORM_32BIT)
|
|
|
|
__asm fld f;
|
|
__asm fistp i;
|
|
|
|
#else
|
|
|
|
i = (int)f;
|
|
|
|
#endif
|
|
|
|
return i;
|
|
}
|
|
|
|
// transformation functions
|
|
unsigned int xGetCenter(OctreeNode* node)
|
|
{
|
|
return ftoint((((node->aabb.xMin + node->aabb.xMax) * 0.5f - mCenter.x) * mScale * (float)(1 << 30)) + (float)(1 << 30));
|
|
}
|
|
unsigned int yGetCenter(OctreeNode* node)
|
|
{
|
|
return ftoint((((node->aabb.yMin + node->aabb.yMax) * 0.5f - mCenter.y) * mScale * (float)(1 << 30)) + (float)(1 << 30));
|
|
}
|
|
unsigned int zGetCenter(OctreeNode* node)
|
|
{
|
|
return ftoint((((node->aabb.zMin + node->aabb.zMax) * 0.5f - mCenter.z) * mScale * (float)(1 << 30)) + (float)(1 << 30));
|
|
}
|
|
|
|
private:
|
|
void insertInternal(OctreeNode* node, OctreeNode* item);
|
|
void addToFreeList(OctreeNode* item);
|
|
OctreeNode* getFreeNode();
|
|
void adjustAABBs(OctreeNode* node);
|
|
|
|
// each node of the tree potentially has a list of leaf nodes that are too close to be split.
|
|
// these functions make adding and removing for this list easier.
|
|
void removeListItem(OctreeNode* next);
|
|
void addListItem(OctreeNode* list, OctreeNode* node);
|
|
|
|
static void testLine(OctreeNode* node, FMOD_VECTOR a, FMOD_VECTOR b, RecursionData* recursionData);
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif // FMOD_SUPPORT_GEOMETRY
|
|
|
|
#endif // _FMOD_OCTREE_H
|