Merge pull request #1002 from ZappoMan/voxel_render_pipeline_improvement

Voxel render pipeline improvement
This commit is contained in:
Philip Rosedale 2013-10-01 13:13:11 -07:00
commit 64151975f2
12 changed files with 253 additions and 65 deletions

View file

@ -1541,6 +1541,9 @@ void Application::init() {
_sharedVoxelSystemViewFrustum.setOrientation(glm::quat());
_sharedVoxelSystemViewFrustum.calculate();
_sharedVoxelSystem.setViewFrustum(&_sharedVoxelSystemViewFrustum);
VoxelNode::removeUpdateHook(&_sharedVoxelSystem);
_sharedVoxelSystem.init();
VoxelTree* tmpTree = _sharedVoxelSystem.getTree();
_sharedVoxelSystem.changeTree(&_clipboard);
@ -1588,6 +1591,7 @@ void Application::init() {
// Set up VoxelSystem after loading preferences so we can get the desired max voxel count
_voxels.setMaxVoxels(Menu::getInstance()->getMaxVoxels());
_voxels.setUseVoxelShader(Menu::getInstance()->isOptionChecked(MenuOption::UseVoxelShader));
_voxels.setUseFastVoxelPipeline(Menu::getInstance()->isOptionChecked(MenuOption::FastVoxelPipeline));
_voxels.init();

View file

@ -253,6 +253,9 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseVoxelShader, 0,
false, this, SLOT(switchVoxelShader()));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0,
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");

View file

@ -152,6 +152,7 @@ namespace MenuOption {
const QString FalseColorOccludedV2 = "FALSE Color Occluded V2 Voxels";
const QString FalseColorOutOfView = "FALSE Color Voxel Out of View";
const QString FalseColorRandomly = "FALSE Color Voxels Randomly";
const QString FastVoxelPipeline = "Fast Voxel Pipeline";
const QString FirstPerson = "First Person";
const QString FrameTimer = "Show Timer";
const QString FrustumRenderMode = "Render Mode";

View file

@ -70,10 +70,12 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_writeRenderFullVBO = true;
_readRenderFullVBO = true;
_tree = new VoxelTree();
_tree->rootNode->setVoxelSystem(this);
pthread_mutex_init(&_bufferWriteLock, NULL);
pthread_mutex_init(&_treeLock, NULL);
VoxelNode::addDeleteHook(this);
VoxelNode::addUpdateHook(this);
_abandonedVBOSlots = 0;
_falseColorizeBySource = false;
_dataSourceID = UNKNOWN_NODE_ID;
@ -96,14 +98,70 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_writeVoxelDirtyArray = NULL;
_readVoxelDirtyArray = NULL;
_inSetupNewVoxelsForDrawing = false;
_useFastVoxelPipeline = false;
}
void VoxelSystem::nodeDeleted(VoxelNode* node) {
void VoxelSystem::voxelDeleted(VoxelNode* node) {
if (node->isKnownBufferIndex() && (node->getVoxelSystem() == this)) {
freeBufferIndex(node->getBufferIndex());
}
}
void VoxelSystem::setUseFastVoxelPipeline(bool useFastVoxelPipeline) {
_useFastVoxelPipeline = useFastVoxelPipeline;
printf("setUseFastVoxelPipeline() _useFastVoxelPipeline=%s\n", debug::valueOf(_useFastVoxelPipeline));
setupNewVoxelsForDrawing();
}
void VoxelSystem::voxelUpdated(VoxelNode* node) {
//printf("VoxelSystem::voxelUpdated() _useFastVoxelPipeline=%s\n", debug::valueOf(_useFastVoxelPipeline));
// If we're in SetupNewVoxelsForDrawing() or _writeRenderFullVBO then bail..
if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) {
return;
}
if (node->getVoxelSystem() == this) {
//printf("VoxelSystem::voxelUpdated()... node->getVoxelSystem() == this\n");
bool shouldRender = false; // assume we don't need to render it
// if it's colored, we might need to render it!
shouldRender = node->calculateShouldRender(_viewFrustum);
node->setShouldRender(shouldRender);
if (!node->isLeaf()) {
// As we check our children, see if any of them went from shouldRender to NOT shouldRender
// then we probably dropped LOD and if we don't have color, we want to average our children
// for a new color.
int childrenGotHiddenCount = 0;
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
VoxelNode* childNode = node->getChildAtIndex(i);
if (childNode) {
bool wasShouldRender = childNode->getShouldRender();
bool isShouldRender = childNode->calculateShouldRender(_viewFrustum);
if (wasShouldRender && !isShouldRender) {
childrenGotHiddenCount++;
}
}
}
if (childrenGotHiddenCount > 0) {
node->setColorFromAverageOfChildren();
}
}
updateNodeInArraysAsPartialVBO(node);
_voxelsUpdated++;
node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things.
setupNewVoxelsForDrawingSingleNode();
}
}
// returns an available index, starts by reusing a previously freed index, but if there isn't one available
// it will use the end of the VBO array and grow our accounting of that array.
// and makes the index available for some other node to use
@ -147,6 +205,7 @@ VoxelSystem::~VoxelSystem() {
pthread_mutex_destroy(&_treeLock);
VoxelNode::removeDeleteHook(this);
VoxelNode::removeUpdateHook(this);
}
void VoxelSystem::setMaxVoxels(int maxVoxels) {
@ -462,7 +521,10 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
break;
}
setupNewVoxelsForDrawing();
if (!_useFastVoxelPipeline || _writeRenderFullVBO) {
setupNewVoxelsForDrawing();
}
pthread_mutex_unlock(&_treeLock);
@ -485,25 +547,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
return; // bail early, it hasn't been long enough since the last time we ran
}
uint64_t sinceLastViewCulling = (start - _lastViewCulling) / 1000;
// If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view
if ((sinceLastViewCulling >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS))
&& !isViewChanging()) {
_lastViewCulling = start;
_inSetupNewVoxelsForDrawing = true;
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
// them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which
// can be expensive).
removeOutOfView();
// Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So,
// we should consider putting this someplace else... as this might be able to occur less frequently, and save us on
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
cleanupRemovedVoxels();
uint64_t endViewCulling = usecTimestampNow();
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
}
checkForCulling(); // check for out of view and deleted voxels...
bool didWriteFullVBO = _writeRenderFullVBO;
if (_tree->isDirty()) {
@ -547,12 +593,80 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
int elapsedmsec = (end - start) / 1000;
_setupNewVoxelsForDrawingLastFinished = end;
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
_inSetupNewVoxelsForDrawing = false;
}
void VoxelSystem::setupNewVoxelsForDrawingSingleNode() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"setupNewVoxelsForDrawingSingleNode()"); // would like to include _voxelsInArrays, _voxelsUpdated
uint64_t start = usecTimestampNow();
uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000;
// clear up the VBOs for any nodes that have been recently deleted.
clearFreeBufferIndexes();
bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging
if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) {
return; // bail early, it hasn't been long enough since the last time we ran
}
checkForCulling(); // check for out of view and deleted voxels...
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
_voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty
// copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated
copyWrittenDataToReadArrays(_writeRenderFullVBO);
// after...
_voxelsUpdated = 0;
pthread_mutex_unlock(&_bufferWriteLock);
uint64_t end = usecTimestampNow();
int elapsedmsec = (end - start) / 1000;
_setupNewVoxelsForDrawingLastFinished = end;
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
}
void VoxelSystem::checkForCulling() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()");
uint64_t start = usecTimestampNow();
uint64_t sinceLastViewCulling = (start - _lastViewCulling) / 1000;
// If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view
if ((sinceLastViewCulling >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS))
&& !isViewChanging()) {
_lastViewCulling = start;
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
// them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which
// can be expensive).
removeOutOfView();
// Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So,
// we should consider putting this someplace else... as this might be able to occur less frequently, and save us on
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
cleanupRemovedVoxels();
uint64_t endViewCulling = usecTimestampNow();
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
}
}
void VoxelSystem::cleanupRemovedVoxels() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "cleanupRemovedVoxels()");
// This handles cleanup of voxels that were culled as part of our regular out of view culling operation
if (!_removedVoxels.isEmpty()) {
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug() << "cleanupRemovedVoxels().. _removedVoxels=" << _removedVoxels.count() << "\n";
}
while (!_removedVoxels.isEmpty()) {
delete _removedVoxels.extract();
}
@ -560,8 +674,12 @@ void VoxelSystem::cleanupRemovedVoxels() {
}
// we also might have VBO slots that have been abandoned, if too many of our VBO slots
// are abandonded we want to rerender our full VBOs
const float TOO_MANY_ABANDONED_RATIO = 0.25f;
const float TOO_MANY_ABANDONED_RATIO = 0.5f;
if (!_writeRenderFullVBO && (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) {
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug() << "cleanupRemovedVoxels().. _abandonedVBOSlots ["
<< _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO \n";
}
_writeRenderFullVBO = true;
}
}
@ -704,7 +822,6 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) {
return 1; // rendered
} else {
node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
node->setVoxelSystem(NULL);
}
return 0; // not-rendered
@ -805,6 +922,9 @@ void VoxelSystem::init() {
// VBO for the verticesArray
initVoxelMemory();
_initialized = true;
// our own _removedVoxels doesn't need to be notified of voxel deletes
VoxelNode::removeDeleteHook(&_removedVoxels);
}
void VoxelSystem::changeTree(VoxelTree* newTree) {
@ -812,6 +932,7 @@ void VoxelSystem::changeTree(VoxelTree* newTree) {
_tree = newTree;
_tree->setDirtyBit();
_tree->rootNode->setVoxelSystem(this);
connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float)));
connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int)));
@ -1031,7 +1152,7 @@ int VoxelSystem::_nodeCount = 0;
void VoxelSystem::killLocalVoxels() {
_tree->eraseAllVoxels();
_voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this??
//setupNewVoxelsForDrawing();
setupNewVoxelsForDrawing();
}

View file

@ -37,7 +37,7 @@ struct VoxelShaderVBOData
};
class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public NodeListHook {
class VoxelSystem : public NodeData, public VoxelNodeDeleteHook, public VoxelNodeUpdateHook, public NodeListHook {
Q_OBJECT
public:
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM);
@ -109,7 +109,8 @@ public:
CoverageMapV2 myCoverageMapV2;
CoverageMap myCoverageMap;
virtual void nodeDeleted(VoxelNode* node);
virtual void voxelDeleted(VoxelNode* node);
virtual void voxelUpdated(VoxelNode* node);
virtual void nodeAdded(Node* node);
virtual void nodeKilled(Node* node);
@ -134,6 +135,8 @@ public slots:
void clearAllNodesBufferIndex();
void cancelImport();
void setUseFastVoxelPipeline(bool useFastVoxelPipeline);
protected:
float _treeScale;
@ -141,6 +144,8 @@ protected:
VoxelTree* _tree;
void setupNewVoxelsForDrawing();
void setupNewVoxelsForDrawingSingleNode();
void checkForCulling();
glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const;
@ -268,6 +273,9 @@ private:
unsigned long _memoryUsageVBO;
unsigned long _initialMemoryUsageGPU;
bool _hasMemoryUsageGPU;
bool _inSetupNewVoxelsForDrawing;
bool _useFastVoxelPipeline;
};
#endif

View file

@ -83,6 +83,8 @@ void AvatarVoxelSystem::init() {
_boneIndicesLocation = _skinProgram.attributeLocation("boneIndices");
_boneWeightsLocation = _skinProgram.attributeLocation("boneWeights");
VoxelNode::removeUpdateHook(this); // we don't want this
_initialized = true;
}

View file

@ -54,8 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) {
_isDirty = true;
_shouldRender = false;
_sourceID = UNKNOWN_NODE_ID;
markWithChangedTime();
calculateAABox();
markWithChangedTime();
}
VoxelNode::~VoxelNode() {
@ -71,6 +71,11 @@ VoxelNode::~VoxelNode() {
}
}
void VoxelNode::markWithChangedTime() {
_lastChanged = usecTimestampNow();
notifyUpdateHooks(); // if the node has changed, notify our hooks
}
// This method is called by VoxelTree when the subtree below this node
// is known to have changed. It's intended to be used as a place to do
// bookkeeping that a node may need to do when the subtree below it has
@ -78,14 +83,13 @@ VoxelNode::~VoxelNode() {
// localized, because this method will get called for every node in an
// recursive unwinding case like delete or add voxel
void VoxelNode::handleSubtreeChanged(VoxelTree* myTree) {
markWithChangedTime();
// here's a good place to do color re-averaging...
if (myTree->getShouldReaverage()) {
setColorFromAverageOfChildren();
}
recalculateSubTreeNodeCount();
markWithChangedTime();
}
void VoxelNode::recalculateSubTreeNodeCount() {
@ -134,8 +138,8 @@ void VoxelNode::deleteChildAtIndex(int childIndex) {
delete _children[childIndex];
_children[childIndex] = NULL;
_isDirty = true;
markWithChangedTime();
_childCount--;
markWithChangedTime();
}
}
@ -145,8 +149,8 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) {
if (_children[childIndex]) {
_children[childIndex] = NULL;
_isDirty = true;
markWithChangedTime();
_childCount--;
markWithChangedTime();
}
return returnedChild;
}
@ -154,9 +158,10 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) {
VoxelNode* VoxelNode::addChildAtIndex(int childIndex) {
if (!_children[childIndex]) {
_children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex));
_children[childIndex]->setVoxelSystem(_voxelSystem); // our child is always part of our voxel system NULL ok
_isDirty = true;
markWithChangedTime();
_childCount++;
markWithChangedTime();
}
return _children[childIndex];
}
@ -242,9 +247,8 @@ void VoxelNode::setFalseColored(bool isFalseColored) {
}
_falseColored = isFalseColored;
_isDirty = true;
markWithChangedTime();
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
markWithChangedTime();
}
};
@ -256,8 +260,8 @@ void VoxelNode::setColor(const nodeColor& color) {
memcpy(&_currentColor,&color,sizeof(nodeColor));
}
_isDirty = true;
markWithChangedTime();
_density = 1.0f; // If color set, assume leaf, re-averaging will update density if needed.
markWithChangedTime();
}
}
#endif
@ -403,23 +407,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const {
return distance;
}
std::vector<VoxelNodeDeleteHook*> VoxelNode::_hooks;
std::vector<VoxelNodeDeleteHook*> VoxelNode::_deleteHooks;
void VoxelNode::addDeleteHook(VoxelNodeDeleteHook* hook) {
_hooks.push_back(hook);
_deleteHooks.push_back(hook);
}
void VoxelNode::removeDeleteHook(VoxelNodeDeleteHook* hook) {
for (int i = 0; i < _hooks.size(); i++) {
if (_hooks[i] == hook) {
_hooks.erase(_hooks.begin() + i);
for (int i = 0; i < _deleteHooks.size(); i++) {
if (_deleteHooks[i] == hook) {
_deleteHooks.erase(_deleteHooks.begin() + i);
return;
}
}
}
void VoxelNode::notifyDeleteHooks() {
for (int i = 0; i < _hooks.size(); i++) {
_hooks[i]->nodeDeleted(this);
for (int i = 0; i < _deleteHooks.size(); i++) {
_deleteHooks[i]->voxelDeleted(this);
}
}
std::vector<VoxelNodeUpdateHook*> VoxelNode::_updateHooks;
void VoxelNode::addUpdateHook(VoxelNodeUpdateHook* hook) {
_updateHooks.push_back(hook);
}
void VoxelNode::removeUpdateHook(VoxelNodeUpdateHook* hook) {
for (int i = 0; i < _updateHooks.size(); i++) {
if (_updateHooks[i] == hook) {
_updateHooks.erase(_updateHooks.begin() + i);
return;
}
}
}
void VoxelNode::notifyUpdateHooks() {
for (int i = 0; i < _updateHooks.size(); i++) {
_updateHooks[i]->voxelUpdated(this);
}
}

View file

@ -25,9 +25,16 @@ typedef unsigned char rgbColor[3];
// Callers who want delete hook callbacks should implement this class
class VoxelNodeDeleteHook {
public:
virtual void nodeDeleted(VoxelNode* node) = 0;
virtual void voxelDeleted(VoxelNode* node) = 0;
};
// Callers who want update hook callbacks should implement this class
class VoxelNodeUpdateHook {
public:
virtual void voxelUpdated(VoxelNode* node) = 0;
};
class VoxelNode {
public:
VoxelNode(); // root node constructor
@ -72,7 +79,7 @@ public:
void clearDirtyBit() { _isDirty = false; }
void setDirtyBit() { _isDirty = true; }
bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }
void markWithChangedTime() { _lastChanged = usecTimestampNow(); }
void markWithChangedTime();
uint64_t getLastChanged() const { return _lastChanged; }
void handleSubtreeChanged(VoxelTree* myTree);
@ -111,6 +118,9 @@ public:
static void addDeleteHook(VoxelNodeDeleteHook* hook);
static void removeDeleteHook(VoxelNodeDeleteHook* hook);
static void addUpdateHook(VoxelNodeUpdateHook* hook);
static void removeUpdateHook(VoxelNodeUpdateHook* hook);
void recalculateSubTreeNodeCount();
unsigned long getSubTreeNodeCount() const { return _subtreeNodeCount; }
@ -121,6 +131,7 @@ private:
void calculateAABox();
void init(unsigned char * octalCode);
void notifyDeleteHooks();
void notifyUpdateHooks();
nodeColor _trueColor;
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
@ -141,7 +152,8 @@ private:
float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside
uint16_t _sourceID;
static std::vector<VoxelNodeDeleteHook*> _hooks;
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
};
#endif /* defined(__hifi__VoxelNode__) */

View file

@ -127,7 +127,7 @@ void VoxelNodeBag::remove(VoxelNode* node) {
}
void VoxelNodeBag::nodeDeleted(VoxelNode* node) {
void VoxelNodeBag::voxelDeleted(VoxelNode* node) {
remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains()
}

View file

@ -34,7 +34,7 @@ public:
static void voxelNodeDeleteHook(VoxelNode* node, void* extraData);
virtual void nodeDeleted(VoxelNode* node);
virtual void voxelDeleted(VoxelNode* node);
private:

View file

@ -214,10 +214,15 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
memcpy(newColor, nodeData + bytesRead, 3);
bytesRead += 3;
}
bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty();
destinationNode->getChildAtIndex(i)->setColor(newColor);
destinationNode->getChildAtIndex(i)->setSourceID(args.sourceID);
bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty();
VoxelNode* childNodeAt = destinationNode->getChildAtIndex(i);
bool nodeWasDirty = false;
bool nodeIsDirty = false;
if (childNodeAt) {
nodeWasDirty = childNodeAt->isDirty();
childNodeAt->setColor(newColor);
childNodeAt->setSourceID(args.sourceID);
nodeIsDirty = childNodeAt->isDirty();
}
if (nodeIsDirty) {
_isDirty = true;
}
@ -316,7 +321,9 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int
bitstreamAt += theseBytesRead;
bytesRead += theseBytesRead;
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
if (args.wantImportProgress) {
emit importProgress((100 * (bitstreamAt - bitstream)) / bufferSizeBytes);
}
}
this->voxelsBytesRead += bufferSizeBytes;
@ -1539,7 +1546,8 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
// read the entire file into a buffer, WHAT!? Why not.
unsigned char* entireFile = new unsigned char[fileLength];
file.read((char*)entireFile, fileLength);
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS);
bool wantImportProgress = true;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, UNKNOWN_NODE_ID, wantImportProgress);
readBitstreamToTree(entireFile, fileLength, args);
delete[] entireFile;
@ -1798,7 +1806,8 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin
bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params);
// ask destination tree to read the bitstream
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode);
bool wantImportProgress = true;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, UNKNOWN_NODE_ID, wantImportProgress);
readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
}
}

View file

@ -98,20 +98,23 @@ public:
class ReadBitstreamToTreeParams {
public:
bool includeColor;
bool includeExistsBits;
VoxelNode* destinationNode;
uint16_t sourceID;
bool includeColor;
bool includeExistsBits;
VoxelNode* destinationNode;
uint16_t sourceID;
bool wantImportProgress;
ReadBitstreamToTreeParams(
bool includeColor = WANT_COLOR,
bool includeExistsBits = WANT_EXISTS_BITS,
VoxelNode* destinationNode = NULL,
uint16_t sourceID = UNKNOWN_NODE_ID) :
includeColor (includeColor),
includeExistsBits (includeExistsBits),
destinationNode (destinationNode),
sourceID (sourceID)
bool includeColor = WANT_COLOR,
bool includeExistsBits = WANT_EXISTS_BITS,
VoxelNode* destinationNode = NULL,
uint16_t sourceID = UNKNOWN_NODE_ID,
bool wantImportProgress = false) :
includeColor(includeColor),
includeExistsBits(includeExistsBits),
destinationNode(destinationNode),
sourceID(sourceID),
wantImportProgress(wantImportProgress)
{}
};