mirror of
https://github.com/overte-org/overte.git
synced 2025-04-17 01:56:39 +02:00
Merge pull request #2803 from ZappoMan/modelserver
Model Server Bug Fixes/Bandwidth improvements
This commit is contained in:
commit
72e6ff3649
12 changed files with 406 additions and 384 deletions
|
@ -2032,7 +2032,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
|
|||
// if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then
|
||||
// we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse
|
||||
// the children and simply mark them as hidden
|
||||
args->tree->recurseNodeWithOperation(voxel, hideAllSubTreeOperation, args );
|
||||
args->tree->recurseElementWithOperation(voxel, hideAllSubTreeOperation, args );
|
||||
return false;
|
||||
|
||||
} break;
|
||||
|
@ -2049,7 +2049,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData
|
|||
// if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then
|
||||
// we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse
|
||||
// the children and simply mark them as visible (as appropriate based on LOD)
|
||||
args->tree->recurseNodeWithOperation(voxel, showAllSubTreeOperation, args);
|
||||
args->tree->recurseElementWithOperation(voxel, showAllSubTreeOperation, args);
|
||||
return false;
|
||||
} break;
|
||||
case ViewFrustum::INTERSECT: {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "ModelTree.h"
|
||||
|
||||
ModelTree::ModelTree(bool shouldReaverage) : Octree(shouldReaverage) {
|
||||
_rootNode = createNewElement();
|
||||
_rootElement = createNewElement();
|
||||
}
|
||||
|
||||
ModelTreeElement* ModelTree::createNewElement(unsigned char * octalCode) {
|
||||
|
@ -74,31 +74,48 @@ bool ModelTree::findAndDeleteOperation(OctreeElement* element, void* extraData)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
class FindAndUpdateModelArgs {
|
||||
class FindAndUpdateModelOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
const ModelItem& searchModel;
|
||||
bool found;
|
||||
FindAndUpdateModelOperator(const ModelItem& searchModel);
|
||||
virtual bool PreRecursion(OctreeElement* element);
|
||||
virtual bool PostRecursion(OctreeElement* element);
|
||||
bool wasFound() const { return _found; }
|
||||
private:
|
||||
const ModelItem& _searchModel;
|
||||
bool _found;
|
||||
};
|
||||
|
||||
bool ModelTree::findAndUpdateOperation(OctreeElement* element, void* extraData) {
|
||||
FindAndUpdateModelArgs* args = static_cast<FindAndUpdateModelArgs*>(extraData);
|
||||
FindAndUpdateModelOperator::FindAndUpdateModelOperator(const ModelItem& searchModel) :
|
||||
_searchModel(searchModel),
|
||||
_found(false) {
|
||||
};
|
||||
|
||||
bool FindAndUpdateModelOperator::PreRecursion(OctreeElement* element) {
|
||||
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
|
||||
// Note: updateModel() will only operate on correctly found models
|
||||
if (modelTreeElement->updateModel(args->searchModel)) {
|
||||
args->found = true;
|
||||
if (modelTreeElement->updateModel(_searchModel)) {
|
||||
_found = true;
|
||||
return false; // stop searching
|
||||
}
|
||||
return true;
|
||||
|
||||
return !_found; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
bool FindAndUpdateModelOperator::PostRecursion(OctreeElement* element) {
|
||||
if (_found) {
|
||||
element->markWithChangedTime();
|
||||
}
|
||||
return !_found; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& senderNode) {
|
||||
// First, look for the existing model in the tree..
|
||||
FindAndUpdateModelArgs args = { model, false };
|
||||
recurseTreeWithOperation(findAndUpdateOperation, &args);
|
||||
FindAndUpdateModelOperator theOperator(model);
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
|
||||
|
||||
// if we didn't find it in the tree, then store it...
|
||||
if (!args.found) {
|
||||
if (!theOperator.wasFound()) {
|
||||
glm::vec3 position = model.getPosition();
|
||||
float size = std::max(MINIMUM_MODEL_ELEMENT_SIZE, model.getRadius());
|
||||
|
||||
|
@ -109,36 +126,49 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send
|
|||
_isDirty = true;
|
||||
}
|
||||
|
||||
class FindAndUpdateModelWithIDandPropertiesArgs {
|
||||
|
||||
class FindAndUpdateModelWithIDandPropertiesOperator : public RecurseOctreeOperator {
|
||||
public:
|
||||
const ModelItemID& modelID;
|
||||
const ModelItemProperties& properties;
|
||||
bool found;
|
||||
FindAndUpdateModelWithIDandPropertiesOperator(const ModelItemID& modelID, const ModelItemProperties& properties);
|
||||
virtual bool PreRecursion(OctreeElement* element);
|
||||
virtual bool PostRecursion(OctreeElement* element);
|
||||
bool wasFound() const { return _found; }
|
||||
private:
|
||||
const ModelItemID& _modelID;
|
||||
const ModelItemProperties& _properties;
|
||||
bool _found;
|
||||
};
|
||||
|
||||
bool ModelTree::findAndUpdateWithIDandPropertiesOperation(OctreeElement* element, void* extraData) {
|
||||
FindAndUpdateModelWithIDandPropertiesArgs* args = static_cast<FindAndUpdateModelWithIDandPropertiesArgs*>(extraData);
|
||||
FindAndUpdateModelWithIDandPropertiesOperator::FindAndUpdateModelWithIDandPropertiesOperator(const ModelItemID& modelID,
|
||||
const ModelItemProperties& properties) :
|
||||
_modelID(modelID),
|
||||
_properties(properties),
|
||||
_found(false) {
|
||||
};
|
||||
|
||||
bool FindAndUpdateModelWithIDandPropertiesOperator::PreRecursion(OctreeElement* element) {
|
||||
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
|
||||
|
||||
// Note: updateModel() will only operate on correctly found models
|
||||
if (modelTreeElement->updateModel(args->modelID, args->properties)) {
|
||||
args->found = true;
|
||||
if (modelTreeElement->updateModel(_modelID, _properties)) {
|
||||
_found = true;
|
||||
return false; // stop searching
|
||||
}
|
||||
return !_found; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
// if we've found our model stop searching
|
||||
if (args->found) {
|
||||
return false;
|
||||
bool FindAndUpdateModelWithIDandPropertiesOperator::PostRecursion(OctreeElement* element) {
|
||||
if (_found) {
|
||||
element->markWithChangedTime();
|
||||
}
|
||||
|
||||
return true;
|
||||
return !_found; // if we haven't yet found it, keep looking
|
||||
}
|
||||
|
||||
void ModelTree::updateModel(const ModelItemID& modelID, const ModelItemProperties& properties) {
|
||||
// First, look for the existing model in the tree..
|
||||
FindAndUpdateModelWithIDandPropertiesArgs args = { modelID, properties, false };
|
||||
recurseTreeWithOperation(findAndUpdateWithIDandPropertiesOperation, &args);
|
||||
// if we found it in the tree, then mark the tree as dirty
|
||||
if (args.found) {
|
||||
// Look for the existing model in the tree..
|
||||
FindAndUpdateModelWithIDandPropertiesOperator theOperator(modelID, properties);
|
||||
recurseTreeWithOperator(&theOperator);
|
||||
if (theOperator.wasFound()) {
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
@ -464,29 +494,12 @@ void ModelTree::update() {
|
|||
lockForWrite();
|
||||
_isDirty = true;
|
||||
|
||||
ModelTreeUpdateArgs args = { };
|
||||
recurseTreeWithOperation(updateOperation, &args);
|
||||
// TODO: we don't need to update models yet, but when we do, for example
|
||||
// when we add animation support, we will revisit this code.
|
||||
//ModelTreeUpdateArgs args = { };
|
||||
//recurseTreeWithOperation(updateOperation, &args);
|
||||
|
||||
// now add back any of the models that moved elements....
|
||||
int movingModels = args._movingModels.size();
|
||||
for (int i = 0; i < movingModels; i++) {
|
||||
bool shouldDie = args._movingModels[i].getShouldDie();
|
||||
|
||||
// if the model is still inside our total bounds, then re-add it
|
||||
AABox treeBounds = getRoot()->getAABox();
|
||||
|
||||
if (!shouldDie && treeBounds.contains(args._movingModels[i].getPosition())) {
|
||||
storeModel(args._movingModels[i]);
|
||||
} else {
|
||||
uint32_t modelID = args._movingModels[i].getID();
|
||||
quint64 deletedAt = usecTimestampNow();
|
||||
_recentlyDeletedModelsLock.lockForWrite();
|
||||
_recentlyDeletedModelItemIDs.insert(deletedAt, modelID);
|
||||
_recentlyDeletedModelsLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// prune the tree...
|
||||
// Now is a reasonable time to prune the tree...
|
||||
recurseTreeWithOperation(pruneOperation, NULL);
|
||||
unlock();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
virtual ModelTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
|
||||
/// Type safe version of getRoot()
|
||||
ModelTreeElement* getRoot() { return (ModelTreeElement*)_rootNode; }
|
||||
ModelTreeElement* getRoot() { return static_cast<ModelTreeElement*>(_rootElement); }
|
||||
|
||||
|
||||
// These methods will allow the OctreeServer to send your tree inbound edit packets of your
|
||||
|
|
|
@ -137,6 +137,7 @@ bool ModelTreeElement::updateModel(const ModelItem& model) {
|
|||
difference, debug::valueOf(model.isNewlyCreated()) );
|
||||
}
|
||||
thisModel.copyChangedProperties(model);
|
||||
markWithChangedTime();
|
||||
} else {
|
||||
if (wantDebug) {
|
||||
qDebug(">>> IGNORING SERVER!!! Would've caused jutter! <<< "
|
||||
|
@ -167,7 +168,7 @@ bool ModelTreeElement::updateModel(const ModelItemID& modelID, const ModelItemPr
|
|||
}
|
||||
if (found) {
|
||||
thisModel.setProperties(properties);
|
||||
|
||||
markWithChangedTime(); // mark our element as changed..
|
||||
const bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,8 +36,15 @@ class Shape;
|
|||
#include <QObject>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
/// derive from this class to use the Octree::recurseTreeWithOperator() method
|
||||
class RecurseOctreeOperator {
|
||||
public:
|
||||
virtual bool PreRecursion(OctreeElement* element) = 0;
|
||||
virtual bool PostRecursion(OctreeElement* element) = 0;
|
||||
};
|
||||
|
||||
// Callback function, for recuseTreeWithOperation
|
||||
typedef bool (*RecurseOctreeOperation)(OctreeElement* node, void* extraData);
|
||||
typedef bool (*RecurseOctreeOperation)(OctreeElement* element, void* extraData);
|
||||
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
|
||||
|
||||
const bool NO_EXISTS_BITS = false;
|
||||
|
@ -159,7 +166,7 @@ class ReadBitstreamToTreeParams {
|
|||
public:
|
||||
bool includeColor;
|
||||
bool includeExistsBits;
|
||||
OctreeElement* destinationNode;
|
||||
OctreeElement* destinationElement;
|
||||
QUuid sourceUUID;
|
||||
SharedNodePointer sourceNode;
|
||||
bool wantImportProgress;
|
||||
|
@ -167,13 +174,13 @@ public:
|
|||
ReadBitstreamToTreeParams(
|
||||
bool includeColor = WANT_COLOR,
|
||||
bool includeExistsBits = WANT_EXISTS_BITS,
|
||||
OctreeElement* destinationNode = NULL,
|
||||
OctreeElement* destinationElement = NULL,
|
||||
QUuid sourceUUID = QUuid(),
|
||||
SharedNodePointer sourceNode = SharedNodePointer(),
|
||||
bool wantImportProgress = false) :
|
||||
includeColor(includeColor),
|
||||
includeExistsBits(includeExistsBits),
|
||||
destinationNode(destinationNode),
|
||||
destinationElement(destinationElement),
|
||||
sourceUUID(sourceUUID),
|
||||
sourceNode(sourceNode),
|
||||
wantImportProgress(wantImportProgress)
|
||||
|
@ -200,14 +207,14 @@ public:
|
|||
|
||||
virtual void update() { }; // nothing to do by default
|
||||
|
||||
OctreeElement* getRoot() { return _rootNode; }
|
||||
OctreeElement* getRoot() { return _rootElement; }
|
||||
|
||||
void eraseAllOctreeElements();
|
||||
|
||||
void processRemoveOctreeElementsBitstream(const unsigned char* bitstream, int bufferSizeBytes);
|
||||
void readBitstreamToTree(const unsigned char* bitstream, unsigned long int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
void deleteOctalCodeFromTree(const unsigned char* codeBuffer, bool collapseEmptyTrees = DONT_COLLAPSE);
|
||||
void reaverageOctreeElements(OctreeElement* startNode = NULL);
|
||||
void reaverageOctreeElements(OctreeElement* startElement = NULL);
|
||||
|
||||
void deleteOctreeElementAt(float x, float y, float z, float s);
|
||||
|
||||
|
@ -222,13 +229,14 @@ public:
|
|||
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
|
||||
|
||||
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
||||
|
||||
void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL);
|
||||
|
||||
void recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation,
|
||||
const glm::vec3& point, void* extraData = NULL);
|
||||
|
||||
int encodeTreeBitstream(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag,
|
||||
void recurseTreeWithOperator(RecurseOctreeOperator* operatorObject);
|
||||
|
||||
int encodeTreeBitstream(OctreeElement* element, OctreePacketData* packetData, OctreeElementBag& bag,
|
||||
EncodeBitstreamParams& params) ;
|
||||
|
||||
bool isDirty() const { return _isDirty; }
|
||||
|
@ -268,28 +276,30 @@ public:
|
|||
void loadOctreeFile(const char* fileName, bool wantColorRandomizer);
|
||||
|
||||
// these will read/write files that match the wireformat, excluding the 'V' leading
|
||||
void writeToSVOFile(const char* filename, OctreeElement* node = NULL);
|
||||
void writeToSVOFile(const char* filename, OctreeElement* element = NULL);
|
||||
bool readFromSVOFile(const char* filename);
|
||||
|
||||
|
||||
unsigned long getOctreeElementsCount();
|
||||
|
||||
void copySubTreeIntoNewTree(OctreeElement* startNode, Octree* destinationTree, bool rebaseToRoot);
|
||||
void copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationNode);
|
||||
void copySubTreeIntoNewTree(OctreeElement* startElement, Octree* destinationTree, bool rebaseToRoot);
|
||||
void copyFromTreeIntoSubTree(Octree* sourceTree, OctreeElement* destinationElement);
|
||||
|
||||
bool getShouldReaverage() const { return _shouldReaverage; }
|
||||
|
||||
void recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation,
|
||||
void recurseElementWithOperation(OctreeElement* element, RecurseOctreeOperation operation,
|
||||
void* extraData, int recursionCount = 0);
|
||||
|
||||
/// Traverse child nodes of node applying operation in post-fix order
|
||||
///
|
||||
void recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation,
|
||||
void recurseElementWithPostOperation(OctreeElement* element, RecurseOctreeOperation operation,
|
||||
void* extraData, int recursionCount = 0);
|
||||
|
||||
void recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation,
|
||||
void recurseElementWithOperationDistanceSorted(OctreeElement* element, RecurseOctreeOperation operation,
|
||||
const glm::vec3& point, void* extraData, int recursionCount = 0);
|
||||
|
||||
bool recurseElementWithOperator(OctreeElement* element, RecurseOctreeOperator* operatorObject, int recursionCount = 0);
|
||||
|
||||
bool getIsViewing() const { return _isViewing; }
|
||||
void setIsViewing(bool isViewing) { _isViewing = isViewing; }
|
||||
|
||||
|
@ -302,21 +312,21 @@ public slots:
|
|||
|
||||
|
||||
protected:
|
||||
void deleteOctalCodeFromTreeRecursion(OctreeElement* node, void* extraData);
|
||||
void deleteOctalCodeFromTreeRecursion(OctreeElement* element, void* extraData);
|
||||
|
||||
int encodeTreeBitstreamRecursion(OctreeElement* node,
|
||||
int encodeTreeBitstreamRecursion(OctreeElement* element,
|
||||
OctreePacketData* packetData, OctreeElementBag& bag,
|
||||
EncodeBitstreamParams& params, int& currentEncodeLevel,
|
||||
const ViewFrustum::location& parentLocationThisView) const;
|
||||
|
||||
static bool countOctreeElementsOperation(OctreeElement* node, void* extraData);
|
||||
static bool countOctreeElementsOperation(OctreeElement* element, void* extraData);
|
||||
|
||||
OctreeElement* nodeForOctalCode(OctreeElement* ancestorNode, const unsigned char* needleCode, OctreeElement** parentOfFoundNode) const;
|
||||
OctreeElement* createMissingNode(OctreeElement* lastParentNode, const unsigned char* codeToReach);
|
||||
int readNodeData(OctreeElement *destinationNode, const unsigned char* nodeData,
|
||||
OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const;
|
||||
OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach);
|
||||
int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData,
|
||||
int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||
|
||||
OctreeElement* _rootNode;
|
||||
OctreeElement* _rootElement;
|
||||
|
||||
bool _isDirty;
|
||||
bool _shouldReaverage;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
typedef unsigned char OCTREE_PACKET_FLAGS;
|
||||
typedef uint16_t OCTREE_PACKET_SEQUENCE;
|
||||
const uint16_t MAX_OCTREE_PACKET_SEQUENCE = 65535;
|
||||
typedef quint64 OCTREE_PACKET_SENT_TIME;
|
||||
typedef uint16_t OCTREE_PACKET_INTERNAL_SECTION_SIZE;
|
||||
const int MAX_OCTREE_PACKET_SIZE = MAX_PACKET_SIZE;
|
||||
|
|
|
@ -875,10 +875,13 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
|||
return; // ignore any packets that are unreasonable
|
||||
}
|
||||
|
||||
// determine our expected sequence number... handle rollover appropriately
|
||||
OCTREE_PACKET_SEQUENCE expected = _incomingPacket > 0 ? _incomingLastSequence + 1 : sequence;
|
||||
|
||||
// Guard against possible corrupted packets... with bad sequence numbers
|
||||
const int MAX_RESONABLE_SEQUENCE_OFFSET = 2000;
|
||||
const int MIN_RESONABLE_SEQUENCE_OFFSET = -2000;
|
||||
int sequenceOffset = (sequence - _incomingLastSequence);
|
||||
int sequenceOffset = (sequence - expected);
|
||||
if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) {
|
||||
qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
|
||||
return; // ignore any packets that are unreasonable
|
||||
|
@ -901,7 +904,6 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
|||
qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence;
|
||||
}
|
||||
} else {
|
||||
OCTREE_PACKET_SEQUENCE expected = _incomingLastSequence+1;
|
||||
if (sequence != expected) {
|
||||
if (wantExtraDebugging) {
|
||||
qDebug() << "out of order... got:" << sequence << "expected:" << expected;
|
||||
|
@ -958,9 +960,9 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet,
|
|||
}
|
||||
}
|
||||
|
||||
// only bump the last sequence if it was greater than our previous last sequence, this will keep us from
|
||||
// only bump the last sequence if it was greater than our expected sequence, this will keep us from
|
||||
// accidentally going backwards when an out of order (recovered) packet comes in
|
||||
if (sequence > _incomingLastSequence) {
|
||||
if (sequence >= expected) {
|
||||
_incomingLastSequence = sequence;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "ParticleTree.h"
|
||||
|
||||
ParticleTree::ParticleTree(bool shouldReaverage) : Octree(shouldReaverage) {
|
||||
_rootNode = createNewElement();
|
||||
_rootElement = createNewElement();
|
||||
}
|
||||
|
||||
ParticleTreeElement* ParticleTree::createNewElement(unsigned char * octalCode) {
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
virtual ParticleTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
|
||||
/// Type safe version of getRoot()
|
||||
ParticleTreeElement* getRoot() { return (ParticleTreeElement*)_rootNode; }
|
||||
ParticleTreeElement* getRoot() { return static_cast<ParticleTreeElement*>(_rootElement); }
|
||||
|
||||
|
||||
// These methods will allow the OctreeServer to send your tree inbound edit packets of your
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
|
||||
VoxelTree::VoxelTree(bool shouldReaverage) : Octree(shouldReaverage)
|
||||
{
|
||||
_rootNode = createNewElement();
|
||||
_rootElement = createNewElement();
|
||||
}
|
||||
|
||||
VoxelTreeElement* VoxelTree::createNewElement(unsigned char * octalCode) {
|
||||
VoxelSystem* voxelSystem = NULL;
|
||||
if (_rootNode) {
|
||||
voxelSystem = ((VoxelTreeElement*)_rootNode)->getVoxelSystem();
|
||||
if (_rootElement) {
|
||||
voxelSystem = (static_cast<VoxelTreeElement*>(_rootElement))->getVoxelSystem();
|
||||
}
|
||||
VoxelTreeElement* newElement = new VoxelTreeElement(octalCode);
|
||||
newElement->setVoxelSystem(voxelSystem);
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
VoxelTree(bool shouldReaverage = false);
|
||||
|
||||
virtual VoxelTreeElement* createNewElement(unsigned char * octalCode = NULL);
|
||||
VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; }
|
||||
VoxelTreeElement* getRoot() { return static_cast<VoxelTreeElement*>(_rootElement); }
|
||||
|
||||
void deleteVoxelAt(float x, float y, float z, float s);
|
||||
|
||||
|
|
Loading…
Reference in a new issue