mirror of
https://github.com/overte-org/overte.git
synced 2025-07-15 09:16:45 +02:00
306 lines
No EOL
13 KiB
C++
306 lines
No EOL
13 KiB
C++
//
|
|
// OctreeElement.h
|
|
// hifi
|
|
//
|
|
// Created by Stephen Birarda on 3/13/13.
|
|
//
|
|
//
|
|
|
|
#ifndef __hifi__OctreeElement__
|
|
#define __hifi__OctreeElement__
|
|
|
|
//#define HAS_AUDIT_CHILDREN
|
|
//#define SIMPLE_CHILD_ARRAY
|
|
#define SIMPLE_EXTERNAL_CHILDREN
|
|
|
|
#include <QReadWriteLock>
|
|
|
|
#include <SharedUtil.h>
|
|
#include "AABox.h"
|
|
#include "ViewFrustum.h"
|
|
#include "OctreeConstants.h"
|
|
//#include "Octree.h"
|
|
|
|
class Octree;
|
|
class OctreeElement;
|
|
class OctreeElementDeleteHook;
|
|
class OctreePacketData;
|
|
class VoxelSystem;
|
|
class ReadBitstreamToTreeParams;
|
|
|
|
// Callers who want delete hook callbacks should implement this class
|
|
class OctreeElementDeleteHook {
|
|
public:
|
|
virtual void elementDeleted(OctreeElement* element) = 0;
|
|
};
|
|
|
|
// Callers who want update hook callbacks should implement this class
|
|
class OctreeElementUpdateHook {
|
|
public:
|
|
virtual void elementUpdated(OctreeElement* element) = 0;
|
|
};
|
|
|
|
|
|
class OctreeElement {
|
|
|
|
protected:
|
|
// can only be constructed by derived implementation
|
|
OctreeElement();
|
|
|
|
virtual OctreeElement* createNewElement(unsigned char * octalCode = NULL) = 0;
|
|
|
|
public:
|
|
virtual void init(unsigned char * octalCode); /// Your subclass must call init on construction.
|
|
virtual ~OctreeElement();
|
|
|
|
// methods you can and should override to implement your tree functionality
|
|
|
|
/// Adds a child to the current element. Override this if there is additional child initialization your class needs.
|
|
virtual OctreeElement* addChildAtIndex(int childIndex);
|
|
|
|
/// Override this to implement LOD averaging on changes to the tree.
|
|
virtual void calculateAverageFromChildren() { }
|
|
|
|
/// Override this to implement LOD collapsing and identical child pruning on changes to the tree.
|
|
virtual bool collapseChildren() { return false; }
|
|
|
|
/// Should this element be considered to have content in it. This will be used in collision and ray casting methods.
|
|
/// By default we assume that only leaves are actual content, but some octrees may have different semantics.
|
|
virtual bool hasContent() const { return isLeaf(); }
|
|
|
|
/// Override this to break up large octree elements when an edit operation is performed on a smaller octree element.
|
|
/// For example, if the octrees represent solid cubes and a delete of a smaller octree element is done then the
|
|
/// meaningful split would be to break the larger cube into smaller cubes of the same color/texture.
|
|
virtual void splitChildren() { }
|
|
|
|
/// Override to indicate that this element requires a split before editing lower elements in the octree
|
|
virtual bool requiresSplit() const { return false; }
|
|
|
|
/// Override to serialize the state of this element. This is used for persistance and for transmission across the network.
|
|
virtual bool appendElementData(OctreePacketData* packetData) const { return true; }
|
|
|
|
/// Override to deserialize the state of this element. This is used for loading from a persisted file or from reading
|
|
/// from the network.
|
|
virtual int readElementDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args)
|
|
{ return 0; }
|
|
|
|
/// Override to indicate that the item is currently rendered in the rendering engine. By default we assume that if
|
|
/// the element should be rendered, then your rendering engine is rendering. But some rendering engines my have cases
|
|
/// where an element is not actually rendering all should render elements. If the isRendered() state doesn't match the
|
|
/// shouldRender() state, the tree will remark elements as changed even in cases there the elements have not changed.
|
|
virtual bool isRendered() const { return getShouldRender(); }
|
|
|
|
virtual bool deleteApproved() const { return true; }
|
|
|
|
|
|
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
|
glm::vec3& penetration, void** penetratedObject) const;
|
|
|
|
// Base class methods you don't need to implement
|
|
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }
|
|
OctreeElement* getChildAtIndex(int childIndex) const;
|
|
void deleteChildAtIndex(int childIndex);
|
|
OctreeElement* removeChildAtIndex(int childIndex);
|
|
|
|
/// handles deletion of all descendants, returns false if delete not approved
|
|
bool safeDeepDeleteChildAtIndex(int childIndex, int recursionCount = 0);
|
|
|
|
|
|
const AABox& getAABox() const { return _box; }
|
|
const glm::vec3& getCorner() const { return _box.getCorner(); }
|
|
float getScale() const { return _box.getScale(); }
|
|
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
|
|
|
|
float getEnclosingRadius() const;
|
|
|
|
|
|
bool isInView(const ViewFrustum& viewFrustum) const;
|
|
ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const;
|
|
float distanceToCamera(const ViewFrustum& viewFrustum) const;
|
|
float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const;
|
|
|
|
bool calculateShouldRender(const ViewFrustum* viewFrustum,
|
|
float voxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE, int boundaryLevelAdjust = 0) const;
|
|
|
|
// points are assumed to be in Voxel Coordinates (not TREE_SCALE'd)
|
|
float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this.
|
|
float distanceToPoint(const glm::vec3& point) const;
|
|
|
|
bool isLeaf() const { return getChildCount() == 0; }
|
|
int getChildCount() const { return numberOfOnes(_childBitmask); }
|
|
void printDebugDetails(const char* label) const;
|
|
bool isDirty() const { return _isDirty; }
|
|
void clearDirtyBit() { _isDirty = false; }
|
|
void setDirtyBit() { _isDirty = true; }
|
|
bool hasChangedSince(quint64 time) const { return (_lastChanged > time); }
|
|
void markWithChangedTime();
|
|
quint64 getLastChanged() const { return _lastChanged; }
|
|
void handleSubtreeChanged(Octree* myTree);
|
|
|
|
// Used by VoxelSystem for rendering in/out of view and LOD
|
|
void setShouldRender(bool shouldRender);
|
|
bool getShouldRender() const { return _shouldRender; }
|
|
|
|
|
|
void setSourceUUID(const QUuid& sourceID);
|
|
QUuid getSourceUUID() const;
|
|
uint16_t getSourceUUIDKey() const { return _sourceUUIDKey; }
|
|
bool matchesSourceUUID(const QUuid& sourceUUID) const;
|
|
static uint16_t getSourceNodeUUIDKey(const QUuid& sourceUUID);
|
|
|
|
static void addDeleteHook(OctreeElementDeleteHook* hook);
|
|
static void removeDeleteHook(OctreeElementDeleteHook* hook);
|
|
|
|
static void addUpdateHook(OctreeElementUpdateHook* hook);
|
|
static void removeUpdateHook(OctreeElementUpdateHook* hook);
|
|
|
|
static unsigned long getNodeCount() { return _voxelNodeCount; }
|
|
static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; }
|
|
static unsigned long getLeafNodeCount() { return _voxelNodeLeafCount; }
|
|
|
|
static quint64 getVoxelMemoryUsage() { return _voxelMemoryUsage; }
|
|
static quint64 getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
|
|
static quint64 getExternalChildrenMemoryUsage() { return _externalChildrenMemoryUsage; }
|
|
static quint64 getTotalMemoryUsage() { return _voxelMemoryUsage + _octcodeMemoryUsage + _externalChildrenMemoryUsage; }
|
|
|
|
static quint64 getGetChildAtIndexTime() { return _getChildAtIndexTime; }
|
|
static quint64 getGetChildAtIndexCalls() { return _getChildAtIndexCalls; }
|
|
static quint64 getSetChildAtIndexTime() { return _setChildAtIndexTime; }
|
|
static quint64 getSetChildAtIndexCalls() { return _setChildAtIndexCalls; }
|
|
|
|
#ifdef BLENDED_UNION_CHILDREN
|
|
static quint64 getSingleChildrenCount() { return _singleChildrenCount; }
|
|
static quint64 getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; }
|
|
static quint64 getTwoChildrenExternalCount() { return _twoChildrenExternalCount; }
|
|
static quint64 getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; }
|
|
static quint64 getThreeChildrenExternalCount() { return _threeChildrenExternalCount; }
|
|
static quint64 getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; }
|
|
static quint64 getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; }
|
|
#endif
|
|
|
|
static quint64 getExternalChildrenCount() { return _externalChildrenCount; }
|
|
static quint64 getChildrenCount(int childCount) { return _childrenCount[childCount]; }
|
|
|
|
#ifdef BLENDED_UNION_CHILDREN
|
|
#ifdef HAS_AUDIT_CHILDREN
|
|
void auditChildren(const char* label) const;
|
|
#endif // def HAS_AUDIT_CHILDREN
|
|
#endif // def BLENDED_UNION_CHILDREN
|
|
|
|
enum ChildIndex {
|
|
CHILD_BOTTOM_RIGHT_NEAR = 0,
|
|
CHILD_BOTTOM_RIGHT_FAR = 1,
|
|
CHILD_TOP_RIGHT_NEAR = 2,
|
|
CHILD_TOP_RIGHT_FAR = 3,
|
|
CHILD_BOTTOM_LEFT_NEAR = 4,
|
|
CHILD_BOTTOM_LEFT_FAR = 5,
|
|
CHILD_TOP_LEFT_NEAR = 6,
|
|
CHILD_TOP_LEFT_FAR = 7,
|
|
CHILD_UNKNOWN = -1
|
|
};
|
|
|
|
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
|
|
|
protected:
|
|
|
|
void deleteAllChildren();
|
|
void setChildAtIndex(int childIndex, OctreeElement* child);
|
|
|
|
#ifdef BLENDED_UNION_CHILDREN
|
|
void storeTwoChildren(OctreeElement* childOne, OctreeElement* childTwo);
|
|
void retrieveTwoChildren(OctreeElement*& childOne, OctreeElement*& childTwo);
|
|
void storeThreeChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree);
|
|
void retrieveThreeChildren(OctreeElement*& childOne, OctreeElement*& childTwo, OctreeElement*& childThree);
|
|
void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const;
|
|
void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree);
|
|
void checkStoreFourChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree, OctreeElement* childFour);
|
|
#endif
|
|
void calculateAABox();
|
|
void notifyDeleteHooks();
|
|
void notifyUpdateHooks();
|
|
|
|
AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
|
|
|
|
/// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes
|
|
union octalCode_t {
|
|
unsigned char buffer[8];
|
|
unsigned char* pointer;
|
|
} _octalCode;
|
|
|
|
quint64 _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes
|
|
|
|
/// Client and server, pointers to child nodes, various encodings
|
|
#ifdef SIMPLE_CHILD_ARRAY
|
|
OctreeElement* _simpleChildArray[8]; /// Only used when SIMPLE_CHILD_ARRAY is enabled
|
|
#endif
|
|
|
|
#ifdef SIMPLE_EXTERNAL_CHILDREN
|
|
union children_t {
|
|
OctreeElement* single;
|
|
OctreeElement** external;
|
|
} _children;
|
|
#endif
|
|
|
|
#ifdef BLENDED_UNION_CHILDREN
|
|
union children_t {
|
|
OctreeElement* single;
|
|
int32_t offsetsTwoChildren[2];
|
|
quint64 offsetsThreeChildrenEncoded;
|
|
OctreeElement** external;
|
|
} _children;
|
|
#ifdef HAS_AUDIT_CHILDREN
|
|
OctreeElement* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding
|
|
#endif // def HAS_AUDIT_CHILDREN
|
|
|
|
#endif //def BLENDED_UNION_CHILDREN
|
|
|
|
uint16_t _sourceUUIDKey; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
|
|
|
// Support for _sourceUUID, we use these static member variables to track the UUIDs that are
|
|
// in use by various voxel server nodes. We map the UUID strings into an 16 bit key, this limits us to at
|
|
// most 65k voxel servers in use at a time within the client. Which is far more than we need.
|
|
static uint16_t _nextUUIDKey; // start at 1, 0 is reserved for NULL
|
|
static std::map<QString, uint16_t> _mapSourceUUIDsToKeys;
|
|
static std::map<uint16_t, QString> _mapKeysToSourceUUIDs;
|
|
|
|
unsigned char _childBitmask; // 1 byte
|
|
|
|
bool _falseColored : 1, /// Client only, is this voxel false colored, 1 bit
|
|
_isDirty : 1, /// Client only, has this voxel changed since being rendered, 1 bit
|
|
_shouldRender : 1, /// Client only, should this voxel render at this time, 1 bit
|
|
_octcodePointer : 1, /// Client and Server only, is this voxel's octal code a pointer or buffer, 1 bit
|
|
_unknownBufferIndex : 1,
|
|
_childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit
|
|
|
|
static QReadWriteLock _deleteHooksLock;
|
|
static std::vector<OctreeElementDeleteHook*> _deleteHooks;
|
|
|
|
//static QReadWriteLock _updateHooksLock;
|
|
static std::vector<OctreeElementUpdateHook*> _updateHooks;
|
|
|
|
static quint64 _voxelNodeCount;
|
|
static quint64 _voxelNodeLeafCount;
|
|
|
|
static quint64 _voxelMemoryUsage;
|
|
static quint64 _octcodeMemoryUsage;
|
|
static quint64 _externalChildrenMemoryUsage;
|
|
|
|
static quint64 _getChildAtIndexTime;
|
|
static quint64 _getChildAtIndexCalls;
|
|
static quint64 _setChildAtIndexTime;
|
|
static quint64 _setChildAtIndexCalls;
|
|
|
|
#ifdef BLENDED_UNION_CHILDREN
|
|
static quint64 _singleChildrenCount;
|
|
static quint64 _twoChildrenOffsetCount;
|
|
static quint64 _twoChildrenExternalCount;
|
|
static quint64 _threeChildrenOffsetCount;
|
|
static quint64 _threeChildrenExternalCount;
|
|
static quint64 _couldStoreFourChildrenInternally;
|
|
static quint64 _couldNotStoreFourChildrenInternally;
|
|
#endif
|
|
static quint64 _externalChildrenCount;
|
|
static quint64 _childrenCount[NUMBER_OF_CHILDREN + 1];
|
|
};
|
|
|
|
#endif /* defined(__hifi__OctreeElement__) */ |