From 62b29d26d28e468a27714012e5f693b1b77fdd6e Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Thu, 29 Aug 2013 18:17:06 -0700 Subject: [PATCH 1/4] Nudge function added. Testing nudge. --- interface/src/Application.cpp | 3 + interface/src/VoxelSystem.h | 1 + libraries/voxels/src/VoxelNode.cpp | 2 +- libraries/voxels/src/VoxelTree.cpp | 93 +++++++++++++++++++++++++++++- libraries/voxels/src/VoxelTree.h | 7 +++ 5 files changed, 102 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d69770678c..e22f1c0ccb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1543,6 +1543,9 @@ void Application::update(float deltaTime) { hoveredNode->setColor(_hoverVoxelOriginalColor); _isHoverVoxelSounding = false; } + glm::vec3 nudgeVec(1, 1, 1); + _voxels.getVoxelTree()->nudgeSubTree(hoveredNode, nudgeVec); + // qDebug("nudge called!\n"); } else { // Voxel is not found, clear all _isHoverVoxelSounding = false; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7b6c001e8a..c51df3ce70 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -60,6 +60,7 @@ public: float getVoxelsCreatedPerSecondAverage(); float getVoxelsColoredPerSecondAverage(); float getVoxelsBytesReadPerSecondAverage(); + VoxelTree* getVoxelTree() {return _tree;} void killLocalVoxels(); diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 7355e91243..72fb72d466 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -422,4 +422,4 @@ void VoxelNode::notifyDeleteHooks() { for (int i = 0; i < _hooks.size(); i++) { _hooks[i]->nodeDeleted(this); } -} +} \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b17200448b..b06562fa7b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -206,7 +206,7 @@ VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode, return childNode; } else { // we need to go deeper - return nodeForOctalCode(childNode, needleCode,parentOfFoundNode); + return nodeForOctalCode(childNode, needleCode, parentOfFoundNode); } } } @@ -452,10 +452,10 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat } } } - int lengthOfancestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode()); + int lengthOfAncestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode()); // If we've reached the parent of the target, then stop breaking up children - if (lengthOfancestorNode == (args->lengthOfCode - 1)) { + if (lengthOfAncestorNode == (args->lengthOfCode - 1)) { break; } ancestorNode->addChildAtIndex(index); @@ -1911,3 +1911,90 @@ void VoxelTree::emptyDeleteQueue() { void VoxelTree::cancelImport() { _stopImport = true; } + +class NodeChunkArgs { +public: + VoxelTree* thisVoxelTree; + float newSize; + glm::vec3 nudgeVec; +}; + +bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) { + if (node->isLeaf()) { + // we have reached the deepest level of nodes/voxels + // now there are two scenarios + // 1) this node's size is <= the minNudgeAmount + // in which case we will simply call nudgeLeaf on this leaf + // 2) this node's size is still not <= the minNudgeAmount + // in which case we need to break this leaf down until the leaf sizes are <= minNudgeAmount + + NodeChunkArgs* args = (NodeChunkArgs*)extraData; + + // get octal code of this node + unsigned char* octalCode = node->getOctalCode(); + + // get voxel position/size + VoxelPositionSize unNudgedDetails; + voxelDetailsForCode(octalCode, unNudgedDetails); + + // check to see if this unNudged node can be nudged + if (unNudgedDetails.s <= args->newSize) { + args->thisVoxelTree->nudgeLeaf(node, extraData); + return false; + } else { + // break the current leaf into smaller chunks + args->thisVoxelTree->chunkifyLeaf(node); + } + } + return true; +} + +void VoxelTree::chunkifyLeaf(VoxelNode* node) { + // because this function will continue being called recursively + // we only need to worry about breaking this specific leaf down + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + node->addChildAtIndex(i); + if (node->isColored()) { + node->getChildAtIndex(i)->setColor(node->getColor()); + } + } +} + +// This function is called to nudge the leaves of a tree, given that the +// nudge amount is >= to the leaf scale. +void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { + NodeChunkArgs* args = (NodeChunkArgs*)extraData; + + // get octal code of this node + unsigned char* octalCode = node->getOctalCode(); + + // get voxel position/size + VoxelPositionSize unNudgedDetails; + voxelDetailsForCode(octalCode, unNudgedDetails); + + // delete the old node + deleteVoxelAt(unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z, unNudgedDetails.s); + qDebug("unNudged voxel deleted!\n"); + + // create a new voxel in its stead + glm::vec3 nudge = args->nudgeVec; + qDebug("nudged by %f, %f, %f\n", nudge.x, nudge.y, nudge.z); + // createVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, unNudgedDetails.s, + // node->getColor()[0], node->getColor()[1], node->getColor()[2], true); + createVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, unNudgedDetails.s, + 0, 0, 0, true); + qDebug("nudged voxel created!\n"); +} + +void VoxelTree::nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount) { + // calculate minNudgeAmount to check if breaking the tree into smaller chunks is necessary + float minNudgeAmount = fmin(nudgeAmount.x, nudgeAmount.y); + minNudgeAmount = fmin(minNudgeAmount, nudgeAmount.z); + + NodeChunkArgs args; + args.thisVoxelTree = this; + args.newSize = minNudgeAmount; + args.nudgeVec = nudgeAmount; + + recurseNodeWithOperation(nodeToNudge, nudgeCheck, &args); +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 4128ba6cbd..396edcc542 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -195,6 +195,8 @@ public: RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData); + void nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount); + signals: void importSize(float x, float y, float z); void importProgress(int progress); @@ -254,6 +256,11 @@ private: void queueForLaterDelete(unsigned char* codeBuffer); /// flushes out any Octal Codes that had to be queued void emptyDeleteQueue(); + + // helper functions for nudgeSubTree + static bool nudgeCheck(VoxelNode* node, void* extraData); + void nudgeLeaf(VoxelNode* node, void* extraData); + void chunkifyLeaf(VoxelNode* node); }; float boundaryDistanceForRenderLevel(unsigned int renderLevel); From 6e37bc3644c728b044317538bc2e6408b1ef2875 Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Thu, 5 Sep 2013 11:06:12 -0700 Subject: [PATCH 2/4] Nudge code working for nudge that is greater than or equal to leaf size. --- interface/src/Application.cpp | 57 ++++++++++++++++-- interface/src/Application.h | 3 + interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + libraries/voxels/src/VoxelEditPacketSender.h | 1 + libraries/voxels/src/VoxelTree.cpp | 61 +++++++++++++++++--- libraries/voxels/src/VoxelTree.h | 5 +- 7 files changed, 113 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e22f1c0ccb..b90b8cbe0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -130,7 +130,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesPerSecond(0), _bytesCount(0), _swatch(NULL), - _pasteMode(false) + _pasteMode(false), + _nudgeCount(0) { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); @@ -1272,6 +1273,50 @@ void Application::pasteVoxels() { } } +void Application::nudgeVoxels() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + if (selectedNode) { + qDebug("UnNudged xyz: %f, %f, %f\n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); + // // clear the clipboard first... + // _clipboard.killLocalVoxels(); + + // nudge the node + glm::vec3 nudgeVec(0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s); + // glm::vec3 nudgeVec(_mouseVoxel.s, _mouseVoxel.s, _mouseVoxel.s); + // _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel); + _voxels.getVoxelTree()->nudgeSubTree(selectedNode, nudgeVec, _voxelEditSender); + + // if (!selectedNode) { + // qDebug("new node is null\n"); + // } else { + // // get octal code of this node + // unsigned char* octalCode = selectedNode->getOctalCode(); + + // // get voxel position/size + // VoxelPositionSize nudgedDetails; + // voxelDetailsForCode(octalCode, nudgedDetails); + // qDebug("Nudged xyz: %f, %f, %f\n", nudgedDetails.x, nudgedDetails.y, nudgedDetails.z); + // } + + // // then copy onto it + // _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboard, true); + // // deleteVoxelUnderCursor(); + + // // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to + // // the server as an set voxel message, this will also rebase the voxels to the new location + // SendVoxelsOperationArgs args; + + // // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a + // // target octalCode for where the user is pointing. + // args.newBaseOctCode = selectedNode->getOctalCode(); + + // _clipboard.recurseTreeWithOperation(sendVoxelsOperation, &args); + // _voxelEditSender.flushQueue(); + } +} + void Application::setListenModeNormal() { _audio.setListenMode(AudioRingBuffer::NORMAL); } @@ -1543,9 +1588,11 @@ void Application::update(float deltaTime) { hoveredNode->setColor(_hoverVoxelOriginalColor); _isHoverVoxelSounding = false; } - glm::vec3 nudgeVec(1, 1, 1); - _voxels.getVoxelTree()->nudgeSubTree(hoveredNode, nudgeVec); - // qDebug("nudge called!\n"); + // if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) { + // nudgeVoxels(); + // _nudgeCount++; + // qDebug("nudgeCount = %d\n", _nudgeCount); + // } } else { // Voxel is not found, clear all _isHoverVoxelSounding = false; @@ -1637,7 +1684,7 @@ void Application::update(float deltaTime) { _mouseVoxel.red = 255; _mouseVoxel.green = _mouseVoxel.blue = 0; } else if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) { - // yellow indicates deletion + // yellow indicates selection _mouseVoxel.red = _mouseVoxel.green = 255; _mouseVoxel.blue = 0; } else { // _addVoxelMode->isChecked() || _colorVoxelMode->isChecked() diff --git a/interface/src/Application.h b/interface/src/Application.h index a88ea3269f..f1c1d53a66 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -142,6 +142,7 @@ public slots: void cutVoxels(); void copyVoxels(); void pasteVoxels(); + void nudgeVoxels(); void setRenderVoxels(bool renderVoxels); void doKillLocalVoxels(); @@ -352,6 +353,8 @@ private: NodeToJurisdictionMap _voxelServerJurisdictions; std::vector _voxelFades; + + int _nudgeCount; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 119f21df60..937ef5b74c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -249,6 +249,7 @@ Menu::Menu() : addActionToQMenuAndActionHash(voxelMenu, MenuOption::CutVoxels, Qt::CTRL | Qt::Key_X, appInstance, SLOT(cutVoxels())); addActionToQMenuAndActionHash(voxelMenu, MenuOption::CopyVoxels, Qt::CTRL | Qt::Key_C, appInstance, SLOT(copyVoxels())); addActionToQMenuAndActionHash(voxelMenu, MenuOption::PasteVoxels, Qt::CTRL | Qt::Key_V, appInstance, SLOT(pasteVoxels())); + addActionToQMenuAndActionHash(voxelMenu, MenuOption::NudgeVoxels, Qt::CTRL | Qt::Key_N, appInstance, SLOT(nudgeVoxels())); QMenu* debugMenu = addMenu("Debug"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 252c9a8707..6934f09d8f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -158,6 +158,7 @@ namespace MenuOption { const QString LookAtVectors = "Look-at Vectors"; const QString LowRes = "Lower Resolution While Moving"; const QString Mirror = "Mirror"; + const QString NudgeVoxels = "Nudge Voxels"; const QString OcclusionCulling = "Occlusion Culling"; const QString Oscilloscope = "Audio Oscilloscope"; const QString Pair = "Pair"; diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index e07bd11baa..bda2c8006d 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -12,6 +12,7 @@ #define __shared__VoxelEditPacketSender__ #include +#include #include // for VoxelDetail #include "JurisdictionMap.h" diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b06562fa7b..6f125e0d6b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -31,6 +31,7 @@ #include "VoxelConstants.h" #include "VoxelNodeBag.h" #include "VoxelTree.h" +#include float boundaryDistanceForRenderLevel(unsigned int renderLevel) { return ::VOXEL_SIZE_SCALE / powf(2, renderLevel); @@ -1912,11 +1913,20 @@ void VoxelTree::cancelImport() { _stopImport = true; } +typedef unsigned char nodeColor[4]; + +const nodeColor red = {255, 0, 0, 0}; +const nodeColor green = {0, 255, 0, 0}; +const nodeColor blue = {0, 0, 255, 0}; + class NodeChunkArgs { public: VoxelTree* thisVoxelTree; float newSize; glm::vec3 nudgeVec; + VoxelEditPacketSender* voxelEditSenderPtr; + + int colorIndex; }; bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) { @@ -1943,20 +1953,31 @@ bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) { return false; } else { // break the current leaf into smaller chunks - args->thisVoxelTree->chunkifyLeaf(node); + args->thisVoxelTree->chunkifyLeaf(node, extraData); } } return true; } -void VoxelTree::chunkifyLeaf(VoxelNode* node) { +void VoxelTree::chunkifyLeaf(VoxelNode* node, void* extraData) { // because this function will continue being called recursively // we only need to worry about breaking this specific leaf down + if (!node->isColored()) { + return; + } + NodeChunkArgs* args = (NodeChunkArgs*)extraData; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { node->addChildAtIndex(i); - if (node->isColored()) { - node->getChildAtIndex(i)->setColor(node->getColor()); + if (args->colorIndex == 0) { + node->getChildAtIndex(i)->setColor(red); + } else if (args->colorIndex == 1) { + node->getChildAtIndex(i)->setColor(green); + } else if (args->colorIndex == 2) { + node->getChildAtIndex(i)->setColor(blue); } + args->colorIndex++; + args->colorIndex = args->colorIndex % 3; + // node->getChildAtIndex(i)->setColor(node->getColor()); } } @@ -1971,9 +1992,21 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { // get voxel position/size VoxelPositionSize unNudgedDetails; voxelDetailsForCode(octalCode, unNudgedDetails); + VoxelDetail voxelDetails; + voxelDetails.x = unNudgedDetails.x; + voxelDetails.y = unNudgedDetails.y; + voxelDetails.z = unNudgedDetails.z; + voxelDetails.s = unNudgedDetails.s; + voxelDetails.red = node->getColor()[0]; + qDebug("rgb: %u, %u, %u\n", node->getColor()[0], node->getColor()[1], node->getColor()[2]); + voxelDetails.green = node->getColor()[1]; + voxelDetails.blue = node->getColor()[2]; + + qDebug("UnNudged xyz: %f, %f, %f\n", unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z); // delete the old node - deleteVoxelAt(unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z, unNudgedDetails.s); + args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails); + // deleteVoxelAt(unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z, unNudgedDetails.s); qDebug("unNudged voxel deleted!\n"); // create a new voxel in its stead @@ -1981,12 +2014,20 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { qDebug("nudged by %f, %f, %f\n", nudge.x, nudge.y, nudge.z); // createVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, unNudgedDetails.s, // node->getColor()[0], node->getColor()[1], node->getColor()[2], true); - createVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, unNudgedDetails.s, - 0, 0, 0, true); - qDebug("nudged voxel created!\n"); + voxelDetails.x = unNudgedDetails.x + nudge.x; + voxelDetails.y = unNudgedDetails.y + nudge.y; + voxelDetails.z = unNudgedDetails.z + nudge.z; + qDebug("Nudged xyz: %f, %f, %f\n", voxelDetails.x, voxelDetails.y, voxelDetails.z); + args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL, voxelDetails); + // unsigned char* newOctalCode = pointToVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, + // unNudgedDetails.s, node->getColor()[0], node->getColor()[1], node->getColor()[2]); + + // // node = new VoxelNode(newOctalCode); + // node = NULL; + qDebug("nudged node created!\n"); } -void VoxelTree::nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount) { +void VoxelTree::nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount, VoxelEditPacketSender& voxelEditSender) { // calculate minNudgeAmount to check if breaking the tree into smaller chunks is necessary float minNudgeAmount = fmin(nudgeAmount.x, nudgeAmount.y); minNudgeAmount = fmin(minNudgeAmount, nudgeAmount.z); @@ -1995,6 +2036,8 @@ void VoxelTree::nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmoun args.thisVoxelTree = this; args.newSize = minNudgeAmount; args.nudgeVec = nudgeAmount; + args.voxelEditSenderPtr = &voxelEditSender; + args.colorIndex = 0; recurseNodeWithOperation(nodeToNudge, nudgeCheck, &args); } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 396edcc542..b684c96923 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -19,6 +19,7 @@ #include "VoxelNode.h" #include "VoxelNodeBag.h" #include "VoxelSceneStats.h" +#include "VoxelEditPacketSender.h" #include @@ -195,7 +196,7 @@ public: RecurseVoxelTreeOperation operation, const glm::vec3& point, void* extraData); - void nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount); + void nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmount, VoxelEditPacketSender& voxelEditSender); signals: void importSize(float x, float y, float z); @@ -260,7 +261,7 @@ private: // helper functions for nudgeSubTree static bool nudgeCheck(VoxelNode* node, void* extraData); void nudgeLeaf(VoxelNode* node, void* extraData); - void chunkifyLeaf(VoxelNode* node); + void chunkifyLeaf(VoxelNode* node, void* extraData); }; float boundaryDistanceForRenderLevel(unsigned int renderLevel); From 647bd5b704922d79b973a7d16c1673f6265aa46a Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Thu, 5 Sep 2013 11:30:23 -0700 Subject: [PATCH 3/4] Got rid of delete in nudge. Create is already destructive. --- interface/src/Application.cpp | 2 ++ libraries/voxels/src/VoxelTree.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b90b8cbe0a..2d963f939d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1314,6 +1314,8 @@ void Application::nudgeVoxels() { // _clipboard.recurseTreeWithOperation(sendVoxelsOperation, &args); // _voxelEditSender.flushQueue(); + } else { + qDebug("selectedNode is NULL\n"); } } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6f125e0d6b..bb20dd1d4a 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -2005,9 +2005,10 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { qDebug("UnNudged xyz: %f, %f, %f\n", unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z); // delete the old node - args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails); + // creating a voxel is inherently destructive + // args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails); // deleteVoxelAt(unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z, unNudgedDetails.s); - qDebug("unNudged voxel deleted!\n"); + // qDebug("unNudged voxel deleted!\n"); // create a new voxel in its stead glm::vec3 nudge = args->nudgeVec; From 868ef8bec67922f4488be9f7341e29d762aa5778 Mon Sep 17 00:00:00 2001 From: LionTurtle Date: Thu, 5 Sep 2013 17:42:25 -0700 Subject: [PATCH 4/4] Add VoxelNudgeMode and preliminary UI grid for nudging. --- interface/src/Application.cpp | 80 ++++++++++++------------------ interface/src/Application.h | 4 +- interface/src/Menu.cpp | 3 ++ interface/src/Menu.h | 1 + interface/src/Util.cpp | 26 ++++++++++ interface/src/Util.h | 2 + libraries/voxels/src/VoxelTree.cpp | 55 ++++++++++---------- libraries/voxels/src/VoxelTree.h | 2 +- 8 files changed, 92 insertions(+), 81 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2d963f939d..9f8453449c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -130,8 +130,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesPerSecond(0), _bytesCount(0), _swatch(NULL), - _pasteMode(false), - _nudgeCount(0) + _pasteMode(false) { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); @@ -689,6 +688,9 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_O: Menu::getInstance()->triggerOption(MenuOption::VoxelSelectMode); break; + case Qt::Key_N: + Menu::getInstance()->triggerOption(MenuOption::VoxelNudgeMode); + break; case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); break; @@ -830,6 +832,9 @@ void Application::mousePressEvent(QMouseEvent* event) { } if (MAKE_SOUND_ON_VOXEL_CLICK && _isHoverVoxel && !_isHoverVoxelSounding) { + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelNudgeMode)) { + _nudgeVoxel = _hoverVoxel; + } _hoverVoxelOriginalColor[0] = _hoverVoxel.red; _hoverVoxelOriginalColor[1] = _hoverVoxel.green; _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; @@ -1274,48 +1279,22 @@ void Application::pasteVoxels() { } void Application::nudgeVoxels() { - VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelNudgeMode)) { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - if (selectedNode) { - qDebug("UnNudged xyz: %f, %f, %f\n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); - // // clear the clipboard first... - // _clipboard.killLocalVoxels(); + if (selectedNode) { + // glPushMatrix(); + // glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); + // renderNudgeGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + // glPopMatrix(); + qDebug("UnNudged xyz: %f, %f, %f\n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z); - // nudge the node - glm::vec3 nudgeVec(0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s); - // glm::vec3 nudgeVec(_mouseVoxel.s, _mouseVoxel.s, _mouseVoxel.s); - // _voxelEditSender.sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, _mouseVoxel); - _voxels.getVoxelTree()->nudgeSubTree(selectedNode, nudgeVec, _voxelEditSender); - - // if (!selectedNode) { - // qDebug("new node is null\n"); - // } else { - // // get octal code of this node - // unsigned char* octalCode = selectedNode->getOctalCode(); - - // // get voxel position/size - // VoxelPositionSize nudgedDetails; - // voxelDetailsForCode(octalCode, nudgedDetails); - // qDebug("Nudged xyz: %f, %f, %f\n", nudgedDetails.x, nudgedDetails.y, nudgedDetails.z); - // } - - // // then copy onto it - // _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboard, true); - // // deleteVoxelUnderCursor(); - - // // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to - // // the server as an set voxel message, this will also rebase the voxels to the new location - // SendVoxelsOperationArgs args; - - // // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a - // // target octalCode for where the user is pointing. - // args.newBaseOctCode = selectedNode->getOctalCode(); - - // _clipboard.recurseTreeWithOperation(sendVoxelsOperation, &args); - // _voxelEditSender.flushQueue(); - } else { - qDebug("selectedNode is NULL\n"); + // nudge the node + // glm::vec3 nudgeVec(_mouseVoxel.s, _mouseVoxel.s, _mouseVoxel.s); + // glm::vec3 nudgeVec(0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s, 0.5 * _mouseVoxel.s); + glm::vec3 nudgeVec(0.25 * _mouseVoxel.s, 0.25 * _mouseVoxel.s, 0.25 * _mouseVoxel.s); + _voxels.getVoxelTree()->nudgeSubTree(selectedNode, nudgeVec, _voxelEditSender); + } } } @@ -1404,6 +1383,7 @@ void Application::init() { _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelColorMode), 0, 2); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelGetColorMode), 0, 3); _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelSelectMode), 0, 4); + _palette.addAction(Menu::getInstance()->getActionForOption(MenuOption::VoxelNudgeMode), 0, 5); _pieMenu.init("./resources/images/hifi-interface-tools-v2-pie.svg", _glWidget->width(), @@ -1590,11 +1570,6 @@ void Application::update(float deltaTime) { hoveredNode->setColor(_hoverVoxelOriginalColor); _isHoverVoxelSounding = false; } - // if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) { - // nudgeVoxels(); - // _nudgeCount++; - // qDebug("nudgeCount = %d\n", _nudgeCount); - // } } else { // Voxel is not found, clear all _isHoverVoxelSounding = false; @@ -1689,6 +1664,8 @@ void Application::update(float deltaTime) { // yellow indicates selection _mouseVoxel.red = _mouseVoxel.green = 255; _mouseVoxel.blue = 0; + } else if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelNudgeMode)) { + _mouseVoxel.red = _mouseVoxel.green = _mouseVoxel.blue = 255; } else { // _addVoxelMode->isChecked() || _colorVoxelMode->isChecked() QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value(); _mouseVoxel.red = paintColor.red(); @@ -2221,7 +2198,14 @@ void Application::displaySide(Camera& whichCamera) { glDisable(GL_LIGHTING); glPushMatrix(); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); - renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelNudgeMode)) { + VoxelNode* selectedNode = _voxels.getVoxelAt(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s); + if (selectedNode) { + renderNudgeGrid(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s); + } + } else { + renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelAddMode)) { // use a contrasting color so that we can see what we're doing glColor3ub(_mouseVoxel.red + 128, _mouseVoxel.green + 128, _mouseVoxel.blue + 128); diff --git a/interface/src/Application.h b/interface/src/Application.h index f1c1d53a66..aca11301b2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -295,6 +295,8 @@ private: glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit bool _justEditedVoxel; // set when we've just added/deleted/colored a voxel + VoxelDetail _nudgeVoxel; // details of the voxel to be nudged + bool _isLookingAtOtherAvatar; glm::vec3 _lookatOtherPosition; float _lookatIndicatorScale; @@ -353,8 +355,6 @@ private: NodeToJurisdictionMap _voxelServerJurisdictions; std::vector _voxelFades; - - int _nudgeCount; }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 937ef5b74c..3cfc804a89 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -206,6 +206,9 @@ Menu::Menu() : QAction* colorVoxelMode = addCheckableActionToQMenuAndActionHash(voxelMenu, MenuOption::VoxelColorMode, Qt::Key_B); _voxelModeActionsGroup->addAction(colorVoxelMode); + + QAction* nudgeVoxelMode = addCheckableActionToQMenuAndActionHash(voxelMenu, MenuOption::VoxelNudgeMode, Qt::Key_N); + _voxelModeActionsGroup->addAction(nudgeVoxelMode); QAction* selectVoxelMode = addCheckableActionToQMenuAndActionHash(voxelMenu, MenuOption::VoxelSelectMode, Qt::Key_O); _voxelModeActionsGroup->addAction(selectVoxelMode); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6934f09d8f..57840604b5 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -195,6 +195,7 @@ namespace MenuOption { const QString VoxelGetColorMode = "Get Color Mode"; const QString VoxelMode = "Cycle Voxel Mode"; const QString VoxelPaintColor = "Voxel Paint Color"; + const QString VoxelNudgeMode = "Nudge Voxel Mode"; const QString VoxelSelectMode = "Select Voxel Mode"; const QString VoxelStats = "Voxel Stats"; const QString VoxelTextures = "Voxel Textures"; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 743957128c..6de1bee2c7 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -414,6 +414,32 @@ void renderMouseVoxelGrid(const float& mouseVoxelX, const float& mouseVoxelY, co glEnd(); } +void renderNudgeGrid(const float& mouseVoxelX, const float& mouseVoxelY, const float& mouseVoxelZ, const float& mouseVoxelS) { + glm::vec3 origin = glm::vec3(mouseVoxelX, mouseVoxelY, mouseVoxelZ); + + glLineWidth(1.0); + + const int GRID_DIMENSIONS = 4; + glBegin(GL_LINES); + + for (int i = 0; i <= GRID_DIMENSIONS; i++) { + for (int j = -GRID_DIMENSIONS / 2; j <= GRID_DIMENSIONS / 2; j++) { + glm::vec3 xColor(0.0, 0.6, 0.0); + glColor3fv(&xColor.x); + + glVertex3f(origin.x + GRID_DIMENSIONS * mouseVoxelS, i * mouseVoxelS, origin.z + j * mouseVoxelS); + glVertex3f(origin.x - GRID_DIMENSIONS * mouseVoxelS, i * mouseVoxelS, origin.z + j * mouseVoxelS); + + glm::vec3 zColor(0.0, 0.0, 0.6); + glColor3fv(&zColor.x); + + glVertex3f(origin.x + j * mouseVoxelS, i * mouseVoxelS, origin.z + GRID_DIMENSIONS * mouseVoxelS); + glVertex3f(origin.x + j * mouseVoxelS, i * mouseVoxelS, origin.z - GRID_DIMENSIONS * mouseVoxelS); + } + } + glEnd(); +} + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness) { glColor4f(0.0f, 0.0f, 0.0f, darkness); diff --git a/interface/src/Util.h b/interface/src/Util.h index c1bb2949fa..dd41b2bab7 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -61,6 +61,8 @@ void renderGroundPlaneGrid(float size, float impact); void renderMouseVoxelGrid(const float& mouseVoxelX, const float& mouseVoxelY, const float& mouseVoxelZ, const float& mouseVoxelS); +void renderNudgeGrid(const float& mouseVoxelX, const float& mouseVoxelY, const float& mouseVoxelZ, const float& mouseVoxelS); + void renderCollisionOverlay(int width, int height, float magnitude); void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index bb20dd1d4a..6a8ba7b28d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1922,6 +1922,7 @@ const nodeColor blue = {0, 0, 255, 0}; class NodeChunkArgs { public: VoxelTree* thisVoxelTree; + float ancestorSize; float newSize; glm::vec3 nudgeVec; VoxelEditPacketSender* voxelEditSenderPtr; @@ -1953,31 +1954,21 @@ bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) { return false; } else { // break the current leaf into smaller chunks - args->thisVoxelTree->chunkifyLeaf(node, extraData); + args->thisVoxelTree->chunkifyLeaf(node); } } return true; } -void VoxelTree::chunkifyLeaf(VoxelNode* node, void* extraData) { +void VoxelTree::chunkifyLeaf(VoxelNode* node) { // because this function will continue being called recursively // we only need to worry about breaking this specific leaf down if (!node->isColored()) { return; } - NodeChunkArgs* args = (NodeChunkArgs*)extraData; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { node->addChildAtIndex(i); - if (args->colorIndex == 0) { - node->getChildAtIndex(i)->setColor(red); - } else if (args->colorIndex == 1) { - node->getChildAtIndex(i)->setColor(green); - } else if (args->colorIndex == 2) { - node->getChildAtIndex(i)->setColor(blue); - } - args->colorIndex++; - args->colorIndex = args->colorIndex % 3; - // node->getChildAtIndex(i)->setColor(node->getColor()); + node->getChildAtIndex(i)->setColor(node->getColor()); } } @@ -1992,39 +1983,35 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) { // get voxel position/size VoxelPositionSize unNudgedDetails; voxelDetailsForCode(octalCode, unNudgedDetails); + + qDebug("UnNudged xyz: %f, %f, %f\n", unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z); + VoxelDetail voxelDetails; voxelDetails.x = unNudgedDetails.x; voxelDetails.y = unNudgedDetails.y; voxelDetails.z = unNudgedDetails.z; voxelDetails.s = unNudgedDetails.s; voxelDetails.red = node->getColor()[0]; - qDebug("rgb: %u, %u, %u\n", node->getColor()[0], node->getColor()[1], node->getColor()[2]); voxelDetails.green = node->getColor()[1]; voxelDetails.blue = node->getColor()[2]; - - qDebug("UnNudged xyz: %f, %f, %f\n", unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z); + glm::vec3 nudge = args->nudgeVec; // delete the old node - // creating a voxel is inherently destructive - // args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails); - // deleteVoxelAt(unNudgedDetails.x, unNudgedDetails.y, unNudgedDetails.z, unNudgedDetails.s); - // qDebug("unNudged voxel deleted!\n"); + if (nudge.x >= args->ancestorSize && nudge.y >= args->ancestorSize && nudge.z >= args->ancestorSize) { + args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_ERASE_VOXEL, voxelDetails); + qDebug("unNudged voxel deleted!\n"); + } - // create a new voxel in its stead - glm::vec3 nudge = args->nudgeVec; + // nudge the old node qDebug("nudged by %f, %f, %f\n", nudge.x, nudge.y, nudge.z); - // createVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, unNudgedDetails.s, - // node->getColor()[0], node->getColor()[1], node->getColor()[2], true); + voxelDetails.x = unNudgedDetails.x + nudge.x; voxelDetails.y = unNudgedDetails.y + nudge.y; voxelDetails.z = unNudgedDetails.z + nudge.z; - qDebug("Nudged xyz: %f, %f, %f\n", voxelDetails.x, voxelDetails.y, voxelDetails.z); - args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL, voxelDetails); - // unsigned char* newOctalCode = pointToVoxel(unNudgedDetails.x + nudge.x, unNudgedDetails.y + nudge.y, unNudgedDetails.z + nudge.z, - // unNudgedDetails.s, node->getColor()[0], node->getColor()[1], node->getColor()[2]); - // // node = new VoxelNode(newOctalCode); - // node = NULL; + // create a new voxel in its stead + args->voxelEditSenderPtr->sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL, voxelDetails); + qDebug("Nudged xyz: %f, %f, %f\n", voxelDetails.x, voxelDetails.y, voxelDetails.z); qDebug("nudged node created!\n"); } @@ -2033,8 +2020,16 @@ void VoxelTree::nudgeSubTree(VoxelNode* nodeToNudge, const glm::vec3& nudgeAmoun float minNudgeAmount = fmin(nudgeAmount.x, nudgeAmount.y); minNudgeAmount = fmin(minNudgeAmount, nudgeAmount.z); + // get octal code of this node + unsigned char* octalCode = nodeToNudge->getOctalCode(); + + // get voxel position/size + VoxelPositionSize ancestorDetails; + voxelDetailsForCode(octalCode, ancestorDetails); + NodeChunkArgs args; args.thisVoxelTree = this; + args.ancestorSize = ancestorDetails.s; args.newSize = minNudgeAmount; args.nudgeVec = nudgeAmount; args.voxelEditSenderPtr = &voxelEditSender; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index b684c96923..281cef63e8 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -261,7 +261,7 @@ private: // helper functions for nudgeSubTree static bool nudgeCheck(VoxelNode* node, void* extraData); void nudgeLeaf(VoxelNode* node, void* extraData); - void chunkifyLeaf(VoxelNode* node, void* extraData); + void chunkifyLeaf(VoxelNode* node); }; float boundaryDistanceForRenderLevel(unsigned int renderLevel);