From 8dc61d89fcb58a00e3fd1117e05939b874f136fb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 14 May 2013 14:19:31 -0700 Subject: [PATCH] Added support for "destructive" vs "non-destructive" voxel create - changed VoxelTree to support destructive and non-destructive mode - added protocol packet headers to differentiate - added new UI to switch modes - default mode now, non-destructive. --- interface/src/Application.cpp | 19 ++++++++---- interface/src/Application.h | 2 ++ interface/src/VoxelSystem.cpp | 14 +++++---- interface/src/VoxelSystem.h | 8 +++-- libraries/shared/src/PacketHeaders.h | 1 + libraries/voxels/src/VoxelTree.cpp | 45 ++++++++++++++++------------ libraries/voxels/src/VoxelTree.h | 34 +++++++++++---------- voxel-server/src/main.cpp | 8 +++-- 8 files changed, 79 insertions(+), 52 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eaebaee9ff..0a6fd4e948 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -147,6 +147,7 @@ Application::Application(int& argc, char** argv) : _paintOn(false), _dominantColor(0), _perfStatsOn(false), + _destructiveAddVoxel(false), _chatEntryOn(false), _oculusTextureID(0), _oculusProgram(0), @@ -989,6 +990,10 @@ void Application::cycleFrustumRenderMode() { updateFrustumRenderModeAction(); } +void Application::setDestructivePaint(bool destructive) { + _destructiveAddVoxel = destructive; +} + void Application::setRenderWarnings(bool renderWarnings) { _voxels.setRenderPipelineWarnings(renderWarnings); } @@ -1075,6 +1080,7 @@ void Application::initMenu() { _renderStatsOn->setShortcut(Qt::Key_Slash); (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(true); + toolsMenu->addAction("Create Voxel is Destructive", this, SLOT(setDestructivePaint(bool)))->setCheckable(true); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); @@ -1295,7 +1301,8 @@ void Application::updateAvatar(float deltaTime) { _paintingVoxel.y >= 0.0 && _paintingVoxel.y <= 1.0 && _paintingVoxel.z >= 0.0 && _paintingVoxel.z <= 1.0) { - sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, _paintingVoxel); + PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + sendVoxelEditMessage(message, _paintingVoxel); } } } @@ -1876,19 +1883,21 @@ void Application::addVoxelInFrontOfAvatar() { detail.green = 128; detail.blue = 128; - sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, detail); + PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + sendVoxelEditMessage(message, detail); // create the voxel locally so it appears immediately - _voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue); + _voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue, _destructiveAddVoxel); } void Application::addVoxelUnderCursor() { if (_mouseVoxel.s != 0) { - sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, _mouseVoxel); + PACKET_HEADER message = (_destructiveAddVoxel ? PACKET_HEADER_SET_VOXEL_DESTRUCTIVE : PACKET_HEADER_SET_VOXEL); + sendVoxelEditMessage(message, _mouseVoxel); // create the voxel locally so it appears immediately _voxels.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, - _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue); + _mouseVoxel.red, _mouseVoxel.green, _mouseVoxel.blue, _destructiveAddVoxel); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 1b1eb69fb3..e22409a77b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -76,6 +76,7 @@ private slots: void setFrustumOffset(bool frustumOffset); void cycleFrustumRenderMode(); + void setDestructivePaint(bool destructive); void setRenderWarnings(bool renderWarnings); void doKillLocalVoxels(); void doRandomizeVoxelColors(); @@ -200,6 +201,7 @@ private: VoxelDetail _paintingVoxel; // The voxel we're painting if we're painting bool _perfStatsOn; // Do we want to display perfStats? + bool _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive ChatEntry _chatEntry; // chat entry field bool _chatEntryOn; // Whether to show the chat entry diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b3c483717d..513253ec19 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1020,22 +1020,24 @@ VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { return _tree->getVoxelAt(x, y, z, s); }; -void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) { +void VoxelSystem::createVoxel(float x, float y, float z, float s, + unsigned char red, unsigned char green, unsigned char blue, bool destructive) { pthread_mutex_lock(&_treeLock); //printLog("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); - _tree->createVoxel(x, y, z, s, red, green, blue); + _tree->createVoxel(x, y, z, s, red, green, blue, destructive); setupNewVoxelsForDrawing(); pthread_mutex_unlock(&_treeLock); }; -void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color) { - _tree->createLine(point1, point2, unitSize, color); +void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { + _tree->createLine(point1, point2, unitSize, color, destructive); setupNewVoxelsForDrawing(); }; -void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug) { - _tree->createSphere(r, xc, yc, zc, s, solid, mode, debug); +void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, + creationMode mode, bool destructive, bool debug) { + _tree->createSphere(r, xc, yc, zc, s, solid, mode, destructive, debug); setupNewVoxelsForDrawing(); }; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 31bf781311..50997d84bf 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -73,9 +73,11 @@ public: void deleteVoxelAt(float x, float y, float z, float s); VoxelNode* getVoxelAt(float x, float y, float z, float s) const; - void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); - void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug = false); + void createVoxel(float x, float y, float z, float s, + unsigned char red, unsigned char green, unsigned char blue, bool destructive = false); + void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false); + void createSphere(float r,float xc, float yc, float zc, float s, bool solid, + creationMode mode, bool destructive = false, bool debug = false); private: int _callsToTreesToArrays; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 49b2fe9d00..bd16bf9ea7 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -21,6 +21,7 @@ const PACKET_HEADER PACKET_HEADER_HEAD_DATA = 'H'; const PACKET_HEADER PACKET_HEADER_Z_COMMAND = 'Z'; const PACKET_HEADER PACKET_HEADER_INJECT_AUDIO = 'I'; const PACKET_HEADER PACKET_HEADER_SET_VOXEL = 'S'; +const PACKET_HEADER PACKET_HEADER_SET_VOXEL_DESTRUCTIVE = 'O'; const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V'; const PACKET_HEADER PACKET_HEADER_VOXEL_DATA_MONOCHROME = 'v'; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d22073a54b..e3cf16b753 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -287,7 +287,7 @@ void VoxelTree::eraseAllVoxels() { _isDirty = true; } -void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { +void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive) { VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL); // create the node if it does not exist @@ -297,19 +297,27 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { } else { // if it does exist, make sure it has no children for (int i = 0; i < 8; i++) { - lastCreatedNode->deleteChildAtIndex(i); + if (lastCreatedNode->getChildAtIndex(i)) { + if (destructive) { + lastCreatedNode->deleteChildAtIndex(i); + } else { + printLog("WARNING! operation would require deleting child at index %d, add Voxel ignored!\n ", i); + } + } } } - // give this node its color - int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer); + if (lastCreatedNode->isLeaf()) { + // give this node its color + int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer); - nodeColor newColor; - memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); - newColor[3] = 1; - lastCreatedNode->setColor(newColor); - if (lastCreatedNode->isDirty()) { - _isDirty = true; + nodeColor newColor; + memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); + newColor[3] = 1; + lastCreatedNode->setColor(newColor); + if (lastCreatedNode->isDirty()) { + _isDirty = true; + } } } @@ -463,14 +471,15 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { return node; } -void VoxelTree::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) { +void VoxelTree::createVoxel(float x, float y, float z, float s, + unsigned char red, unsigned char green, unsigned char blue, bool destructive) { unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue); - this->readCodeColorBufferToTree(voxelData); + this->readCodeColorBufferToTree(voxelData, destructive); delete voxelData; } -void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color) { +void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { glm::vec3 distance = point2 - point1; glm::vec3 items = distance / unitSize; int maxItems = std::max(items.x, std::max(items.y, items.z)); @@ -478,14 +487,12 @@ void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, r glm::vec3 pointAt = point1; for (int i = 0; i <= maxItems; i++ ) { pointAt += increment; - unsigned char* voxelData = pointToVoxel(pointAt.x,pointAt.y,pointAt.z,unitSize,color[0],color[1],color[2]); - readCodeColorBufferToTree(voxelData); - delete voxelData; + createVoxel(pointAt.x, pointAt.y, pointAt.z, unitSize, color[0], color[1], color[2], destructive); } } void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float voxelSize, - bool solid, creationMode mode, bool debug) { + bool solid, creationMode mode, bool destructive, bool debug) { bool wantColorRandomizer = (mode == RANDOM); bool wantNaturalSurface = (mode == NATURAL); @@ -601,13 +608,13 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v x = xc + (thisRadius + i * subVoxelScale) * cos(theta) * sin(phi); y = yc + (thisRadius + i * subVoxelScale) * sin(theta) * sin(phi); z = zc + (thisRadius + i * subVoxelScale) * cos(phi); - this->createVoxel(x, y, z, subVoxelScale, red, green, blue); + this->createVoxel(x, y, z, subVoxelScale, red, green, blue, destructive); } naturalSurfaceRendered = true; } } if (!naturalSurfaceRendered) { - this->createVoxel(x, y, z, thisVoxelSize, red, green, blue); + this->createVoxel(x, y, z, thisVoxelSize, red, green, blue, destructive); } } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 3c33c7b02c..6d384f0244 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -22,36 +22,38 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; class VoxelTree { public: // when a voxel is created in the tree (object new'd) - long voxelsCreated; + long voxelsCreated; // when a voxel is colored/set in the tree (object may have already existed) - long voxelsColored; - long voxelsBytesRead; - + long voxelsColored; + long voxelsBytesRead; + SimpleMovingAverage voxelsCreatedStats; - SimpleMovingAverage voxelsColoredStats; - SimpleMovingAverage voxelsBytesReadStats; + SimpleMovingAverage voxelsColoredStats; + SimpleMovingAverage voxelsBytesReadStats; VoxelTree(); ~VoxelTree(); - + VoxelNode *rootNode; int leavesWrittenToBitstream; - void eraseAllVoxels(); + void eraseAllVoxels(); - void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); + void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, bool includeColor = true); - void readCodeColorBufferToTree(unsigned char *codeColorBuffer); - void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = false); + void readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive = false); + void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = false); void printTreeForDebugging(VoxelNode *startNode); void reaverageVoxelColors(VoxelNode *startNode); void deleteVoxelAt(float x, float y, float z, float s, bool stage = false); VoxelNode* getVoxelAt(float x, float y, float z, float s) const; - void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); - void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug = false); - + void createVoxel(float x, float y, float z, float s, + unsigned char red, unsigned char green, unsigned char blue, bool destructive = false); + void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false); + void createSphere(float r,float xc, float yc, float zc, float s, bool solid, + creationMode mode, bool destructive = false, bool debug = false); + void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, @@ -70,7 +72,7 @@ public: VoxelNode*& node, float& distance, BoxFace& face); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); + void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); // these will read/write files that match the wireformat, excluding the 'V' leading void writeToFileV2(const char* filename) const; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 74a2ca73ca..6530bc1d6f 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -503,9 +503,11 @@ int main(int argc, const char * argv[]) if (agentList->getAgentSocket().receive(&agentPublicAddress, packetData, &receivedBytes)) { // XXXBHG: Hacked in support for 'S' SET command - if (packetData[0] == PACKET_HEADER_SET_VOXEL) { + if (packetData[0] == PACKET_HEADER_SET_VOXEL || packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) { + bool destructive = (packetData[0] == PACKET_HEADER_SET_VOXEL_DESTRUCTIVE); unsigned short int itemNumber = (*((unsigned short int*)&packetData[1])); - printf("got I - insert voxels - command from client receivedBytes=%ld itemNumber=%d\n", + printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n", + destructive ? "PACKET_HEADER_SET_VOXEL_DESTRUCTIVE" : "PACKET_HEADER_SET_VOXEL", receivedBytes,itemNumber); int atByte = 3; unsigned char* pVoxelData = (unsigned char*)&packetData[3]; @@ -534,7 +536,7 @@ int main(int argc, const char * argv[]) printf("inserting voxel at: %f,%f,%f\n",vertices[0],vertices[1],vertices[2]); delete []vertices; - randomTree.readCodeColorBufferToTree(pVoxelData); + randomTree.readCodeColorBufferToTree(pVoxelData, destructive); // skip to next pVoxelData+=voxelDataSize; atByte+=voxelDataSize;