From d1d2e75143b110bbedd0e843fa0d898b716e4b69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 May 2013 19:00:02 -0700 Subject: [PATCH 01/44] first cut at export and import of voxels --- interface/src/Application.cpp | 40 +++++++++++++++++++++++++++++- interface/src/Application.h | 5 +++- interface/src/VoxelSystem.cpp | 12 +++++++++ interface/src/VoxelSystem.h | 2 ++ libraries/voxels/src/VoxelTree.cpp | 11 +++++--- libraries/voxels/src/VoxelTree.h | 4 +-- voxel-server/src/main.cpp | 2 +- 7 files changed, 68 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a0979eb4b9..b18a0095e7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -853,7 +854,10 @@ void Application::idle() { // red indicates deletion _mouseVoxel.red = 255; _mouseVoxel.green = _mouseVoxel.blue = 0; - + } else if (_selectVoxelMode->isChecked()) { + // yellow indicates deletion + _mouseVoxel.red = _mouseVoxel.green = 255; + _mouseVoxel.blue = 0; } else { // _addVoxelMode->isChecked() || _colorVoxelMode->isChecked() QColor paintColor = _voxelPaintColor->data().value(); _mouseVoxel.red = paintColor.red(); @@ -1136,6 +1140,35 @@ void Application::chooseVoxelPaintColor() { // restore the main window's active state _window->activateWindow(); } + +void Application::exportVoxels() { + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", + tr("High Fidelity Voxel Files (*.hio2)")); + QByteArray fileNameAscii = fileNameString.toAscii(); + const char* fileName = fileNameAscii.data(); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, + _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } + _voxels.writeToFileV2(fileName,selectedNode); +} + +void Application::importVoxels() { + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); + QByteArray fileNameAscii = fileNameString.toAscii(); + const char* fileName = fileNameAscii.data(); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, + _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } + + // not yet supported!!! + _voxels.readFromFileV2(fileName,selectedNode); +} void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); @@ -1202,6 +1235,9 @@ void Application::initMenu() { (_colorVoxelMode = voxelMenu->addAction( "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_3))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); + (_selectVoxelMode = voxelMenu->addAction( + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_8))->setCheckable(true); + _voxelModeActions->addAction(_selectVoxelMode); voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::Key_4); voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::Key_5); @@ -1212,6 +1248,8 @@ void Application::initMenu() { _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); + voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); + voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index 35d49d275a..ed03708bd9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -99,7 +99,9 @@ private slots: void decreaseVoxelSize(); void increaseVoxelSize(); void chooseVoxelPaintColor(); - + void exportVoxels(); + void importVoxels(); + private: void initMenu(); @@ -155,6 +157,7 @@ private: QAction* _addVoxelMode; // Whether add voxel mode is enabled QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled QAction* _colorVoxelMode; // Whether color voxel mode is enabled + QAction* _selectVoxelMode; // Whether select voxel mode is enabled QAction* _voxelPaintColor; // The color with which to paint voxels QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index ea8787a902..2a0a7e7a7a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -70,6 +70,18 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } +void VoxelSystem::writeToFileV2(const char* filename, VoxelNode* node) const { + _tree->writeToFileV2(filename, node); +} + +bool VoxelSystem::readFromFileV2(const char* filename, VoxelNode* node) { + bool result = _tree->readFromFileV2(filename, node); + if (result) { + setupNewVoxelsForDrawing(); + } + return result; +} + long int VoxelSystem::getVoxelsCreated() { return _tree->voxelsCreated; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7bffb1d33c..1aeb66a7c6 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -44,6 +44,8 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); + void writeToFileV2(const char* filename, VoxelNode* node) const; + bool readFromFileV2(const char* filename, VoxelNode* node); long int getVoxelsCreated(); long int getVoxelsColored(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 798b447d6c..89b584a541 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1105,7 +1105,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } -bool VoxelTree::readFromFileV2(const char* fileName) { +bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { printLog("loading file %s...\n", fileName); @@ -1126,7 +1126,7 @@ bool VoxelTree::readFromFileV2(const char* fileName) { return false; } -void VoxelTree::writeToFileV2(const char* fileName) const { +void VoxelTree::writeToFileV2(const char* fileName, VoxelNode* node) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); @@ -1134,7 +1134,12 @@ void VoxelTree::writeToFileV2(const char* fileName) const { printLog("saving to file %s...\n", fileName); VoxelNodeBag nodeBag; - nodeBag.insert(rootNode); + // If we were given a specific node, start from there, otherwise start from root + if (node) { + nodeBag.insert(node); + } else { + nodeBag.insert(rootNode); + } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 0643b1038e..5e56be5062 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -91,8 +91,8 @@ public: 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; - bool readFromFileV2(const char* filename); + void writeToFileV2(const char* filename, VoxelNode* node = NULL) const; + bool readFromFileV2(const char* filename, VoxelNode* node = NULL); unsigned long getVoxelCount(); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 1a93021f09..70f7ab8752 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -517,7 +517,7 @@ int main(int argc, const char * argv[]) { const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); if (voxelsFilename) { - randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer); + randomTree.readFromFileV2(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate From eb675c8dd79d16ca17d2e6de7da0b129247fe82e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 08:25:30 -0700 Subject: [PATCH 02/44] fix crash when no audio mixer available --- libraries/audio/src/AudioInjectionManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 275161730e..b49151616d 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -58,7 +58,10 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) { // if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list if (!_isDestinationSocketExplicit) { - _destinationSocket = *AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER)->getActiveSocket(); + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + if (audioMixer) { + _destinationSocket = *audioMixer->getActiveSocket(); + } } injector->injectAudio(_injectorSocket, &_destinationSocket); From 377fb1e936ef64670145d947b771bba1d0e1ad18 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 12:06:58 -0700 Subject: [PATCH 03/44] latest copy and paste --- interface/src/Application.cpp | 35 +++++++++++++++----- interface/src/Application.h | 2 ++ interface/src/main.cpp | 14 ++++++++ libraries/shared/src/OctalCode.cpp | 51 ++++++++++++++++++++++++++++++ libraries/shared/src/OctalCode.h | 3 ++ libraries/voxels/src/VoxelTree.cpp | 27 +++++++++++++++- libraries/voxels/src/VoxelTree.h | 4 +++ 7 files changed, 127 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3908164890..95e3e5f1c1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1153,6 +1153,22 @@ void Application::importVoxels() { // not yet supported!!! _voxels.readFromFileV2(fileName,selectedNode); } + +void Application::copyVoxels() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } +} + +void Application::pasteVoxels() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } +} void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); @@ -1211,29 +1227,32 @@ void Application::initMenu() { _voxelModeActions = new QActionGroup(this); _voxelModeActions->setExclusive(false); // exclusivity implies one is always checked (_addVoxelMode = voxelMenu->addAction( - "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_1))->setCheckable(true); + "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_A))->setCheckable(true); _voxelModeActions->addAction(_addVoxelMode); (_deleteVoxelMode = voxelMenu->addAction( - "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_2))->setCheckable(true); + "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_D))->setCheckable(true); _voxelModeActions->addAction(_deleteVoxelMode); (_colorVoxelMode = voxelMenu->addAction( - "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_3))->setCheckable(true); + "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_C))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); (_selectVoxelMode = voxelMenu->addAction( - "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_8))->setCheckable(true); + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); - voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::Key_4); - voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::Key_5); - voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::Key_6); + voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::SHIFT | Qt::Key_P); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Minus); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Plus); - _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::Key_7); + _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), + Qt::CTRL | Qt::SHIFT | Qt::Key_C); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); + voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index ed03708bd9..57605f8cc5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,6 +101,8 @@ private slots: void chooseVoxelPaintColor(); void exportVoxels(); void importVoxels(); + void copyVoxels(); + void pasteVoxels(); private: diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ea915658af..5091eb9f4f 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -18,7 +18,21 @@ #include "Application.h" #include "Log.h" +#include + int main(int argc, const char * argv[]) { + + unsigned char test1[2] = {2, 0xE0 }; + unsigned char test2[2] = {2, 0xFC }; + + unsigned char* result1 = chopOctalCode((unsigned char*)&test1, 1); + + printOctalCode((unsigned char*)&test1); + printOctalCode(result1); + + unsigned char* result2 = chopOctalCode((unsigned char*)&test2, 1); + printOctalCode((unsigned char*)&test2); + printOctalCode(result2); timeval startup_time; gettimeofday(&startup_time, NULL); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index d218639882..b69136ddb6 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -168,3 +168,54 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB return result; } + +char getOctalCodeSectionValue(unsigned char* octalCode, int section) { + return sectionValue(octalCode + 1 + (3 * section / 8), (3 * section) % 8); +} + +void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { + unsigned char* byteAt = octalCode + 1 + (3 * section / 8); + char bitInByte = (3 * section) % 8; + char shiftBy = 8 - bitInByte - 3; + const unsigned char UNSHIFTED_MASK = 0x03; + unsigned char shiftedMask; + unsigned char shiftedValue; + + + if (shiftBy >=0) { + shiftedMask = UNSHIFTED_MASK << shiftBy; + shiftedValue = sectionValue << shiftBy; + } else { + shiftedMask = UNSHIFTED_MASK >> -shiftBy; + shiftedValue = sectionValue >> -shiftBy; + } + + byteAt[0] = byteAt[0] & (shiftedMask | shiftedValue); + if (bitInByte >= 6) { + shiftBy = bitInByte + 1; + shiftedMask = UNSHIFTED_MASK << shiftBy; + shiftedValue = sectionValue << shiftBy; + + byteAt[1] = byteAt[1] & (shiftedMask | shiftedValue); + } +} + +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { + int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + unsigned char* newCode = NULL; + if (codeLength > chopLevels) { + int newLength = codeLength - chopLevels; + newCode = new unsigned char[newLength+1]; + *newCode = newLength; // set the length byte + + for (int section = chopLevels; section < codeLength; section++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); + setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); + } + } + return newCode; +} + +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode) { +} + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bf4a6ef699..bce7a066b9 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -17,6 +17,9 @@ bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * child int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); + // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 01a9ace8b6..a0864964a2 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -53,7 +53,7 @@ VoxelTree::~VoxelTree() { // Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. // stops recursion if operation function returns false. void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { - recurseNodeWithOperation(rootNode, operation,extraData); + recurseNodeWithOperation(rootNode, operation, extraData); } // Recurses voxel node with an operation function @@ -1165,3 +1165,28 @@ bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { (*(unsigned long*)extraData)++; return true; // keep going } + +void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { + + printLog("copySubTreeIntoNewTree()...\n"); + + VoxelNodeBag nodeBag; + // If we were given a specific node, start from there, otherwise start from root + nodeBag.insert(startNode); + + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + + while (!nodeBag.isEmpty()) { + VoxelNode* subTree = nodeBag.extract(); + + // ask our tree to write a bitsteam + bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], + MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + + // ask destination tree to read the bitstream + destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + } + + +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 5e56be5062..eccc4e0434 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -95,6 +95,9 @@ public: bool readFromFileV2(const char* filename, VoxelNode* node = NULL); unsigned long getVoxelCount(); + + void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); + void copyNodeIntoTree(VoxelNode* node); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, @@ -107,6 +110,7 @@ private: bool deltaViewFrustum, const ViewFrustum* lastViewFrustum); static bool countVoxelsOperation(VoxelNode* node, void* extraData); + static bool copySubTreeIntoNewTreeOperation(VoxelNode* node, void* extraData); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; From 46c6f2f9b5f3add89a29fb695a53401a68c5057f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 15:02:28 -0700 Subject: [PATCH 04/44] latest copy paste --- interface/src/Application.cpp | 13 +++++++- interface/src/Application.h | 2 ++ interface/src/VoxelSystem.cpp | 9 ++++++ interface/src/VoxelSystem.h | 4 +++ interface/src/main.cpp | 13 -------- libraries/shared/src/OctalCode.cpp | 16 ++++++--- libraries/shared/src/OctalCode.h | 1 + libraries/voxels/src/VoxelTree.cpp | 52 ++++++++++++++++++++++++------ libraries/voxels/src/VoxelTree.h | 26 +++++++-------- 9 files changed, 95 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95e3e5f1c1..7f5eeccd76 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1159,6 +1159,7 @@ void Application::copyVoxels() { printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { selectedNode->printDebugDetails("selected voxel"); + _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); } } @@ -1166,7 +1167,17 @@ void Application::pasteVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + // First, create a temporary Paste Tree + VoxelTree _temporaryPasteTree; + + // Create a destination node to paste into + _temporaryPasteTree.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, 0, 0, 0); + + // Paste into the temporary tree + destinationNode = _temporaryPasteTree.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + _temporaryPasteTree.copyFromTreeIntoSubTree(&_clipboardTree, destinationNode); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 57605f8cc5..85d5d7ef43 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -184,6 +184,8 @@ private: Stars _stars; VoxelSystem _voxels; + VoxelTree _clipboardTree; // if I copy/paste + QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2a0a7e7a7a..359e5b77af 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1156,3 +1156,12 @@ void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bo _tree->createSphere(r, xc, yc, zc, s, solid, mode, destructive, debug); setupNewVoxelsForDrawing(); }; + +void VoxelSystem::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { + _tree->copySubTreeIntoNewTree(startNode, destinationTree, rebaseToRoot); +} + +void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { + _tree->copyFromTreeIntoSubTree(sourceTree, destinationNode); +} + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 1aeb66a7c6..c15ba53ba0 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -85,6 +85,10 @@ public: 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 copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); + void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); + private: // disallow copying of VoxelSystem objects VoxelSystem(const VoxelSystem&); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 5091eb9f4f..8894e5bd7c 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -21,19 +21,6 @@ #include int main(int argc, const char * argv[]) { - - unsigned char test1[2] = {2, 0xE0 }; - unsigned char test2[2] = {2, 0xFC }; - - unsigned char* result1 = chopOctalCode((unsigned char*)&test1, 1); - - printOctalCode((unsigned char*)&test1); - printOctalCode(result1); - - unsigned char* result2 = chopOctalCode((unsigned char*)&test2, 1); - printOctalCode((unsigned char*)&test2); - printOctalCode(result2); - timeval startup_time; gettimeofday(&startup_time, NULL); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index b69136ddb6..f331545b33 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -170,14 +170,18 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB char getOctalCodeSectionValue(unsigned char* octalCode, int section) { - return sectionValue(octalCode + 1 + (3 * section / 8), (3 * section) % 8); + int startAtByte = 1 + (3 * section / 8); + char startIndexInByte = (3 * section) % 8; + unsigned char* startByte = octalCode + startAtByte; + + return sectionValue(startByte, startIndexInByte); } void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { unsigned char* byteAt = octalCode + 1 + (3 * section / 8); char bitInByte = (3 * section) % 8; char shiftBy = 8 - bitInByte - 3; - const unsigned char UNSHIFTED_MASK = 0x03; + const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; @@ -190,13 +194,17 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio shiftedValue = sectionValue >> -shiftBy; } - byteAt[0] = byteAt[0] & (shiftedMask | shiftedValue); + unsigned char oldValue = *byteAt & ~shiftedMask; + unsigned char newValue = oldValue | shiftedValue; + *byteAt = newValue; if (bitInByte >= 6) { shiftBy = bitInByte + 1; shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; - byteAt[1] = byteAt[1] & (shiftedMask | shiftedValue); + oldValue = byteAt[1] & ~shiftedMask; + newValue = oldValue | shiftedValue; + byteAt[1] = newValue; } } diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bce7a066b9..1849989cc3 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -19,6 +19,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); +int numberOfThreeBitSectionsInCode(unsigned char * octalCode); // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index a0864964a2..562cfcc88c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -212,10 +212,15 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, - bool includeColor, bool includeExistsBits) { + bool includeColor, bool includeExistsBits, VoxelNode* destinationNode) { int bytesRead = 0; unsigned char* bitstreamAt = bitstream; + // If destination node is not included, set it to root + if (!destinationNode) { + destinationNode = rootNode; + } + _nodesChangedFromBitstream = 0; // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes @@ -223,14 +228,14 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int // if there are more bytes after that, it's assumed to be another root relative tree while (bitstreamAt < bitstream + bufferSizeBytes) { - VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL); + VoxelNode* bitstreamRootNode = nodeForOctalCode(destinationNode, (unsigned char *)bitstreamAt, NULL); if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) { // if the octal code returned is not on the same level as // the code being searched for, we have VoxelNodes to create // Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial // octal code is always relative to root! - bitstreamRootNode = createMissingNode(rootNode, (unsigned char*) bitstreamAt); + bitstreamRootNode = createMissingNode(destinationNode, (unsigned char*) bitstreamAt); if (bitstreamRootNode->isDirty()) { _isDirty = true; _nodesChangedFromBitstream++; @@ -862,7 +867,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -882,7 +887,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, node, outputBuffer, availableBytes, - bag, viewFrustum, includeColor, includeExistsBits, + bag, viewFrustum, includeColor, includeExistsBits, chopLevels, deltaViewFrustum, lastViewFrustum); // if childBytesWritten == 1 then something went wrong... that's not possible @@ -907,7 +912,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1062,7 +1067,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, outputBuffer, availableBytes, bag, - viewFrustum, includeColor, includeExistsBits, + viewFrustum, includeColor, includeExistsBits, chopLevels, deltaViewFrustum, lastViewFrustum); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, @@ -1173,6 +1178,12 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat VoxelNodeBag nodeBag; // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(startNode); + + int chopLevels = 0; + + if (rebaseToRoot) { + chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); + } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; @@ -1182,11 +1193,32 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // ask our tree to write a bitsteam bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], - MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); // ask destination tree to read the bitstream destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); } - - } + +void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { + printLog("copyFromTreeIntoSubTree()...\n"); + + VoxelNodeBag nodeBag; + // If we were given a specific node, start from there, otherwise start from root + nodeBag.insert(sourceTree->rootNode); + + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + + while (!nodeBag.isEmpty()) { + VoxelNode* subTree = nodeBag.extract(); + + // ask our tree to write a bitsteam + bytesWritten = sourceTree->encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], + MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + + // ask destination tree to read the bitstream + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + } +} + diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index eccc4e0434..a2302f6cc7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -44,19 +44,20 @@ public: VoxelTree(bool shouldReaverage = false); ~VoxelTree(); - VoxelNode *rootNode; + VoxelNode* rootNode; int leavesWrittenToBitstream; void eraseAllVoxels(); - void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS); - void readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive = false); - void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = ACTUALLY_DELETE, + void processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes); + void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, + VoxelNode* destinationNode = NULL); + void readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive = false); + void deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage = ACTUALLY_DELETE, bool collapseEmptyTrees = DONT_COLLAPSE); - void printTreeForDebugging(VoxelNode *startNode); - void reaverageVoxelColors(VoxelNode *startNode); + 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; @@ -70,7 +71,7 @@ public: int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, @@ -97,20 +98,19 @@ public: unsigned long getVoxelCount(); void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); - void copyNodeIntoTree(VoxelNode* node); + void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, - const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; + const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum); static bool countVoxelsOperation(VoxelNode* node, void* extraData); - static bool copySubTreeIntoNewTreeOperation(VoxelNode* node, void* extraData); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; From 1eac57dd0c5f7a8bced6f2e51093ae885edd4ca7 Mon Sep 17 00:00:00 2001 From: Geenz Date: Thu, 30 May 2013 15:02:11 -0400 Subject: [PATCH 05/44] #19351 - Atmosphere shaders should be handled per-pixel instead of per-vertex. --- .../resources/shaders/SkyFromAtmosphere.frag | 154 +++++++++++----- .../resources/shaders/SkyFromAtmosphere.vert | 165 +++++++----------- interface/resources/shaders/SkyFromSpace.frag | 161 ++++++++++++----- interface/resources/shaders/SkyFromSpace.vert | 150 +++++----------- 4 files changed, 325 insertions(+), 305 deletions(-) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index 37d26ba40a..c7fedd4e4a 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -1,48 +1,106 @@ -#version 120 - -// -// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: -// -// NVIDIA Statement on the Software -// -// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are -// detailed. -// -// No Warranty -// -// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL -// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -// Limitation of Liability -// -// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR -// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT -// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY -// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH -// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. -// - -// -// Atmospheric scattering fragment shader -// -// Author: Sean O'Neil -// -// Copyright (c) 2004 Sean O'Neil -// - -uniform vec3 v3LightPos; -uniform float g; -uniform float g2; - -varying vec3 v3Direction; - - -void main (void) -{ - float fCos = dot(v3LightPos, v3Direction) / length(v3Direction); - float fMiePhase = 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5); - gl_FragColor = gl_Color + fMiePhase * gl_SecondaryColor; - gl_FragColor.a = gl_FragColor.b; -} +#version 120 + +// +// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: +// +// NVIDIA Statement on the Software +// +// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are +// detailed. +// +// No Warranty +// +// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL +// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +// Limitation of Liability +// +// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR +// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT +// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY +// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH +// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. +// + +// +// Atmospheric scattering fragment shader +// +// Author: Sean O'Neil +// +// Copyright (c) 2004 Sean O'Neil +// + +uniform vec3 v3CameraPos; // The camera's current position +uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels +uniform float fInnerRadius; // The inner (planetary) radius +uniform float fKrESun; // Kr * ESun +uniform float fKmESun; // Km * ESun +uniform float fKr4PI; // Kr * 4 * PI +uniform float fKm4PI; // Km * 4 * PI +uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) +uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +uniform float fScaleOverScaleDepth; // fScale / fScaleDepth + +const int nSamples = 2; +const float fSamples = 2.0; + +uniform vec3 v3LightPos; +uniform float g; +uniform float g2; + +varying vec3 position; + +float scale(float fCos) +{ + float x = 1.0 - fCos; + return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +void main (void) +{ + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = position; + vec3 v3Ray = v3Pos - v3CameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = v3CameraPos; + float fHeight = length(v3Start); + float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepth * scale(fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + for(int i=0; i Date: Fri, 31 May 2013 11:52:18 -0700 Subject: [PATCH 06/44] more work on copy and paste --- interface/src/Application.cpp | 67 ++++++++++++++++++++++++++---- interface/src/Application.h | 2 + libraries/shared/src/OctalCode.cpp | 21 +++++++++- libraries/shared/src/OctalCode.h | 7 ++-- libraries/voxels/src/VoxelTree.cpp | 22 ++++++++-- 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b6aba80c06..5395bfa54f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include "Application.h" #include "InterfaceConfig.h" @@ -1319,26 +1320,76 @@ void Application::copyVoxels() { if (selectedNode) { selectedNode->printDebugDetails("selected voxel"); _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); + + // debug tree + _clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } +const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; +struct SendVoxelsOperataionArgs { + unsigned char* newBaseOctCode; + unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; + int bufferInUse; + +}; + void Application::pasteVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - // First, create a temporary Paste Tree - VoxelTree _temporaryPasteTree; + // 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 + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + args.newBaseOctCode = selectedNode->getOctalCode(); + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); - // Create a destination node to paste into - _temporaryPasteTree.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, 0, 0, 0); - - // Paste into the temporary tree - destinationNode = _temporaryPasteTree.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - _temporaryPasteTree.copyFromTreeIntoSubTree(&_clipboardTree, destinationNode); + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + } } } + +bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { + SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; + if (node->isColored()) { + const int SIZE_OF_COLOR_DATA = 3; + const int RED_INDEX = 0; + const int GREEN_INDEX = 1; + const int BLUE_INDEX = 2; + unsigned char* nodeOctalCode = node->getOctalCode(); + printOctalCode(nodeOctalCode); + unsigned char* rebasedCodeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); + printOctalCode(rebasedCodeColorBuffer); + int rebasedCodeLength = numberOfThreeBitSectionsInCode(rebasedCodeColorBuffer); + int bytesInRebasedCode = bytesRequiredForCodeLength(rebasedCodeLength); + int codeAndColorLength = bytesInRebasedCode + SIZE_OF_COLOR_DATA; + + // copy the colors over + rebasedCodeColorBuffer[bytesInRebasedCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; + rebasedCodeColorBuffer[bytesInRebasedCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; + rebasedCodeColorBuffer[bytesInRebasedCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; + + // if we have room don't have room in the buffer, then send the previously generated message first + if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + } + + // copy this node's code color details into our buffer. + memcpy(&args->messageBuffer[args->bufferInUse], rebasedCodeColorBuffer, codeAndColorLength); + args->bufferInUse += codeAndColorLength; + } + return true; // keep going +} + void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9a6d02ecc0..7761d9a84b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -160,6 +160,8 @@ private slots: void pasteVoxels(); private: + + static bool sendVoxelsOperataion(VoxelNode* node, void* extraData); void initMenu(); void updateFrustumRenderModeAction(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index f331545b33..150789bec8 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -224,6 +224,25 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { return newCode; } -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode) { +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace) { + int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); + int newCodeLength = newParentCodeLength + oldCodeLength; + const int COLOR_SPACE = 3; + int bufferLength = newCodeLength + (includeColorSpace ? COLOR_SPACE : 0); + unsigned char* newCode = new unsigned char[bufferLength]; + *newCode = newCodeLength; // set the length byte + + // copy parent code section first + for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { + char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); + setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); + } + // copy original code section next + for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); + setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); + } + return newCode; } diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 1849989cc3..bfed24a87c 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -16,11 +16,10 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); - -unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); int numberOfThreeBitSectionsInCode(unsigned char * octalCode); - +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, + bool includeColorSpace = false); // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 562cfcc88c..704c15e4db 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -878,9 +878,22 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned } // write the octal code - int codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); - memcpy(outputBuffer,node->getOctalCode(),codeLength); - + int codeLength; + if (chopLevels) { + unsigned char* newCode = chopOctalCode(node->getOctalCode(), chopLevels); + if (newCode) { + codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); + memcpy(outputBuffer, newCode, codeLength); + delete newCode; + } else { + codeLength = 1; // chopped to root! + *outputBuffer = 0; // root + } + } else { + codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); + memcpy(outputBuffer, node->getOctalCode(), codeLength); + } + outputBuffer += codeLength; // move the pointer bytesWritten += codeLength; // keep track of byte count availableBytes -= codeLength; // keep track or remaining space @@ -1183,6 +1196,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat if (rebaseToRoot) { chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); + printLog("copySubTreeIntoNewTree()...rebaseToRoot=true, chopLevels=%d\n", chopLevels); } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static @@ -1218,7 +1232,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); // ask destination tree to read the bitstream - readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS,destinationNode); } } From e4bc7af6b4a95a52dde268a2f09a5ef40eca7a38 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 14:52:29 -0700 Subject: [PATCH 07/44] Working on avatar voxels. --- interface/src/Application.cpp | 9 +++-- interface/src/Application.h | 1 + interface/src/Avatar.cpp | 20 ++++++++++- interface/src/Avatar.h | 3 ++ interface/src/VoxelSystem.cpp | 63 +++++++++++++++++++---------------- interface/src/VoxelSystem.h | 15 ++++----- 6 files changed, 68 insertions(+), 43 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dd3dba178..12af31234b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -156,8 +156,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); - _voxels.setViewFrustum(&_viewFrustum); - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); @@ -1417,8 +1415,6 @@ void Application::initDisplay() { void Application::init() { _voxels.init(); - _voxels.setViewerAvatar(&_myAvatar); - _voxels.setCamera(&_myCamera); _environment.init(); @@ -1429,6 +1425,7 @@ void Application::init() { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); + _myAvatar.init(); _myAvatar.setPosition(START_LOCATION); _myCamera.setMode(CAMERA_MODE_THIRD_PERSON ); _myCamera.setModeShiftRate(1.0f); @@ -2298,7 +2295,9 @@ QAction* Application::checkedVoxelModeAction() const { void Application::attachNewHeadToAgent(Agent* newAgent) { if (newAgent->getLinkedData() == NULL) { - newAgent->setLinkedData(new Avatar(newAgent)); + Avatar* newAvatar = new Avatar(newAgent); + newAvatar->init(); + newAgent->setLinkedData(newAvatar); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 22694aaae5..c2918f1add 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -65,6 +65,7 @@ public: Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } + ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 3a4162d296..886fb78d97 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -61,6 +61,8 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; bool usingBigSphereCollisionTest = true; @@ -93,7 +95,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -119,6 +122,12 @@ Avatar::~Avatar() { delete _balls; } +void Avatar::init() { + _voxels.init(); + + _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); +} + void Avatar::reset() { _head.reset(); } @@ -1132,6 +1141,15 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque const float RENDER_TRANSLUCENT_BEYOND = 0.5f; + // Render the body's voxels + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.z); + glm::quat rotation = getOrientation(); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); + _voxels.render(false); + glPopMatrix(); + // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { float distanceToCamera = glm::length(_cameraPosition - _joint[b].position); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d272514ed1..d1bc651eff 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -19,6 +19,7 @@ #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" +#include "VoxelSystem.h" enum DriveKeys { @@ -46,6 +47,7 @@ public: Avatar(Agent* owningAgent = NULL); ~Avatar(); + void init(); void reset(); void simulate(float deltaTime, Transmitter* transmitter); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface); @@ -147,6 +149,7 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; + VoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5e1b72e5c4..b4202511e6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "Application.h" #include "Log.h" #include "VoxelConstants.h" #include "InterfaceConfig.h" @@ -37,14 +38,15 @@ GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1, -1,0,0, +1,0,0, +1,0,0, -1,0,0, -1,0,0, +1,0,0, +1,0,0, -1,0,0 }; -GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . +GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- 8,9,13, 8,13,12, // Y- 16,23,19, 16,20,23, // X- 17,18,22, 17,22,21, // X+ 10,11,15, 10,15,14, // Y+ - 4,5,6, 4,6,7 }; // Z+ . + 4,5,6, 4,6,7 }; // Z+ -VoxelSystem::VoxelSystem() : AgentData(NULL) { +VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : + AgentData(NULL), _treeScale(treeScale), _maxVoxels(maxVoxels) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _writeRenderFullVBO = true; _readRenderFullVBO = true; @@ -312,12 +314,11 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { } int VoxelSystem::newTreeToArrays(VoxelNode* node) { - assert(_viewFrustum); // you must set up _viewFrustum before calling this int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! if (node->isColored()) { - float distanceToNode = node->distanceToCamera(*_viewFrustum); + float distanceToNode = node->distanceToCamera(*Application::getInstance()->getViewFrustum()); float boundary = boundaryDistanceForRenderLevel(node->getLevel()); float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); bool inBoundary = (distanceToNode <= boundary); @@ -352,7 +353,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -382,7 +383,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -425,6 +426,9 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { return 0; // not-updated } +ProgramObject* VoxelSystem::_perlinModulateProgram = 0; +GLuint VoxelSystem::_permutationNormalTextureID = 0; + void VoxelSystem::init() { _renderWarningsOn = false; @@ -440,23 +444,23 @@ void VoxelSystem::init() { _unusedArraySpace = 0; // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_writeVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); - _readVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_readVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); + _writeVoxelDirtyArray = new bool[_maxVoxels]; + memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); + _readVoxelDirtyArray = new bool[_maxVoxels]; + memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels]; // populate the indicesArray // this will not change given new voxels, so we can set it all up now - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { // fill the indices array int voxelIndexOffset = n * INDICES_PER_VOXEL; GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; @@ -468,11 +472,11 @@ void VoxelSystem::init() { } } - GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; GLfloat* normalsArrayEndPointer = normalsArray; // populate the normalsArray - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { *(normalsArrayEndPointer++) = identityNormals[i]; } @@ -481,32 +485,35 @@ void VoxelSystem::init() { // VBO for the verticesArray glGenBuffers(1, &_vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the normalsArray glGenBuffers(1, &_vboNormalsID); glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); glBufferData(GL_ARRAY_BUFFER, - VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, + VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, normalsArray, GL_STATIC_DRAW); // VBO for colorsArray glGenBuffers(1, &_vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the indicesArray glGenBuffers(1, &_vboIndicesID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, - INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, + INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW); // delete the indices and normals arrays that are no longer needed delete[] indicesArray; delete[] normalsArray; - // create our simple fragment shader + // create our simple fragment shader if we're the first system to init + if (_perlinModulateProgram != 0) { + return; + } switchToResourcesParentIfRequired(); _perlinModulateProgram = new ProgramObject(); _perlinModulateProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); @@ -661,7 +668,7 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); + glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); @@ -855,7 +862,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { - ViewFrustum::location inFrustum = childNode->inFrustum(*thisVoxelSystem->_viewFrustum); + ViewFrustum::location inFrustum = childNode->inFrustum(*Application::getInstance()->getViewFrustum()); switch (inFrustum) { case ViewFrustum::OUTSIDE: { args->nodesOutside++; @@ -907,9 +914,9 @@ bool VoxelSystem::hasViewChanged() { } // If our viewFrustum has changed since our _lastKnowViewFrustum - if (_viewFrustum && !_lastStableViewFrustum.matches(_viewFrustum)) { + if (!_lastStableViewFrustum.matches(Application::getInstance()->getViewFrustum())) { result = true; - _lastStableViewFrustum = *_viewFrustum; // save last stable + _lastStableViewFrustum = *Application::getInstance()->getViewFrustum(); // save last stable } return result; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7bffb1d33c..de904bb64f 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -16,7 +16,6 @@ #include #include #include -#include "Avatar.h" #include "Camera.h" #include "Util.h" #include "world.h" @@ -27,7 +26,7 @@ const int NUM_CHILDREN = 8; class VoxelSystem : public AgentData { public: - VoxelSystem(); + VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM); ~VoxelSystem(); int parseData(unsigned char* sourceBuffer, int numBytes); @@ -41,8 +40,6 @@ public: unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; - void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; - void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); long int getVoxelsCreated(); @@ -114,8 +111,8 @@ private: static float _maxDistance; static float _minDistance; - Avatar* _viewerAvatar; - Camera* _camera; + float _treeScale; + int _maxVoxels; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -143,9 +140,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ProgramObject* _perlinModulateProgram; - GLuint _permutationNormalTextureID; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -158,6 +152,9 @@ private: bool _voxelsDirty; + static ProgramObject* _perlinModulateProgram; + static GLuint _permutationNormalTextureID; + public: void updateVBOs(); void updateFullVBOs(); // all voxels in the VBO From d98b28d4abdabe00b2b67fdd1023d258082dd868 Mon Sep 17 00:00:00 2001 From: Geenz Date: Fri, 31 May 2013 20:30:42 -0400 Subject: [PATCH 08/44] So apparently, this was a scale problem the entire time. --- interface/resources/shaders/SkyFromAtmosphere.frag | 2 +- interface/resources/shaders/SkyFromSpace.frag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index c7fedd4e4a..4f3bbff9b0 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -87,7 +87,7 @@ void main (void) float fHeight = length(v3SamplePoint); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight; - float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; + float fCameraAngle = dot(normalize(v3Ray), v3SamplePoint) / fHeight * 0.99; float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle))); vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI)); v3FrontColor += v3Attenuate * (fDepth * fScaledLength); diff --git a/interface/resources/shaders/SkyFromSpace.frag b/interface/resources/shaders/SkyFromSpace.frag index 2dcbc9d6fb..d4e1c58da5 100644 --- a/interface/resources/shaders/SkyFromSpace.frag +++ b/interface/resources/shaders/SkyFromSpace.frag @@ -97,7 +97,7 @@ void main (void) float fHeight = length(v3SamplePoint); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight; - float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight; + float fCameraAngle = dot(normalize(v3Ray), v3SamplePoint) / fHeight * 0.99; float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle))); vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI)); v3FrontColor += v3Attenuate * (fDepth * fScaledLength); From de76851207d07486b47919dd6aa3273a12057a09 Mon Sep 17 00:00:00 2001 From: Geenz Date: Fri, 31 May 2013 20:35:26 -0400 Subject: [PATCH 09/44] Remove unnecessary normalize. --- interface/resources/shaders/SkyFromAtmosphere.frag | 2 +- interface/resources/shaders/SkyFromSpace.frag | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index 4f3bbff9b0..b640f5f952 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -87,7 +87,7 @@ void main (void) float fHeight = length(v3SamplePoint); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight; - float fCameraAngle = dot(normalize(v3Ray), v3SamplePoint) / fHeight * 0.99; + float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99; float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle))); vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI)); v3FrontColor += v3Attenuate * (fDepth * fScaledLength); diff --git a/interface/resources/shaders/SkyFromSpace.frag b/interface/resources/shaders/SkyFromSpace.frag index d4e1c58da5..b1380d00be 100644 --- a/interface/resources/shaders/SkyFromSpace.frag +++ b/interface/resources/shaders/SkyFromSpace.frag @@ -97,7 +97,7 @@ void main (void) float fHeight = length(v3SamplePoint); float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight; - float fCameraAngle = dot(normalize(v3Ray), v3SamplePoint) / fHeight * 0.99; + float fCameraAngle = dot((v3Ray), v3SamplePoint) / fHeight * 0.99; float fScatter = (fStartOffset + fDepth * (scale(fLightAngle) - scale(fCameraAngle))); vec3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI)); v3FrontColor += v3Attenuate * (fDepth * fScaledLength); From 7425b392376223376c552c748b14aab906c91e07 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 17:55:30 -0700 Subject: [PATCH 10/44] Working on avatar voxel system. --- interface/src/Avatar.cpp | 9 +- interface/src/Avatar.h | 5 +- interface/src/AvatarVoxelSystem.cpp | 97 ++++++++++++++++++++ interface/src/AvatarVoxelSystem.h | 43 +++++++++ interface/src/VoxelSystem.cpp | 134 +++++++++++----------------- interface/src/VoxelSystem.h | 33 ++++--- 6 files changed, 216 insertions(+), 105 deletions(-) create mode 100644 interface/src/AvatarVoxelSystem.cpp create mode 100644 interface/src/AvatarVoxelSystem.h diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index cc30a011af..7198c0030c 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -57,9 +57,6 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; -const float AVATAR_TREE_SCALE = 1.0f; -const int MAX_VOXELS_PER_AVATAR = 2000; - bool usingBigSphereCollisionTest = true; float chatMessageScale = 0.0015; @@ -91,8 +88,7 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false), - _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) + _isMouseTurningRight(false) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -1153,7 +1149,8 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the body's voxels glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); + const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition; + glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z); glm::quat rotation = getOrientation(); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d1bc651eff..726ae972c2 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -13,13 +13,13 @@ #include #include "world.h" #include "AvatarTouch.h" +#include "AvatarVoxelSystem.h" #include "InterfaceConfig.h" #include "SerialInterface.h" #include "Balls.h" #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" -#include "VoxelSystem.h" enum DriveKeys { @@ -149,7 +149,8 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; - VoxelSystem _voxels; + + AvatarVoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp new file mode 100644 index 0000000000..79f3f113b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.cpp @@ -0,0 +1,97 @@ +// +// AvatarVoxelSystem.cpp +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include "AvatarVoxelSystem.h" + +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; + +AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +} + +AvatarVoxelSystem::~AvatarVoxelSystem() { + delete[] _readBoneIndicesArray; + delete[] _readBoneWeightsArray; + delete[] _writeBoneIndicesArray; + delete[] _writeBoneWeightsArray; +} + +void AvatarVoxelSystem::init() { + VoxelSystem::init(); + + // prep the data structures for incoming voxel data + _writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + + _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + + // VBO for the boneIndicesArray + glGenBuffers(1, &_vboBoneIndicesID); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // VBO for the boneWeightsArray + glGenBuffers(1, &_vboBoneWeightsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); +} + +void AvatarVoxelSystem::render(bool texture) { + VoxelSystem::render(texture); +} + +void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); + + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + *(writeBoneIndicesAt + j) = 0; + *(writeBoneWeightsAt + j) = 0.0f; + } +} + +void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); + + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); + + segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); +} + +void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); + + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); + + segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h new file mode 100644 index 0000000000..d129e046b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.h @@ -0,0 +1,43 @@ +// +// AvatarVoxelSystem.h +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__AvatarVoxelSystem__ +#define __interface__AvatarVoxelSystem__ + +#include "VoxelSystem.h" + +class AvatarVoxelSystem : public VoxelSystem { +public: + + AvatarVoxelSystem(); + virtual ~AvatarVoxelSystem(); + + virtual void init(); + virtual void render(bool texture); + +protected: + + virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color); + virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + +private: + + GLubyte* _readBoneIndicesArray; + GLfloat* _readBoneWeightsArray; + GLubyte* _writeBoneIndicesArray; + GLfloat* _writeBoneWeightsArray; + + GLuint _vboBoneIndicesID; + GLuint _vboBoneWeightsID; + + ProgramObject* _skinProgram; +}; + +#endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b4202511e6..7f5a926d28 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -231,10 +231,8 @@ void VoxelSystem::cleanupRemovedVoxels() { } void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { - int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); - int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); - memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); - memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); + copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); + _voxelsInReadArrays = _voxelsInWriteArrays; // clear our dirty flags @@ -261,47 +259,37 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + copyWrittenDataSegmentToReadArrays(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); } } } // if we got to the end of the array, and we're in an active dirty segment... if (inSegment) { - segmentEnd = _voxelsInWriteArrays - 1; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); + copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); } // update our length _voxelsInReadArrays = _voxelsInWriteArrays; } +void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); + + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); +} + void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); if (_voxelsDirty && _voxelsUpdated) { @@ -364,12 +352,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); node->setBufferIndex(nodeIndex); _writeVoxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode _voxelsInWriteArrays++; // our know vertices in the arrays @@ -415,17 +398,23 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); + return 1; // updated! } return 0; // not-updated } +void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + *(writeColorsAt +j) = color[j % 3]; + } +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -546,20 +535,7 @@ void VoxelSystem::init() { } void VoxelSystem::updateFullVBOs() { - glBufferIndex segmentStart = 0; - glBufferIndex segmentEnd = _voxelsInReadArrays; - - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + updateVBOSegment(0, _voxelsInReadArrays); // consider the _readVoxelDirtyArray[] clean! memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool)); @@ -581,39 +557,17 @@ void VoxelSystem::updatePartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + updateVBOSegment(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } _readVoxelDirtyArray[i] = false; // consider us clean! } } // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { - segmentEnd = _voxelsInReadArrays - 1; + if (inSegment) { + updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } } @@ -635,6 +589,20 @@ void VoxelSystem::updateVBOs() { _callsToTreesToArrays = 0; // clear it } +void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); +} + void VoxelSystem::render(bool texture) { PerformanceWarning warn(_renderWarningsOn, "render()"); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index de904bb64f..a7824d8326 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -31,11 +31,9 @@ public: int parseData(unsigned char* sourceBuffer, int numBytes); - void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }; - - void init(); + virtual void init(); void simulate(float deltaTime) { }; - void render(bool texture); + virtual void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -80,6 +78,16 @@ public: 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); + +protected: + + int _maxVoxels; + + virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color); + virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + private: // disallow copying of VoxelSystem objects VoxelSystem(const VoxelSystem&); @@ -107,12 +115,13 @@ private: void copyWrittenDataToReadArraysFullVBOs(); void copyWrittenDataToReadArraysPartialVBOs(); + void updateVBOs(); + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; static float _minDistance; - float _treeScale; - int _maxVoxels; + float _treeScale; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -121,8 +130,8 @@ private: bool* _writeVoxelDirtyArray; bool* _readVoxelDirtyArray; unsigned long _voxelsUpdated; - unsigned long _voxelsInWriteArrays; unsigned long _voxelsInReadArrays; + unsigned long _voxelsInWriteArrays; unsigned long _unusedArraySpace; bool _writeRenderFullVBO; @@ -140,7 +149,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -149,17 +157,14 @@ private: void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); + + void updateFullVBOs(); // all voxels in the VBO + void updatePartialVBOs(); // multiple segments, only dirty voxels bool _voxelsDirty; static ProgramObject* _perlinModulateProgram; static GLuint _permutationNormalTextureID; - -public: - void updateVBOs(); - void updateFullVBOs(); // all voxels in the VBO - void updatePartialVBOs(); // multiple segments, only dirty voxels - }; #endif From 6c975f9c6fe2a95a9225909de722721290637f2e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sat, 1 Jun 2013 15:06:29 -0700 Subject: [PATCH 11/44] More work on avatar voxels. --- interface/resources/shaders/skin_voxels.vert | 34 +++++++++++ interface/src/Avatar.cpp | 3 +- interface/src/AvatarVoxelSystem.cpp | 64 +++++++++++++++++--- interface/src/AvatarVoxelSystem.h | 13 +++- interface/src/VoxelSystem.cpp | 24 +++++--- interface/src/VoxelSystem.h | 2 + 6 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 interface/resources/shaders/skin_voxels.vert diff --git a/interface/resources/shaders/skin_voxels.vert b/interface/resources/shaders/skin_voxels.vert new file mode 100644 index 0000000000..c63b2e1b31 --- /dev/null +++ b/interface/resources/shaders/skin_voxels.vert @@ -0,0 +1,34 @@ +#version 120 + +// +// skin_voxels.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +const int MAX_BONES = 32; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 boneMatrices[MAX_BONES]; + +attribute vec4 boneIndices; +attribute vec4 boneWeights; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 normal = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 boneMatrix = boneMatrices[int(boneIndices[i])]; + float boneWeight = boneWeights[i]; + position += boneMatrix * gl_Vertex * boneWeight; + normal += boneMatrix * vec4(gl_Normal, 0.0) * boneWeight; + } + position = gl_ModelViewProjectionMatrix * position; + normal = normalize(gl_ModelViewMatrix * normal); + + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_Position = position; +} diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7198c0030c..6ee8cefb55 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -88,7 +88,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 79f3f113b9..dcea2816ec 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -8,13 +8,18 @@ #include #include "AvatarVoxelSystem.h" +#include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : + VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), + _avatar(avatar) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -24,6 +29,11 @@ AvatarVoxelSystem::~AvatarVoxelSystem() { delete[] _writeBoneWeightsArray; } +ProgramObject* AvatarVoxelSystem::_skinProgram = 0; +int AvatarVoxelSystem::_boneMatricesLocation; +int AvatarVoxelSystem::_boneIndicesLocation; +int AvatarVoxelSystem::_boneWeightsLocation; + void AvatarVoxelSystem::init() { VoxelSystem::init(); @@ -43,6 +53,18 @@ void AvatarVoxelSystem::init() { glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // load our skin program if this is the first avatar system to initialize + if (_skinProgram != 0) { + return; + } + _skinProgram = new ProgramObject(); + _skinProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_voxels.vert"); + _skinProgram->link(); + + _boneMatricesLocation = _skinProgram->uniformLocation("boneMatrices"); + _boneIndicesLocation = _skinProgram->attributeLocation("boneIndices"); + _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } void AvatarVoxelSystem::render(bool texture) { @@ -53,11 +75,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - *(writeBoneIndicesAt + j) = 0; - *(writeBoneWeightsAt + j) = 0.0f; + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + for (int i = 0; i < VERTICES_PER_VOXEL; i++) { + GLubyte boneIndices[] = { 0, 0, 0, 0}; + glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + } } } @@ -95,3 +121,25 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } +void AvatarVoxelSystem::bindProgram(bool texture) { + _skinProgram->bind(); + + QMatrix4x4 boneMatrices[1]; + + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneIndicesLocation); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneWeightsLocation); +} + +void AvatarVoxelSystem::releaseProgram(bool texture) { + _skinProgram->release(); + _skinProgram->disableAttributeArray(_boneIndicesLocation); + _skinProgram->disableAttributeArray(_boneWeightsLocation); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index d129e046b9..1b28a1a60d 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,10 +11,12 @@ #include "VoxelSystem.h" +class Avatar; + class AvatarVoxelSystem : public VoxelSystem { public: - AvatarVoxelSystem(); + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); @@ -26,9 +28,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: + Avatar* _avatar; + GLubyte* _readBoneIndicesArray; GLfloat* _readBoneWeightsArray; GLubyte* _writeBoneIndicesArray; @@ -37,7 +43,10 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; - ProgramObject* _skinProgram; + static ProgramObject* _skinProgram; + static int _boneMatricesLocation; + static int _boneIndicesLocation; + static int _boneWeightsLocation; }; #endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7f5a926d28..c2d3de8da1 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -625,10 +625,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - if (texture) { - _perlinModulateProgram->bind(); - glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); - } + bindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -643,10 +640,7 @@ void VoxelSystem::render(bool texture) { glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - if (texture) { - _perlinModulateProgram->release(); - glBindTexture(GL_TEXTURE_2D, 0); - } + releaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -663,6 +657,20 @@ void VoxelSystem::render(bool texture) { pthread_mutex_unlock(&_bufferWriteLock); } +void VoxelSystem::bindProgram(bool texture) { + if (texture) { + _perlinModulateProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + } +} + +void VoxelSystem::releaseProgram(bool texture) { + if (texture) { + _perlinModulateProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index a7824d8326..8c9337bbe5 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -87,6 +87,8 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: // disallow copying of VoxelSystem objects From 8d757e148fb5007b0f12a50c7e794fe78262ae52 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 2 Jun 2013 19:55:51 -0700 Subject: [PATCH 12/44] More work on voxeltars; basic skinning works. --- interface/src/Avatar.cpp | 19 ++-- interface/src/Avatar.h | 8 +- interface/src/AvatarVoxelSystem.cpp | 141 ++++++++++++++++++++-------- interface/src/AvatarVoxelSystem.h | 9 +- interface/src/Skeleton.cpp | 13 ++- interface/src/Skeleton.h | 11 ++- interface/src/VoxelSystem.cpp | 25 +++-- interface/src/VoxelSystem.h | 15 +-- 8 files changed, 168 insertions(+), 73 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 62de224e99..2250bda751 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -172,8 +172,6 @@ Avatar::~Avatar() { void Avatar::init() { _voxels.init(); - - _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); } void Avatar::reset() { @@ -953,8 +951,11 @@ void Avatar::updateBodyBalls(float deltaTime) { } */ - //update position by velocity... + // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; + + // update rotation + _bodyBall[b].rotation = _skeleton.joint[b].rotation; } } @@ -1016,14 +1017,7 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_TRANSLUCENT_BEYOND = 0.5f; // Render the body's voxels - glPushMatrix(); - const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition; - glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z); - glm::quat rotation = getOrientation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); _voxels.render(false); - glPopMatrix(); // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { @@ -1130,6 +1124,11 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } +void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const { + position = _bodyBall[jointID].position; + rotation = _bodyBall[jointID].rotation; +} + void Avatar::writeAvatarDataToFile() { Application::getInstance()->setSetting("avatarPos", _position); Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll)); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 4fff0bdc40..c7561d3986 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -66,7 +66,7 @@ public: void setOrientation (const glm::quat& orientation); //getters - + const Skeleton& getSkeleton () const { return _skeleton;} float getHeadYawRate () const { return _head.yawRate;} float getBodyYaw () const { return _bodyYaw;} bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} @@ -97,6 +97,9 @@ public: void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; + // Get the position/rotation of a single body ball + void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const; + //read/write avatar data void writeAvatarDataToFile(); void readAvatarDataFromFile(); @@ -108,7 +111,8 @@ private: struct AvatarBall { - glm::vec3 position; + glm::vec3 position; + glm::quat rotation; glm::vec3 velocity; float jointTightness; float radius; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index dcea2816ec..50c8ca8a71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,15 +7,15 @@ #include +#include + +#include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), @@ -38,21 +38,31 @@ void AvatarVoxelSystem::init() { VoxelSystem::init(); // prep the data structures for incoming voxel data - _writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; - _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; // VBO for the boneIndicesArray glGenBuffers(1, &_vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the boneWeightsArray glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + for (int i = 0; i < 150; i++) { + int power = pow(2, randIntInRange(6, 8)); + float size = 1.0f / power; + _tree->createVoxel( + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, size, 255, 0, 255, true); + } + setupNewVoxelsForDrawing(); // load our skin program if this is the first avatar system to initialize if (_skinProgram != 0) { @@ -75,14 +85,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); for (int i = 0; i < VERTICES_PER_VOXEL; i++) { - GLubyte boneIndices[] = { 0, 0, 0, 0}; - glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { - *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; - *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + BoneIndices boneIndices; + glm::vec4 boneWeights; + computeBoneIndicesAndWeights(computeVoxelVertex(startVertex, voxelScale, i), boneIndices, boneWeights); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; } } } @@ -91,16 +102,16 @@ void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segment VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); } @@ -108,38 +119,94 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } -void AvatarVoxelSystem::bindProgram(bool texture) { +void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { _skinProgram->bind(); - QMatrix4x4 boneMatrices[1]; + // the base matrix includes centering and scale + QMatrix4x4 baseMatrix; + baseMatrix.scale(_treeScale); + baseMatrix.translate(-0.5f, -0.5f, -0.5f); - _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + // bone matrices include joint transforms + QMatrix4x4 boneMatrices[NUM_AVATAR_JOINTS]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + glm::vec3 position; + glm::quat orientation; + _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); + boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); + const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition; + boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z); + boneMatrices[i] *= baseMatrix; + } + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + glVertexAttribPointer(_boneIndicesLocation, BONE_ELEMENTS_PER_VERTEX, GL_UNSIGNED_BYTE, false, 0, 0); _skinProgram->enableAttributeArray(_boneIndicesLocation); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_ELEMENTS_PER_VERTEX); _skinProgram->enableAttributeArray(_boneWeightsLocation); } -void AvatarVoxelSystem::releaseProgram(bool texture) { +void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->release(); _skinProgram->disableAttributeArray(_boneIndicesLocation); _skinProgram->disableAttributeArray(_boneWeightsLocation); } +class IndexDistance { +public: + IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + + GLubyte index; + float distance; +}; + +void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const { + // transform into joint space + glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE; + + // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) + IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + if (distance < nearest[j].distance) { + // move the rest of the indices down + for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) { + nearest[k] = nearest[k - 1]; + } + nearest[j] = IndexDistance(i, distance); + break; + } + } + } + + // compute the weights based on inverse distance + float totalWeight = 0.0f; + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + indices[i] = nearest[i].index; + weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + } + + // normalize the weights + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + weights[i] /= totalWeight; + } +} diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index 1b28a1a60d..e3a80c3817 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,6 +11,9 @@ #include "VoxelSystem.h" +const int BONE_ELEMENTS_PER_VERTEX = 4; +typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; + class Avatar; class AvatarVoxelSystem : public VoxelSystem { @@ -28,11 +31,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: + void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const; + Avatar* _avatar; GLubyte* _readBoneIndicesArray; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 64a8645247..ae31810d8e 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,7 +18,7 @@ void Skeleton::initialize() { joint[b].parent = AVATAR_JOINT_NULL; joint[b].position = glm::vec3(0.0, 0.0, 0.0); joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); - joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f); + joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; } @@ -77,9 +77,18 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); - // calculate bone length + // calculate bone length, absolute positions for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { joint[b].length = glm::length(joint[b].defaultPosePosition); + + if (joint[b].parent == AVATAR_JOINT_NULL) { + joint[b].absoluteDefaultPosePosition = glm::vec3(0.0f, 0.0f, 0.0f); + } else { + joint[b].absoluteDefaultPosePosition = joint[ joint[b].parent ].absoluteDefaultPosePosition; + } + + glm::vec3 rotatedJointVector = joint[b].defaultPosePosition; + joint[b].absoluteDefaultPosePosition += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 4c1152728d..5602dfc136 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -58,11 +58,12 @@ public: struct AvatarJoint { - AvatarJointID parent; // which joint is this joint connected to? - glm::vec3 position; // the position at the "end" of the joint - in global space - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion - float length; // the length of vector connecting the joint and its parent + AvatarJointID parent; // which joint is this joint connected to? + glm::vec3 position; // the position at the "end" of the joint - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 absoluteDefaultPosePosition; // the absolute position when the avatar is in the "T-pose" + glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion + float length; // the length of vector connecting the joint and its parent }; AvatarJoint joint[ NUM_AVATAR_JOINTS ]; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index c2d3de8da1..dc2e06506f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -415,6 +415,11 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s } } +glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const { + const float* identityVertex = identityVertices + index * 3; + return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -609,8 +614,8 @@ void VoxelSystem::render(bool texture) { // get the lock so that the update thread won't change anything pthread_mutex_lock(&_bufferWriteLock); - glPushMatrix(); updateVBOs(); + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -625,7 +630,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - bindProgram(texture); + applyScaleAndBindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -633,14 +638,13 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - releaseProgram(texture); + removeScaleAndReleaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -650,21 +654,24 @@ void VoxelSystem::render(bool texture) { // bind with 0 to switch back to normal operation glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - // scale back down to 1 so heads aren't massive - glPopMatrix(); pthread_mutex_unlock(&_bufferWriteLock); } -void VoxelSystem::bindProgram(bool texture) { +void VoxelSystem::applyScaleAndBindProgram(bool texture) { + glPushMatrix(); + glScalef(_treeScale, _treeScale, _treeScale); + if (texture) { _perlinModulateProgram->bind(); glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); } } -void VoxelSystem::releaseProgram(bool texture) { +void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { + // scale back down to 1 so heads aren't massive + glPopMatrix(); + if (texture) { _perlinModulateProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 8c9337bbe5..3a46e19517 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -81,14 +81,20 @@ public: protected: - int _maxVoxels; + float _treeScale; + int _maxVoxels; + VoxelTree* _tree; + + glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const; + + void setupNewVoxelsForDrawing(); virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: // disallow copying of VoxelSystem objects @@ -123,8 +129,6 @@ private: static float _maxDistance; static float _minDistance; - float _treeScale; - VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; GLfloat* _writeVerticesArray; @@ -157,7 +161,6 @@ private: int newTreeToArrays(VoxelNode *currentNode); void cleanupRemovedVoxels(); - void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); void updateFullVBOs(); // all voxels in the VBO From 9e046b74e67b457fdae56b7fb7bf238574145d47 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 08:09:27 -0700 Subject: [PATCH 13/44] working on avatar touch --- interface/src/Application.cpp | 39 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe84ec4748..e0e5ea8046 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,6 +50,8 @@ using namespace std; +const bool TESTING_AVATAR_TOUCH = false; + // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; @@ -1078,24 +1080,31 @@ void Application::idle() { _myAvatar.simulate(deltaTime, NULL); } - if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { - if (_manualFirstPerson) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { - - if (_myAvatar.getIsNearInteractingOther()) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { + if (TESTING_AVATAR_TOUCH) { + if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1.0f); + } + } else { + if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { + if (_manualFirstPerson) { + if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } - else { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); + } else { + + if (_myAvatar.getIsNearInteractingOther()) { + if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); + } + } + else { + if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1.0f); + } } } } From cf67f28b57eb4c7eda9f3f4c9a6c8c45ac637337 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 08:10:41 -0700 Subject: [PATCH 14/44] merge --- .../resources/shaders/SkyFromAtmosphere.frag | 212 +++++++++--------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index b640f5f952..dbefc8270e 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -1,106 +1,106 @@ -#version 120 - -// -// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: -// -// NVIDIA Statement on the Software -// -// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are -// detailed. -// -// No Warranty -// -// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL -// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -// Limitation of Liability -// -// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR -// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT -// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY -// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH -// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. -// - -// -// Atmospheric scattering fragment shader -// -// Author: Sean O'Neil -// -// Copyright (c) 2004 Sean O'Neil -// - -uniform vec3 v3CameraPos; // The camera's current position -uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels -uniform float fInnerRadius; // The inner (planetary) radius -uniform float fKrESun; // Kr * ESun -uniform float fKmESun; // Km * ESun -uniform float fKr4PI; // Kr * 4 * PI -uniform float fKm4PI; // Km * 4 * PI -uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) -uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) -uniform float fScaleOverScaleDepth; // fScale / fScaleDepth - -const int nSamples = 2; -const float fSamples = 2.0; - -uniform vec3 v3LightPos; -uniform float g; -uniform float g2; - -varying vec3 position; - -float scale(float fCos) -{ - float x = 1.0 - fCos; - return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); -} - -void main (void) -{ - // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) - vec3 v3Pos = position; - vec3 v3Ray = v3Pos - v3CameraPos; - float fFar = length(v3Ray); - v3Ray /= fFar; - - // Calculate the ray's starting position, then calculate its scattering offset - vec3 v3Start = v3CameraPos; - float fHeight = length(v3Start); - float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); - float fStartAngle = dot(v3Ray, v3Start) / fHeight; - float fStartOffset = fDepth * scale(fStartAngle); - - // Initialize the scattering loop variables - //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); - float fSampleLength = fFar / fSamples; - float fScaledLength = fSampleLength * fScale; - vec3 v3SampleRay = v3Ray * fSampleLength; - vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; - - // Now loop through the sample rays - vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); - for(int i=0; i Date: Mon, 3 Jun 2013 10:08:42 -0700 Subject: [PATCH 15/44] Slight fix to capsule/box penetration test: we should use the smaller distance to the diagonal, not the first one we find. --- interface/src/AvatarVoxelSystem.cpp | 4 +--- libraries/voxels/src/AABox.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 50c8ca8a71..d6b51bec82 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,8 +7,6 @@ #include -#include - #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -201,7 +199,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float totalWeight = 0.0f; for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { indices[i] = nearest[i].index; - weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON); + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); totalWeight += weights[i]; } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index b7580b243e..1b29c70b59 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -292,13 +292,16 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, secondAxisMaxPlane + thirdAxisMaxPlane + offset }; + float minDistance = FLT_MAX; for (int i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { float divisor = glm::dot(direction, diagonals[i]); if (fabs(divisor) < EPSILON) { continue; // segment is parallel to diagonal plane } - float directionalDistance = -glm::dot(origin, diagonals[i]) / divisor; - return getClosestPointOnFace(glm::vec3(origin + direction * directionalDistance), face); + minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); + } + if (minDistance != FLT_MAX) { + return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); } } From 7dd217b3182eb6df44439d53c60a0accbd25c821 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 10:57:18 -0700 Subject: [PATCH 16/44] more work on copy and paste --- interface/src/Application.cpp | 79 +++++++++++++++++++------------ libraries/shared/src/SharedUtil.h | 2 +- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5395bfa54f..30f4d958a2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1002,7 +1002,7 @@ void Application::idle() { _mouseVoxel.z += faceVector.z * _mouseVoxel.s; } } - } else if (_addVoxelMode->isChecked()) { + } else if (_addVoxelMode->isChecked() || _selectVoxelMode->isChecked()) { // place the voxel a fixed distance away float worldMouseVoxelScale = _mouseVoxelScale * TREE_SCALE; glm::vec3 pt = mouseRayOrigin + mouseRayDirection * (2.0f + worldMouseVoxelScale * 0.5f); @@ -1318,11 +1318,16 @@ void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + // clear the clipboard first... + _clipboardTree.eraseAllVoxels(); + + // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); // debug tree - _clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); + //_clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } @@ -1335,25 +1340,37 @@ struct SendVoxelsOperataionArgs { }; void Application::pasteVoxels() { + unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // 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 + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + + // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // voxel size/position details. if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - - // 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 - SendVoxelsOperataionArgs args; - args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; - unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; - *sequenceAt = 0; - args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence args.newBaseOctCode = selectedNode->getOctalCode(); - _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); - - // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { - AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); - } + } else { + printf("pasteVoxels() no voxel at current location, calculate octCode... \n"); + args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } + + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); + + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + } + + if (calculatedOctCode) { + delete calculatedOctCode; } } @@ -1449,33 +1466,35 @@ void Application::initMenu() { QMenu* voxelMenu = menuBar->addMenu("Voxels"); _voxelModeActions = new QActionGroup(this); _voxelModeActions->setExclusive(false); // exclusivity implies one is always checked + (_addVoxelMode = voxelMenu->addAction( - "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_A))->setCheckable(true); + "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_A))->setCheckable(true); _voxelModeActions->addAction(_addVoxelMode); (_deleteVoxelMode = voxelMenu->addAction( - "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_D))->setCheckable(true); + "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_D))->setCheckable(true); _voxelModeActions->addAction(_deleteVoxelMode); (_colorVoxelMode = voxelMenu->addAction( - "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_C))->setCheckable(true); + "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_B))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); (_selectVoxelMode = voxelMenu->addAction( - "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_S))->setCheckable(true); + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); - voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::SHIFT | Qt::Key_P); - voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Minus); - voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Plus); + voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn); - _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), - Qt::CTRL | Qt::SHIFT | Qt::Key_C); + _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, + SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); - voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); - voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); - voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); - voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); + + voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); + voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); + voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8da9d7beca..6c48c9e42e 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -70,7 +70,7 @@ struct VoxelDetail { unsigned char blue; }; -unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b ); +unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r = 0, unsigned char g = 0, unsigned char b = 0); bool createVoxelEditMessage(unsigned char command, short int sequence, int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut); From 8d031b5c2d4a075fbe039bf708163437544c6de7 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 11:53:00 -0700 Subject: [PATCH 17/44] preparation for extending the avatar ball array to accommodate more touch capabilities --- interface/src/Application.cpp | 10 +++--- interface/src/Audio.cpp | 2 +- interface/src/Avatar.cpp | 43 +++++++++++----------- interface/src/Avatar.h | 68 ++++++++++++++++++++++++----------- interface/src/Skeleton.h | 4 +-- 5 files changed, 77 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e0e5ea8046..130bd5e7fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -289,22 +289,22 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); } else if (OculusManager::isConnected()) { _myCamera.setUpShift (0.0f); _myCamera.setDistance (0.0f); _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); _myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); } @@ -1556,7 +1556,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { if (_cameraFrustum->isChecked()) { position = camera.getPosition(); } else { - position = _myAvatar.getHeadPosition(); + position = _myAvatar.getHeadJointPosition(); } float fov = camera.getFieldOfView(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 97929a99ca..3f5068a577 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -143,7 +143,7 @@ int audioCallback (const void* inputBuffer, unsigned char *currentPacketPtr = dataPacket + 1; // memcpy the three float positions - memcpy(currentPacketPtr, &interfaceAvatar->getHeadPosition(), sizeof(float) * 3); + memcpy(currentPacketPtr, &interfaceAvatar->getHeadJointPosition(), sizeof(float) * 3); currentPacketPtr += (sizeof(float) * 3); // tell the mixer not to add additional attenuation to our source diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 46a4d302ca..c02a6ccaa7 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -118,16 +118,18 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { - for (int b=0; b 0.0) { glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bodyBall[b].velocity += collisionForce * 0.0f * deltaTime; - _velocity += collisionForce * 40.0f * deltaTime; + + _velocity += collisionForce * 40.0f * deltaTime; _bodyBall[b].position = position + directionVector * combinedRadius; } } @@ -760,11 +759,11 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); - // loop through the joints of each avatar to check for every possible collision - for (int b=1; b_bodyBall[o].isCollidable) { glm::vec3 vectorBetweenJoints(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); @@ -893,8 +892,8 @@ void Avatar::render(bool lookingInMirror) { } void Avatar::resetBodyBalls() { - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - _bodyBall[b].position = _skeleton.joint[b].position; + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + _bodyBall[b].position = _skeleton.joint[b].position; // put balls on joints _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } } @@ -905,7 +904,7 @@ void Avatar::updateBodyBalls(float deltaTime) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 springVector(_bodyBall[b].position); if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL) { @@ -942,8 +941,8 @@ void Avatar::updateBodyBalls(float deltaTime) { /* //apply forces from touch... - if (_skeleton.joint[b].touchForce > 0.0) { - _skeleton.joint[b].springyVelocity += _mouseRayDirection * _skeleton.joint[b].touchForce * 0.7f; + if (_bodyBall[b].touchForce > 0.0) { + _bodyBall[b].velocity += _mouseRayDirection * _bodyBall[b].touchForce * 0.7f; } */ @@ -1010,8 +1009,8 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_TRANSLUCENT_BEYOND = 0.5f; // Render the body as balls and cones - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - float distanceToCamera = glm::length(_cameraPosition - _skeleton.joint[b].position); + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + float distanceToCamera = glm::length(_cameraPosition - _bodyBall[b].position); float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); @@ -1029,7 +1028,7 @@ void Avatar::renderBody(bool lookingInMirror) { || b == AVATAR_JOINT_RIGHT_ELBOW || b == AVATAR_JOINT_RIGHT_WRIST || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { - // Render the sphere at the joint + // Render the body ball sphere if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW || b == AVATAR_JOINT_RIGHT_WRIST || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { @@ -1051,7 +1050,7 @@ void Avatar::renderBody(bool lookingInMirror) { glPopMatrix(); } - // Render the cone connecting this joint to its parent + // Render the cone connecting this ball to its parent if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { if ((b != AVATAR_JOINT_HEAD_TOP ) && (b != AVATAR_JOINT_HEAD_BASE ) diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 6746ba51cd..c1303287be 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -20,6 +20,37 @@ #include "Skeleton.h" #include "Transmitter.h" + +enum AvatarBodyBallID +{ + BODY_BALL_NULL = -1, + BODY_BALL_PELVIS, + BODY_BALL_TORSO, + BODY_BALL_CHEST, + BODY_BALL_NECK_BASE, + BODY_BALL_HEAD_BASE, + BODY_BALL_HEAD_TOP, + BODY_BALL_LEFT_COLLAR, + BODY_BALL_LEFT_SHOULDER, + BODY_BALL_LEFT_ELBOW, + BODY_BALL_LEFT_WRIST, + BODY_BALL_LEFT_FINGERTIPS, + BODY_BALL_RIGHT_COLLAR, + BODY_BALL_RIGHT_SHOULDER, + BODY_BALL_RIGHT_ELBOW, + BODY_BALL_RIGHT_WRIST, + BODY_BALL_RIGHT_FINGERTIPS, + BODY_BALL_LEFT_HIP, + BODY_BALL_LEFT_KNEE, + BODY_BALL_LEFT_HEEL, + BODY_BALL_LEFT_TOES, + BODY_BALL_RIGHT_HIP, + BODY_BALL_RIGHT_KNEE, + BODY_BALL_RIGHT_HEEL, + BODY_BALL_RIGHT_TOES, + NUM_AVATAR_BODY_BALLS +}; + enum DriveKeys { FWD = 0, @@ -64,19 +95,14 @@ public: void setOrientation (const glm::quat& orientation); //getters - - float getHeadYawRate () const { return _head.yawRate;} - float getBodyYaw () const { return _bodyYaw;} - bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} - const glm::vec3& getHeadPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} - const glm::vec3& getSpringyHeadPosition () const { return _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position;} - const glm::vec3& getJointPosition (AvatarJointID j) const { return _bodyBall[j].position;} - - glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } - glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } - glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } - - + float getHeadYawRate () const { return _head.yawRate;} + float getBodyYaw () const { return _bodyYaw;} + bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();} + const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} + const glm::vec3& getBallPosition (AvatarJointID j) const { return _bodyBall[j].position;} + glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } + glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } + glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } const glm::vec3& getVelocity () const { return _velocity;} float getSpeed () const { return _speed;} float getHeight () const { return _height;} @@ -106,12 +132,14 @@ private: struct AvatarBall { - glm::vec3 position; - glm::vec3 velocity; - float jointTightness; - float radius; - bool isCollidable; - float touchForce; + AvatarJointID parent; + glm::vec3 parentOffset; + glm::vec3 position; + glm::vec3 velocity; + float jointTightness; + float radius; + bool isCollidable; + float touchForce; }; Head _head; @@ -124,7 +152,7 @@ private: float _bodyRollDelta; glm::vec3 _movedHandOffset; glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion - AvatarBall _bodyBall[ NUM_AVATAR_JOINTS ]; + AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; glm::vec3 _cameraPosition; glm::vec3 _handHoldingPosition; diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 4c1152728d..28d3a6e81e 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -60,9 +60,9 @@ public: { AvatarJointID parent; // which joint is this joint connected to? glm::vec3 position; // the position at the "end" of the joint - in global space - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the default pose glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion - float length; // the length of vector connecting the joint and its parent + float length; // the length of vector between the joint and its parent }; AvatarJoint joint[ NUM_AVATAR_JOINTS ]; From 00dce6b59e0ae18125e75d346b6f922d87370d36 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 12:01:01 -0700 Subject: [PATCH 18/44] fix --- interface/src/Avatar.cpp | 2 +- interface/src/Avatar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index c02a6ccaa7..6d2f0eefad 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -119,7 +119,7 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { for (int b=0; b Date: Mon, 3 Jun 2013 12:10:18 -0700 Subject: [PATCH 19/44] don't attempt to send microphone audio if AgentList is NULL --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 97929a99ca..995cb12a7f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -116,7 +116,7 @@ int audioCallback (const void* inputBuffer, printLog("got output\n"); } - if (inputLeft) { + if (agentList && inputLeft) { // Measure the loudness of the signal from the microphone and store in audio object float loudness = 0; From 78fe89172ac221ad59e8bfab4c478234c5a62c0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 12:23:16 -0700 Subject: [PATCH 20/44] eyedropper mode, and import work --- interface/src/Application.cpp | 150 ++++++++++++++++++-------- interface/src/Application.h | 3 +- libraries/voxels/src/VoxelConstants.h | 9 +- 3 files changed, 115 insertions(+), 47 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30f4d958a2..ab335dce97 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1285,6 +1285,58 @@ void Application::chooseVoxelPaintColor() { _window->activateWindow(); } +const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; +struct SendVoxelsOperataionArgs { + unsigned char* newBaseOctCode; + unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; + int bufferInUse; + +}; + +bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { + SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; + if (node->isColored()) { + unsigned char* nodeOctalCode = node->getOctalCode(); + printOctalCode(nodeOctalCode); + + unsigned char* codeColorBuffer = NULL; + int codeLength = 0; + int bytesInCode = 0; + int codeAndColorLength; + + // If the newBase is NULL, then don't rebase + if (args->newBaseOctCode) { + codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); + printOctalCode(codeColorBuffer); + codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + } else { + codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + codeColorBuffer = new unsigned char[codeAndColorLength]; + memcpy(codeColorBuffer, nodeOctalCode, bytesInCode); + } + + // copy the colors over + codeColorBuffer[bytesInCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; + codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; + codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; + + // if we have room don't have room in the buffer, then send the previously generated message first + if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + } + + // copy this node's code color details into our buffer. + memcpy(&args->messageBuffer[args->bufferInUse], codeColorBuffer, codeAndColorLength); + args->bufferInUse += codeAndColorLength; + } + return true; // keep going +} + void Application::exportVoxels() { QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", tr("High Fidelity Voxel Files (*.hio2)")); @@ -1303,15 +1355,45 @@ void Application::importVoxels() { QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); + + // Read the file into a tree + VoxelTree importVoxels; + importVoxels.readFromFileV2(fileName); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // Recurse the Import Voxels 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 + unsigned char* calculatedOctCode = NULL; + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + + // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // voxel size/position details. if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + args.newBaseOctCode = NULL; // selectedNode->getOctalCode(); + } else { + printf("importVoxels() no voxel at current location, calculate octCode... \n"); + args.newBaseOctCode = NULL; // = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } + + importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); + + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } - // not yet supported!!! - _voxels.readFromFileV2(fileName,selectedNode); + if (calculatedOctCode) { + delete calculatedOctCode; + } + } void Application::copyVoxels() { @@ -1331,14 +1413,6 @@ void Application::copyVoxels() { } } -const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; -struct SendVoxelsOperataionArgs { - unsigned char* newBaseOctCode; - unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; - int bufferInUse; - -}; - void Application::pasteVoxels() { unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1374,40 +1448,6 @@ void Application::pasteVoxels() { } } -bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { - SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; - if (node->isColored()) { - const int SIZE_OF_COLOR_DATA = 3; - const int RED_INDEX = 0; - const int GREEN_INDEX = 1; - const int BLUE_INDEX = 2; - unsigned char* nodeOctalCode = node->getOctalCode(); - printOctalCode(nodeOctalCode); - unsigned char* rebasedCodeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); - printOctalCode(rebasedCodeColorBuffer); - int rebasedCodeLength = numberOfThreeBitSectionsInCode(rebasedCodeColorBuffer); - int bytesInRebasedCode = bytesRequiredForCodeLength(rebasedCodeLength); - int codeAndColorLength = bytesInRebasedCode + SIZE_OF_COLOR_DATA; - - // copy the colors over - rebasedCodeColorBuffer[bytesInRebasedCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; - rebasedCodeColorBuffer[bytesInRebasedCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; - rebasedCodeColorBuffer[bytesInRebasedCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; - - // if we have room don't have room in the buffer, then send the previously generated message first - if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { - AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); - args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence - } - - // copy this node's code color details into our buffer. - memcpy(&args->messageBuffer[args->bufferInUse], rebasedCodeColorBuffer, codeAndColorLength); - args->bufferInUse += codeAndColorLength; - } - return true; // keep going -} - - void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); _window->setMenuBar(menuBar); @@ -1479,6 +1519,9 @@ void Application::initMenu() { (_selectVoxelMode = voxelMenu->addAction( "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); + (_eyedropperMode = voxelMenu->addAction( + "Eyedropper Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_E))->setCheckable(true); + _voxelModeActions->addAction(_eyedropperMode); voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); @@ -1486,6 +1529,7 @@ void Application::initMenu() { _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); + voxelMenu->addAction("Use Voxel Color", this, SLOT(useVoxelPaintColor()), Qt::CTRL | Qt::Key_U); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); @@ -2359,6 +2403,8 @@ void Application::maybeEditVoxelUnderCursor() { } } else if (_deleteVoxelMode->isChecked()) { deleteVoxelUnderCursor(); + } else if (_eyedropperMode->isChecked()) { + eyedropperVoxelUnderCursor(); } } @@ -2383,6 +2429,20 @@ void Application::deleteVoxelUnderCursor() { _justEditedVoxel = true; } +void Application::eyedropperVoxelUnderCursor() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode && selectedNode->isColored()) { + QColor selectedColor(selectedNode->getColor()[RED_INDEX], + selectedNode->getColor()[GREEN_INDEX], + selectedNode->getColor()[BLUE_INDEX]); + + if (selectedColor.isValid()) { + _voxelPaintColor->setData(selectedColor); + _voxelPaintColor->setIcon(createSwatchIcon(selectedColor)); + } + } +} + void Application::goHome() { _myAvatar.setPosition(START_LOCATION); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 7761d9a84b..ee48307910 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -182,7 +182,7 @@ private: void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); void deleteVoxelUnderCursor(); - + void eyedropperVoxelUnderCursor(); void goHome(); void resetSensors(); @@ -225,6 +225,7 @@ private: QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled QAction* _colorVoxelMode; // Whether color voxel mode is enabled QAction* _selectVoxelMode; // Whether select voxel mode is enabled + QAction* _eyedropperMode; // Whether voxel color eyedropper mode is enabled QAction* _voxelPaintColor; // The color with which to paint voxels QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 156a310476..b18315402a 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -23,11 +23,18 @@ const int MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; -const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL; + +const int NUMBER_OF_COLORS = 3; // RGB! +const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes +const int RED_INDEX = 0; +const int GREEN_INDEX = 1; +const int BLUE_INDEX = 2; +const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; typedef unsigned long int glBufferIndex; const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; const double SIXTY_FPS_IN_MILLISECONDS = 1000.0/60; const double VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0; // once a second is fine + #endif From 6479a41206cb073ad11e7fd1e4e3693d13523af3 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 12:26:20 -0700 Subject: [PATCH 21/44] more ball prep --- interface/src/Avatar.cpp | 168 ++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 71 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 6d2f0eefad..4fb2846a0f 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -101,10 +101,10 @@ Avatar::Avatar(Agent* owningAgent) : initializeBodyBalls(); - _height = _skeleton.getHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius + _bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius; + _height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius; _maxArmLength = _skeleton.getArmLength(); - _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius; - _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius; + _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; + _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; _avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS); @@ -128,41 +128,67 @@ void Avatar::initializeBodyBalls() { _bodyBall[b].isCollidable = true; _bodyBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS; } + + // specify the parent joint of each ball + _bodyBall[ BODY_BALL_PELVIS ].radius = 0.07; + _bodyBall[ BODY_BALL_TORSO ].radius = 0.065; + _bodyBall[ BODY_BALL_CHEST ].radius = 0.08; + _bodyBall[ BODY_BALL_NECK_BASE ].radius = 0.03; + _bodyBall[ BODY_BALL_HEAD_BASE ].radius = 0.07; - // specify the radii of the balls - _bodyBall[ AVATAR_JOINT_PELVIS ].radius = 0.07; - _bodyBall[ AVATAR_JOINT_TORSO ].radius = 0.065; - _bodyBall[ AVATAR_JOINT_CHEST ].radius = 0.08; - _bodyBall[ AVATAR_JOINT_NECK_BASE ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].radius = 0.04; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].radius = 0.03; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].radius = 0.02; + _bodyBall[ BODY_BALL_LEFT_WRIST ].radius = 0.02; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].radius = 0.01; - _bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].radius = 0.04; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].radius = 0.03; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].radius = 0.02; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].radius = 0.02; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].radius = 0.01; - _bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01; + _bodyBall[ BODY_BALL_LEFT_HIP ].radius = 0.04; + _bodyBall[ BODY_BALL_LEFT_KNEE ].radius = 0.025; + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius = 0.025; + _bodyBall[ BODY_BALL_LEFT_TOES ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_TOES ].radius = 0.025; - - _bodyBall[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_HIP ].radius = 0.04; + _bodyBall[ BODY_BALL_RIGHT_KNEE ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_HEEL ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_TOES ].radius = 0.025; + // specify the parent joint for each ball + _bodyBall[ BODY_BALL_PELVIS ].parentJoint = AVATAR_JOINT_NULL; + _bodyBall[ BODY_BALL_TORSO ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_CHEST ].parentJoint = AVATAR_JOINT_TORSO; + _bodyBall[ BODY_BALL_NECK_BASE ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_HEAD_BASE ].parentJoint = AVATAR_JOINT_NECK_BASE; + _bodyBall[ BODY_BALL_HEAD_TOP ].parentJoint = AVATAR_JOINT_HEAD_BASE; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].parentJoint = AVATAR_JOINT_LEFT_COLLAR; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].parentJoint = AVATAR_JOINT_LEFT_SHOULDER; + _bodyBall[ BODY_BALL_LEFT_WRIST ].parentJoint = AVATAR_JOINT_LEFT_ELBOW; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].parentJoint = AVATAR_JOINT_LEFT_WRIST; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].parentJoint = AVATAR_JOINT_RIGHT_COLLAR; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].parentJoint = AVATAR_JOINT_RIGHT_SHOULDER; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].parentJoint = AVATAR_JOINT_RIGHT_ELBOW; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].parentJoint = AVATAR_JOINT_RIGHT_WRIST; + _bodyBall[ BODY_BALL_LEFT_HIP ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_LEFT_KNEE ].parentJoint = AVATAR_JOINT_LEFT_HIP; + _bodyBall[ BODY_BALL_LEFT_HEEL ].parentJoint = AVATAR_JOINT_LEFT_KNEE; + _bodyBall[ BODY_BALL_LEFT_TOES ].parentJoint = AVATAR_JOINT_LEFT_HEEL; + _bodyBall[ BODY_BALL_RIGHT_HIP ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_RIGHT_KNEE ].parentJoint = AVATAR_JOINT_RIGHT_HIP; + _bodyBall[ BODY_BALL_RIGHT_HEEL ].parentJoint = AVATAR_JOINT_RIGHT_KNEE; + _bodyBall[ BODY_BALL_RIGHT_TOES ].parentJoint = AVATAR_JOINT_RIGHT_HEEL; + /* // to aid in hand-shaking and hand-holding, the right hand is not collidable - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].isCollidable = false; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].isCollidable = false; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS].isCollidable = false; */ } @@ -458,22 +484,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { right * _head.getLeanSideways() + front * _head.getLeanForward(); - _bodyBall[ AVATAR_JOINT_TORSO ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_CHEST ].position += headLean * 0.4f; - _bodyBall[ AVATAR_JOINT_NECK_BASE ].position += headLean * 0.7f; - _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position += headLean * 1.0f; + _bodyBall[ BODY_BALL_TORSO ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_CHEST ].position += headLean * 0.4f; + _bodyBall[ BODY_BALL_NECK_BASE ].position += headLean * 0.7f; + _bodyBall[ BODY_BALL_HEAD_BASE ].position += headLean * 1.0f; - _bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ AVATAR_JOINT_LEFT_WRIST ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_LEFT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].position += headLean * 0.0f; - _bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position += headLean * 0.0f; } } @@ -487,8 +513,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); - _head.setPosition(_bodyBall[ AVATAR_JOINT_HEAD_BASE ].position); - _head.setScale (_bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius); + _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); + _head.setScale (_bodyBall[ BODY_BALL_HEAD_BASE ].radius); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.simulate(deltaTime, !_owningAgent); @@ -581,7 +607,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { _avatarTouch.setHasInteractingOther(true); _avatarTouch.setYourBodyPosition(_interactingOther->_position); - _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); _avatarTouch.setYourOrientation (_interactingOther->getOrientation()); _avatarTouch.setYourHandState (_interactingOther->_handState); @@ -652,7 +678,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { } _avatarTouch.setMyHandState(_handState); - _avatarTouch.setMyHandPosition(_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setMyHandPosition(_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); } } @@ -856,7 +882,7 @@ void Avatar::render(bool lookingInMirror) { } glPushMatrix(); - glm::vec3 chatPosition = _bodyBall[AVATAR_JOINT_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight; + glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight; glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::vec3 chatAxis = glm::axis(chatRotation); @@ -901,13 +927,13 @@ void Avatar::resetBodyBalls() { void Avatar::updateBodyBalls(float deltaTime) { // Check for a large repositioning, and re-initialize balls if this has happened const float BEYOND_BODY_SPRING_RANGE = 2.f; - if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { + if (glm::length(_position - _bodyBall[BODY_BALL_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 springVector(_bodyBall[b].position); - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL) { + if (b == BODY_BALL_PELVIS) { springVector -= _position; } else { @@ -1020,18 +1046,18 @@ void Avatar::renderBody(bool lookingInMirror) { } // Always render other people, and render myself when beyond threshold distance - if (b == AVATAR_JOINT_HEAD_BASE) { // the head is rendered as a special + if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special if (lookingInMirror || _owningAgent || distanceToCamera > RENDER_OPAQUE_BEYOND * 0.5) { _head.render(lookingInMirror, _cameraPosition, alpha); } } else if (_owningAgent || distanceToCamera > RENDER_TRANSLUCENT_BEYOND - || b == AVATAR_JOINT_RIGHT_ELBOW - || b == AVATAR_JOINT_RIGHT_WRIST - || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { + || b == BODY_BALL_RIGHT_ELBOW + || b == BODY_BALL_RIGHT_WRIST + || b == BODY_BALL_RIGHT_FINGERTIPS ) { // Render the body ball sphere - if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW - || b == AVATAR_JOINT_RIGHT_WRIST - || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { + if (_owningAgent || b == BODY_BALL_RIGHT_ELBOW + || b == BODY_BALL_RIGHT_WRIST + || b == BODY_BALL_RIGHT_FINGERTIPS ) { glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); @@ -1042,8 +1068,8 @@ void Avatar::renderBody(bool lookingInMirror) { alpha); } - if ((b != AVATAR_JOINT_HEAD_TOP ) - && (b != AVATAR_JOINT_HEAD_BASE )) { + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z); glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f); @@ -1052,20 +1078,20 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the cone connecting this ball to its parent if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { - if ((b != AVATAR_JOINT_HEAD_TOP ) - && (b != AVATAR_JOINT_HEAD_BASE ) - && (b != AVATAR_JOINT_PELVIS ) - && (b != AVATAR_JOINT_TORSO ) - && (b != AVATAR_JOINT_CHEST ) - && (b != AVATAR_JOINT_LEFT_COLLAR ) - && (b != AVATAR_JOINT_LEFT_SHOULDER ) - && (b != AVATAR_JOINT_RIGHT_COLLAR ) - && (b != AVATAR_JOINT_RIGHT_SHOULDER)) { + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE ) + && (b != BODY_BALL_PELVIS ) + && (b != BODY_BALL_TORSO ) + && (b != BODY_BALL_CHEST ) + && (b != BODY_BALL_LEFT_COLLAR ) + && (b != BODY_BALL_LEFT_SHOULDER ) + && (b != BODY_BALL_RIGHT_COLLAR ) + && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); float r1 = _bodyBall[_skeleton.joint[b].parent ].radius * 0.8; float r2 = _bodyBall[b ].radius * 0.8; - if (b == AVATAR_JOINT_HEAD_BASE) { + if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; } renderJointConnectingCone From 73f8fca2afaa182d93d9a11e9510d6d8141e5891 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Jun 2013 13:00:54 -0700 Subject: [PATCH 22/44] More work on voxeltars; added rotations. --- interface/src/Avatar.cpp | 8 +++- interface/src/AvatarVoxelSystem.cpp | 9 ++-- interface/src/Skeleton.cpp | 65 +++++++++++++-------------- interface/src/Skeleton.h | 68 +++++++++++++++-------------- interface/src/Util.cpp | 21 +++++++++ interface/src/Util.h | 2 + 6 files changed, 103 insertions(+), 70 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 2250bda751..fa193d3a70 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -909,6 +909,8 @@ void Avatar::updateBodyBalls(float deltaTime) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } + glm::quat orientation = getOrientation(); + glm::vec3 jointDirection = orientation * JOINT_DIRECTION; for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { glm::vec3 springVector(_bodyBall[b].position); @@ -955,7 +957,11 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - _bodyBall[b].rotation = _skeleton.joint[b].rotation; + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; + } else { + _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; + } } } diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index d6b51bec82..9e441c148c 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -144,10 +144,11 @@ void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { glm::vec3 position; glm::quat orientation; _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); - boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].translate(position.x, position.y, position.z); + orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation); boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); - const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition; - boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z); + const glm::vec3& bindPosition = _avatar->getSkeleton().joint[i].absoluteBindPosePosition; + boneMatrices[i].translate(-bindPosition.x, -bindPosition.y, -bindPosition.z); boneMatrices[i] *= baseMatrix; } _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); @@ -182,7 +183,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition); + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteBindPosePosition); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index ae31810d8e..136cb6f619 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -5,6 +5,7 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include "Skeleton.h" +#include "Util.h" const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f; const float FLOATING_HEIGHT = 0.13f; @@ -17,7 +18,7 @@ void Skeleton::initialize() { for (int b=0; b 179.99f) { // 180 degree rotation; must use another axis + axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); + float axisLength = glm::length(axis); + if (axisLength < EPSILON) { // parallel to x; y will work + axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); + } else { + axis /= axisLength; + } + } else { + axis = glm::normalize(glm::cross(v1, v2)); + } + return glm::angleAxis(angle, axis); +} + // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) diff --git a/interface/src/Util.h b/interface/src/Util.h index 0823ac405b..0187d93da5 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -45,6 +45,8 @@ void drawVector(glm::vec3* vector); float angleBetween(const glm::vec3& v1, const glm::vec3& v2); +glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 safeEulerAngles(const glm::quat& q); glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); From c4b3b568e7e551f5716642b29f7aaefa21f9b253 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:13:52 -0700 Subject: [PATCH 23/44] make import and export properly rebase --- interface/src/Application.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab335dce97..73a0190267 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1343,12 +1343,22 @@ void Application::exportVoxels() { QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + VoxelTree exportTree; + + // then copy onto it + _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); + + exportTree.writeToFileV2(fileName); } - _voxels.writeToFileV2(fileName,selectedNode); + } void Application::importVoxels() { @@ -1377,10 +1387,10 @@ void Application::importVoxels() { // voxel size/position details. if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - args.newBaseOctCode = NULL; // selectedNode->getOctalCode(); + args.newBaseOctCode = selectedNode->getOctalCode(); } else { printf("importVoxels() no voxel at current location, calculate octCode... \n"); - args.newBaseOctCode = NULL; // = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); @@ -1520,7 +1530,7 @@ void Application::initMenu() { "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); (_eyedropperMode = voxelMenu->addAction( - "Eyedropper Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_E))->setCheckable(true); + "Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_G))->setCheckable(true); _voxelModeActions->addAction(_eyedropperMode); voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); @@ -1529,7 +1539,6 @@ void Application::initMenu() { _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); - voxelMenu->addAction("Use Voxel Color", this, SLOT(useVoxelPaintColor()), Qt::CTRL | Qt::Key_U); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); From ea965f22902c4e81105bf2f4a9b33de7f0c2103d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:46:21 -0700 Subject: [PATCH 24/44] fixed issue with sendVoxelsOperataion, some other cleanup --- interface/src/Application.cpp | 26 ++++++++++---------------- libraries/voxels/src/VoxelTree.cpp | 9 --------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 73a0190267..ec51855c49 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1297,7 +1297,6 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; if (node->isColored()) { unsigned char* nodeOctalCode = node->getOctalCode(); - printOctalCode(nodeOctalCode); unsigned char* codeColorBuffer = NULL; int codeLength = 0; @@ -1307,7 +1306,6 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { // If the newBase is NULL, then don't rebase if (args->newBaseOctCode) { codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); - printOctalCode(codeColorBuffer); codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); bytesInCode = bytesRequiredForCodeLength(codeLength); codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; @@ -1327,7 +1325,7 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { // if we have room don't have room in the buffer, then send the previously generated message first if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); - args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset } // copy this node's code color details into our buffer. @@ -1359,6 +1357,8 @@ void Application::exportVoxels() { exportTree.writeToFileV2(fileName); } + // restore the main window's active state + _window->activateWindow(); } void Application::importVoxels() { @@ -1394,9 +1394,9 @@ void Application::importVoxels() { } importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); - + // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { + if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } @@ -1404,29 +1404,24 @@ void Application::importVoxels() { delete calculatedOctCode; } + // restore the main window's active state + _window->activateWindow(); } void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); - // clear the clipboard first... _clipboardTree.eraseAllVoxels(); // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); - - // debug tree - //_clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } void Application::pasteVoxels() { unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); // 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 @@ -1437,19 +1432,18 @@ void Application::pasteVoxels() { args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // voxel size/position details. + // 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. if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); args.newBaseOctCode = selectedNode->getOctalCode(); } else { - printf("pasteVoxels() no voxel at current location, calculate octCode... \n"); args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { + if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 704c15e4db..af6b435512 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1185,18 +1185,11 @@ bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { } void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { - - printLog("copySubTreeIntoNewTree()...\n"); - VoxelNodeBag nodeBag; - // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(startNode); - int chopLevels = 0; - if (rebaseToRoot) { chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); - printLog("copySubTreeIntoNewTree()...rebaseToRoot=true, chopLevels=%d\n", chopLevels); } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static @@ -1215,8 +1208,6 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat } void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { - printLog("copyFromTreeIntoSubTree()...\n"); - VoxelNodeBag nodeBag; // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); From 0f2b73613091eb8f6b40684a8250d000d2812205 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:50:42 -0700 Subject: [PATCH 25/44] cleanup --- interface/src/Application.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ec51855c49..9b1b97be19 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1341,19 +1341,9 @@ void Application::exportVoxels() { QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - - printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, - _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - - if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); - VoxelTree exportTree; - - // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); - exportTree.writeToFileV2(fileName); } @@ -1371,8 +1361,6 @@ void Application::importVoxels() { importVoxels.readFromFileV2(fileName); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, - _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); // Recurse the Import Voxels 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 @@ -1386,10 +1374,8 @@ void Application::importVoxels() { // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the // voxel size/position details. if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); args.newBaseOctCode = selectedNode->getOctalCode(); } else { - printf("importVoxels() no voxel at current location, calculate octCode... \n"); args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } @@ -1744,17 +1730,6 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::vec3 up = rotation * AVATAR_UP; glm::vec3 right = rotation * AVATAR_RIGHT; - /* - printf("position.x=%f, position.y=%f, position.z=%f\n", position.x, position.y, position.z); - printf("yaw=%f, pitch=%f, roll=%f\n", yaw,pitch,roll); - printf("direction.x=%f, direction.y=%f, direction.z=%f\n", direction.x, direction.y, direction.z); - printf("up.x=%f, up.y=%f, up.z=%f\n", up.x, up.y, up.z); - printf("right.x=%f, right.y=%f, right.z=%f\n", right.x, right.y, right.z); - printf("fov=%f\n", fov); - printf("nearClip=%f\n", nearClip); - printf("farClip=%f\n", farClip); - */ - // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); viewFrustum.setOrientation(direction,up,right); @@ -2355,7 +2330,6 @@ void Application::maybeEditVoxelUnderCursor() { //_myAvatar.getPosition() voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); voxelInjector->setVolume (16 * pow (_mouseVoxel.s, 2) / .0000001); //255 is max, and also default value - // printf("mousevoxelscale is %f\n", _mouseVoxel.s); /* for (int i = 0; i < 22050; i++) { From 26bbb9917b7b9ab096e3238048a4a800f510b6e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:23:55 -0700 Subject: [PATCH 26/44] more work on avatar touch --- interface/src/Application.cpp | 2 +- interface/src/Avatar.cpp | 242 +++++++++++++++++++++++----------- interface/src/Avatar.h | 23 ++-- interface/src/Skeleton.cpp | 1 + interface/src/Skeleton.h | 1 + 5 files changed, 185 insertions(+), 84 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 130bd5e7fe..1480b81050 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,7 +50,7 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = false; +const bool TESTING_AVATAR_TOUCH = true; // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 4fb2846a0f..99ddd65853 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -44,7 +44,7 @@ const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; const float AVATAR_BRAKING_STRENGTH = 40.0f; -const float JOINT_TOUCH_RANGE = 0.01f; +const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; const float LEAN_SENSITIVITY = 0.15; @@ -64,7 +64,8 @@ float chatMessageHeight = 0.20; Avatar::Avatar(Agent* owningAgent) : AvatarData(owningAgent), _head(this), - _TEST_bigSphereRadius(0.4f), + _ballSpringsInitialized(false), + _TEST_bigSphereRadius(0.5f), _TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f), _mousePressed(false), _bodyPitchDelta(0.0f), @@ -118,6 +119,8 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { + _ballSpringsInitialized = false; //this gets set to true on the first update pass... + for (int b=0; b (1.0f - range)) { _bodyBall[b].touchForce = (dot - (1.0f - range)) / range; @@ -585,11 +670,6 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); - //Test: Show angle between your fwd vector and nearest avatar - //glm::vec3 vectorBetweenUs = otherAvatar->getJointPosition(AVATAR_JOINT_PELVIS) - - // getJointPosition(AVATAR_JOINT_PELVIS); - //printLog("Angle between: %f\n", angleBetween(vectorBetweenUs, getBodyFrontDirection())); - // test whether shoulders are close enough to allow for reaching to touch hands glm::vec3 v(_position - otherAvatar->_position); float distance = glm::length(v); @@ -689,16 +769,16 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - glm::vec3 vectorFromJointToBigSphereCenter(_bodyBall[b].position - position); - float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); + glm::vec3 vectorFromBallToBigSphereCenter(_bodyBall[b].position - position); + float distanceToBigSphereCenter = glm::length(vectorFromBallToBigSphereCenter); float combinedRadius = _bodyBall[b].radius + radius; if (distanceToBigSphereCenter < combinedRadius) { if (distanceToBigSphereCenter > 0.0) { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + glm::vec3 directionVector = vectorFromBallToBigSphereCenter / distanceToBigSphereCenter; float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + glm::vec3 collisionForce = vectorFromBallToBigSphereCenter * penetration; _velocity += collisionForce * 40.0f * deltaTime; _bodyBall[b].position = position + directionVector * combinedRadius; @@ -792,18 +872,18 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime for (int o=b+1; o_bodyBall[o].isCollidable) { - glm::vec3 vectorBetweenJoints(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); - float distanceBetweenJoints = glm::length(vectorBetweenJoints); + glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); + float distanceBetweenBalls = glm::length(vectorBetweenBalls); - if (distanceBetweenJoints > 0.0) { // to avoid divide by zero + if (distanceBetweenBalls > 0.0) { // to avoid divide by zero float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius; // check for collision - if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { - glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; + if (distanceBetweenBalls < combinedRadius * COLLISION_RADIUS_SCALAR) { + glm::vec3 directionVector = vectorBetweenBalls / distanceBetweenBalls; // push balls away from each other and apply friction - float penetration = 1.0f - (distanceBetweenJoints / (combinedRadius * COLLISION_RADIUS_SCALAR)); + float penetration = 1.0f - (distanceBetweenBalls / (combinedRadius * COLLISION_RADIUS_SCALAR)); glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime; bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime; @@ -919,7 +999,12 @@ void Avatar::render(bool lookingInMirror) { void Avatar::resetBodyBalls() { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - _bodyBall[b].position = _skeleton.joint[b].position; // put balls on joints + + glm::vec3 targetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + _bodyBall[b].position = targetPosition; // put ball on target position _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } } @@ -931,30 +1016,39 @@ void Avatar::updateBodyBalls(float deltaTime) { resetBodyBalls(); } for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - glm::vec3 springVector(_bodyBall[b].position); - - if (b == BODY_BALL_PELVIS) { - springVector -= _position; - } - else { - springVector -= _bodyBall[ _skeleton.joint[b].parent ].position; - } - - float length = glm::length(springVector); - - if (length > 0.0f) { // to avoid divide by zero - glm::vec3 springDirection = springVector / length; - - float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime; - _bodyBall[b].velocity -= springDirection * force; + + if (_ballSpringsInitialized) { + + //apply spring forces + glm::vec3 springVector(_bodyBall[b].position); - if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { - _bodyBall[_skeleton.joint[b].parent].velocity += springDirection * force; + if (b == BODY_BALL_PELVIS) { + springVector -= _position; } + else { + springVector -= _bodyBall[_bodyBall[b].parentBall].position; + } + + float length = glm::length(springVector); + + if (length > 0.0f) { // to avoid divide by zero + glm::vec3 springDirection = springVector / length; + + float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime; + _bodyBall[b].velocity -= springDirection * force; + + if (_bodyBall[b].parentBall != BODY_BALL_NULL) { + _bodyBall[_bodyBall[b].parentBall].velocity += springDirection * force; + } + } } // apply tightness force - (causing ball position to be close to skeleton joint position) - _bodyBall[b].velocity += (_skeleton.joint[b].position - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime; + glm::vec3 targetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + _bodyBall[b].velocity += (targetPosition - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime; // apply decay float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; @@ -1077,7 +1171,7 @@ void Avatar::renderBody(bool lookingInMirror) { } // Render the cone connecting this ball to its parent - if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { + if (_bodyBall[b].parentBall != BODY_BALL_NULL) { if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE ) && (b != BODY_BALL_PELVIS ) @@ -1089,15 +1183,15 @@ void Avatar::renderBody(bool lookingInMirror) { && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); - float r1 = _bodyBall[_skeleton.joint[b].parent ].radius * 0.8; - float r2 = _bodyBall[b ].radius * 0.8; + float r1 = _bodyBall[_bodyBall[b].parentBall ].radius * 0.8; + float r2 = _bodyBall[b].radius * 0.8; if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; } renderJointConnectingCone ( - _bodyBall[_skeleton.joint[b].parent ].position, - _bodyBall[b ].position, r2, r2 + _bodyBall[_bodyBall[b].parentBall].position, + _bodyBall[b].position, r2, r2 ); } } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 8b5a67c7fb..3809678cd5 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -48,6 +48,9 @@ enum AvatarBodyBallID BODY_BALL_RIGHT_KNEE, BODY_BALL_RIGHT_HEEL, BODY_BALL_RIGHT_TOES, + +//TEST! +//BODY_BALL_LEFT_MID_THIGH, NUM_AVATAR_BODY_BALLS }; @@ -132,18 +135,21 @@ private: struct AvatarBall { - AvatarJointID parentJoint; - glm::vec3 parentOffset; - glm::vec3 position; - glm::vec3 velocity; - float jointTightness; - float radius; - bool isCollidable; - float touchForce; + AvatarJointID parentJoint; // the skeletal joint that serves as a reference for determining the position + glm::vec3 parentOffset; // a 3D vector in the frame of reference of the parent skeletal joint + AvatarBodyBallID parentBall; // the ball to which this ball is constrained for spring forces + glm::vec3 position; // the actual dynamic position of the ball at any given time + glm::vec3 velocity; // the velocity of the ball + float springLength; // the ideal length of the spring between this ball and its parentBall + float jointTightness; // how tightly the ball position attempts to stay at its ideal position (determined by parentOffset) + float radius; // the radius of the ball + bool isCollidable; // whether or not the ball responds to collisions + float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; Head _head; Skeleton _skeleton; + bool _ballSpringsInitialized; float _TEST_bigSphereRadius; glm::vec3 _TEST_bigSpherePosition; bool _mousePressed; @@ -151,7 +157,6 @@ private: float _bodyYawDelta; float _bodyRollDelta; glm::vec3 _movedHandOffset; - glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; glm::vec3 _cameraPosition; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 64a8645247..e360b0f97f 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -101,6 +101,7 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p } } + float Skeleton::getArmLength() { return joint[ AVATAR_JOINT_RIGHT_ELBOW ].length + joint[ AVATAR_JOINT_RIGHT_WRIST ].length diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 28d3a6e81e..5b979b47f3 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -55,6 +55,7 @@ public: float getHeight(); float getPelvisStandingHeight(); float getPelvisFloatingHeight(); + //glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; } struct AvatarJoint { From b73eb66492a6654347efde52e598d83b47d46244 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:31:39 -0700 Subject: [PATCH 27/44] temp test --- interface/src/Avatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 99ddd65853..91feb88681 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -43,7 +43,10 @@ const float HEAD_MIN_PITCH = -45; const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; -const float AVATAR_BRAKING_STRENGTH = 40.0f; + +//const float AVATAR_BRAKING_STRENGTH = 40.0f; +const float AVATAR_BRAKING_STRENGTH = 0.0f; + const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; From 3ff11d0eb88b586812c5816b5cf741261d182985 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:42:27 -0700 Subject: [PATCH 28/44] test --- interface/src/Avatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 91feb88681..f4a2627e41 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -35,7 +35,10 @@ const float BODY_SPRING_FORCE = 300.0f; const float BODY_SPRING_DECAY = 16.0f; const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions + +//const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions +const float COLLISION_BODY_FORCE = 0.0; //pertains to avatar-to-avatar collisions + const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROLL_SCALE = 0.40; const float HEAD_MAX_PITCH = 45; From da09dd3259ca59f53bbb9aaa6f2cb2fe44950180 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 17:16:52 -0700 Subject: [PATCH 29/44] test --- interface/src/Avatar.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index f4a2627e41..99ddd65853 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -35,10 +35,7 @@ const float BODY_SPRING_FORCE = 300.0f; const float BODY_SPRING_DECAY = 16.0f; const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions - -//const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 0.0; //pertains to avatar-to-avatar collisions - +const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROLL_SCALE = 0.40; const float HEAD_MAX_PITCH = 45; @@ -46,10 +43,7 @@ const float HEAD_MIN_PITCH = -45; const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; - -//const float AVATAR_BRAKING_STRENGTH = 40.0f; -const float AVATAR_BRAKING_STRENGTH = 0.0f; - +const float AVATAR_BRAKING_STRENGTH = 40.0f; const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; From cee22443643174d2493a12435f730e975553abb0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 17:55:48 -0700 Subject: [PATCH 30/44] fixed formatting things --- interface/src/Application.cpp | 6 ++---- interface/src/Avatar.cpp | 32 +++++++++++++++----------------- interface/src/Skeleton.cpp | 2 +- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1480b81050..36ff4075d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,7 +50,7 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = true; +const bool TESTING_AVATAR_TOUCH = false; // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; @@ -1093,14 +1093,12 @@ void Application::idle() { _myCamera.setModeShiftRate(1.0f); } } else { - if (_myAvatar.getIsNearInteractingOther()) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } - else { + } else { if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setModeShiftRate(1.0f); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 99ddd65853..3949120737 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -121,7 +121,7 @@ void Avatar::initializeBodyBalls() { _ballSpringsInitialized = false; //this gets set to true on the first update pass... - for (int b=0; b::max(); - //loop through all the other avatars for potential interactions... + // loop through all the other avatars for potential interactions... AgentList* agentList = AgentList::getInstance(); for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { @@ -844,7 +844,7 @@ void Avatar::updateAvatarCollisions(float deltaTime) { glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) { - //apply forces from collision + // apply forces from collision applyCollisionWithOtherAvatar(otherAvatar, deltaTime); } @@ -860,16 +860,16 @@ void Avatar::updateAvatarCollisions(float deltaTime) { } } -//detect collisions with other avatars and respond +// detect collisions with other avatars and respond void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); // loop through the body balls of each avatar to check for every possible collision - for (int b=1; b_bodyBall[o].isCollidable) { glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); @@ -898,7 +898,7 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime } // b loop } // collidable - //apply force on the whole body + // apply force on the whole body _velocity += bodyPushForce; } @@ -938,7 +938,7 @@ void Avatar::render(bool lookingInMirror) { // render a simple round on the ground projected down from the avatar's position renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), 0.1f, 0.2f); - //render body + // render body renderBody(lookingInMirror); // if this is my avatar, then render my interactions with the other avatar @@ -1010,7 +1010,7 @@ void Avatar::resetBodyBalls() { } void Avatar::updateBodyBalls(float deltaTime) { - // Check for a large repositioning, and re-initialize balls if this has happened + // Check for a large repositioning, and re-initialize balls if this has happened const float BEYOND_BODY_SPRING_RANGE = 2.f; if (glm::length(_position - _bodyBall[BODY_BALL_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); @@ -1019,13 +1019,12 @@ void Avatar::updateBodyBalls(float deltaTime) { if (_ballSpringsInitialized) { - //apply spring forces + // apply spring forces glm::vec3 springVector(_bodyBall[b].position); if (b == BODY_BALL_PELVIS) { springVector -= _position; - } - else { + } else { springVector -= _bodyBall[_bodyBall[b].parentBall].position; } @@ -1054,19 +1053,18 @@ void Avatar::updateBodyBalls(float deltaTime) { float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; if (decay > 0.0) { _bodyBall[b].velocity *= decay; - } - else { + } else { _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } /* - //apply forces from touch... + // apply forces from touch... if (_bodyBall[b].touchForce > 0.0) { _bodyBall[b].velocity += _mouseRayDirection * _bodyBall[b].touchForce * 0.7f; } */ - //update position by velocity... + // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; } } @@ -1229,7 +1227,7 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity _head.setYaw (angles.x); _head.setPitch(angles.y); _head.setRoll (angles.z); - //printLog("Y/P/R: %3.1f, %3.1f, %3.1f\n", angles.x, angles.y, angles.z); + // printLog("Y/P/R: %3.1f, %3.1f, %3.1f\n", angles.x, angles.y, angles.z); } } diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index e360b0f97f..55c6210068 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -14,7 +14,7 @@ Skeleton::Skeleton() { void Skeleton::initialize() { - for (int b=0; b Date: Mon, 3 Jun 2013 18:08:11 -0700 Subject: [PATCH 31/44] copy and paste working --- interface/src/Application.cpp | 2 +- libraries/shared/src/OctalCode.cpp | 33 ++++++++++++++++----------- libraries/shared/src/OctalCode.h | 8 +++++++ libraries/voxels/src/VoxelConstants.h | 7 +----- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b2bd7b22e6..8cc313b4bb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2397,7 +2397,7 @@ void Application::deleteVoxelUnderCursor() { for (int i = 0; i < 5000; i++) { voxelInjector->addSample(10000 * sin((i * 2 * PIE) / (500 * sin((i + 1) / 500.0)))); //FM 3 resonant pulse - // voxelInjector->addSample(20000 * sin((i) /((4 / _mouseVoxel.s) * sin((i)/(20 * _mouseVoxel.s / .001))))); //FM 2 comb filter + //voxelInjector->addSample(20000 * sin((i) /((4 / _mouseVoxel.s) * sin((i)/(20 * _mouseVoxel.s / .001))))); //FM 2 comb filter } AudioInjectionManager::threadInjector(voxelInjector); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 150789bec8..d51f058459 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -170,22 +170,21 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB char getOctalCodeSectionValue(unsigned char* octalCode, int section) { - int startAtByte = 1 + (3 * section / 8); - char startIndexInByte = (3 * section) % 8; + int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); + char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; unsigned char* startByte = octalCode + startAtByte; return sectionValue(startByte, startIndexInByte); } void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { - unsigned char* byteAt = octalCode + 1 + (3 * section / 8); - char bitInByte = (3 * section) % 8; - char shiftBy = 8 - bitInByte - 3; + int byteForSection = (BITS_IN_OCTAL * section / BITS_IN_BYTE); + unsigned char* byteAt = octalCode + 1 + byteForSection; + char bitInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; + char shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; - - if (shiftBy >=0) { shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; @@ -193,15 +192,24 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio shiftedMask = UNSHIFTED_MASK >> -shiftBy; shiftedValue = sectionValue >> -shiftBy; } - unsigned char oldValue = *byteAt & ~shiftedMask; unsigned char newValue = oldValue | shiftedValue; *byteAt = newValue; - if (bitInByte >= 6) { - shiftBy = bitInByte + 1; + + // If the requested section is partially in the byte, then we + // need to also set the portion of the section value in the next byte + // there's only two cases where this happens, if the bit in byte is + // 6, then it means that 1 extra bit lives in the next byte. If the + // bit in this byte is 7 then 2 extra bits live in the next byte. + const int FIRST_PARTIAL_BIT = 6; + if (bitInByte >= FIRST_PARTIAL_BIT) { + int bitsInFirstByte = BITS_IN_BYTE - bitInByte; + int bitsInSecondByte = BITS_IN_OCTAL - bitsInFirstByte; + shiftBy = BITS_IN_BYTE - bitsInSecondByte; + shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; - + oldValue = byteAt[1] & ~shiftedMask; newValue = oldValue | shiftedValue; byteAt[1] = newValue; @@ -228,8 +236,7 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); int newCodeLength = newParentCodeLength + oldCodeLength; - const int COLOR_SPACE = 3; - int bufferLength = newCodeLength + (includeColorSpace ? COLOR_SPACE : 0); + int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); unsigned char* newCode = new unsigned char[bufferLength]; *newCode = newCodeLength; // set the length byte diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bfed24a87c..761eac1953 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -11,6 +11,14 @@ #include +const int BITS_IN_BYTE = 8; +const int BITS_IN_OCTAL = 3; +const int NUMBER_OF_COLORS = 3; // RGB! +const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes +const int RED_INDEX = 0; +const int GREEN_INDEX = 1; +const int BLUE_INDEX = 2; + void printOctalCode(unsigned char * octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index b18315402a..5bf1345d73 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -13,6 +13,7 @@ #define __hifi_VoxelConstants_h__ #include +#include const int TREE_SCALE = 128; @@ -23,12 +24,6 @@ const int MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; - -const int NUMBER_OF_COLORS = 3; // RGB! -const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes -const int RED_INDEX = 0; -const int GREEN_INDEX = 1; -const int BLUE_INDEX = 2; const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; typedef unsigned long int glBufferIndex; From 03f79f5cab8d566373e7be82d4b762e6f5fbb4d0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 21:04:42 -0700 Subject: [PATCH 32/44] fixed delete voxel --- libraries/voxels/src/VoxelTree.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index af6b435512..5bf9844fc1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,9 +286,9 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, b } } - // If we're not a colored leaf, and we have no children, then delete ourselves - // This will collapse the empty tree above us. - if (collapseEmptyTrees && parentNode->getChildCount() == 0 && !parentNode->isColored()) { + // If we're in collpaseEmptryTrees mode, and we're the last child of this parent, then delete the parent. + // This will collapse the empty tree above us. + if (collapseEmptyTrees && parentNode->getChildCount() == 0) { // Can't delete the root this way. if (parentNode != rootNode) { deleteVoxelCodeFromTree(parentNode->getOctalCode(), stage, collapseEmptyTrees); From 435791f28c0d08fa144881f773e7a46a303fc9b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:02:10 -0700 Subject: [PATCH 33/44] CR feedback --- interface/src/Application.cpp | 14 +++++++------- interface/src/Application.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05bd0f3d5a..d8eed95ea7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1293,15 +1293,15 @@ void Application::chooseVoxelPaintColor() { } const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; -struct SendVoxelsOperataionArgs { +struct SendVoxelsOperationArgs { unsigned char* newBaseOctCode; unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; int bufferInUse; }; -bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { - SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; +bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { + SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; if (node->isColored()) { unsigned char* nodeOctalCode = node->getOctalCode(); @@ -1372,7 +1372,7 @@ void Application::importVoxels() { // Recurse the Import Voxels 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 unsigned char* calculatedOctCode = NULL; - SendVoxelsOperataionArgs args; + SendVoxelsOperationArgs args; args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; *sequenceAt = 0; @@ -1386,7 +1386,7 @@ void Application::importVoxels() { args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); + importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args); // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { @@ -1418,7 +1418,7 @@ void Application::pasteVoxels() { // 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 - SendVoxelsOperataionArgs args; + SendVoxelsOperationArgs args; args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; *sequenceAt = 0; @@ -1433,7 +1433,7 @@ void Application::pasteVoxels() { args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args); // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { diff --git a/interface/src/Application.h b/interface/src/Application.h index ee48307910..edcc1d6b82 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -161,7 +161,7 @@ private slots: private: - static bool sendVoxelsOperataion(VoxelNode* node, void* extraData); + static bool sendVoxelsOperation(VoxelNode* node, void* extraData); void initMenu(); void updateFrustumRenderModeAction(); From 1f3de3e12b64621a4d125942a6b7b93d46ffc18f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:03:26 -0700 Subject: [PATCH 34/44] CR feedback --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5bf9844fc1..de6bafef3d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,7 +286,7 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, b } } - // If we're in collpaseEmptryTrees mode, and we're the last child of this parent, then delete the parent. + // If we're in collapseEmptyTrees mode, and we're the last child of this parent, then delete the parent. // This will collapse the empty tree above us. if (collapseEmptyTrees && parentNode->getChildCount() == 0) { // Can't delete the root this way. From 0a9b3bf5ce87e1045d4aaf21f323330db6d44159 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:07:18 -0700 Subject: [PATCH 35/44] changed file name and exention to Sparse Voxel Octree and svo --- interface/src/Application.cpp | 7 ++++--- voxel-edit/src/main.cpp | 2 +- voxel-server/src/main.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d8eed95ea7..00772e7fec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1343,8 +1343,8 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { } void Application::exportVoxels() { - QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", - tr("High Fidelity Voxel Files (*.hio2)")); + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.svo", + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1359,7 +1359,8 @@ void Application::exportVoxels() { } void Application::importVoxels() { - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 222bf3f15b..d2c88812ca 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -92,7 +92,7 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); - myTree.writeToFileV2("voxels.hio2"); + myTree.writeToFileV2("voxels.svo"); } return 0; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 70f7ab8752..4d06f60f0c 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -30,8 +30,8 @@ #include #endif -const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.hio2"; -const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.hio2"; +const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; +const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; const double VOXEL_PERSIST_INTERVAL = 1000.0 * 30; // every 30 seconds const int VOXEL_LISTEN_PORT = 40106; From 37cc436b2b9c4a082f6e252f38a4d91f70e41a11 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:08:18 -0700 Subject: [PATCH 36/44] CR feedback --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index de6bafef3d..96c9320edd 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1223,7 +1223,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); // ask destination tree to read the bitstream - readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS,destinationNode); + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS, destinationNode); } } From 4f3872c18fb696863cfbe20c71a4f84e2c0a49ad Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:13:58 -0700 Subject: [PATCH 37/44] CR feedback --- interface/src/Application.cpp | 4 ++-- interface/src/VoxelSystem.cpp | 8 ++++---- interface/src/VoxelSystem.h | 4 ++-- libraries/voxels/src/VoxelTree.cpp | 4 ++-- libraries/voxels/src/VoxelTree.h | 4 ++-- voxel-edit/src/main.cpp | 2 +- voxel-server/src/main.cpp | 8 ++++---- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 00772e7fec..4610d889ed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1351,7 +1351,7 @@ void Application::exportVoxels() { if (selectedNode) { VoxelTree exportTree; _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); - exportTree.writeToFileV2(fileName); + exportTree.writeToSVOFile(fileName); } // restore the main window's active state @@ -1366,7 +1366,7 @@ void Application::importVoxels() { // Read the file into a tree VoxelTree importVoxels; - importVoxels.readFromFileV2(fileName); + importVoxels.readFromSVOFile(fileName); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b99519e845..11c274119b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -70,12 +70,12 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } -void VoxelSystem::writeToFileV2(const char* filename, VoxelNode* node) const { - _tree->writeToFileV2(filename, node); +void VoxelSystem::writeToSVOFile(const char* filename, VoxelNode* node) const { + _tree->writeToSVOFile(filename, node); } -bool VoxelSystem::readFromFileV2(const char* filename, VoxelNode* node) { - bool result = _tree->readFromFileV2(filename, node); +bool VoxelSystem::readFromSVOFile(const char* filename) { + bool result = _tree->readFromSVOFile(filename); if (result) { setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index c15ba53ba0..ee63801f92 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -44,8 +44,8 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); - void writeToFileV2(const char* filename, VoxelNode* node) const; - bool readFromFileV2(const char* filename, VoxelNode* node); + void writeToSVOFile(const char* filename, VoxelNode* node) const; + bool readFromSVOFile(const char* filename); long int getVoxelsCreated(); long int getVoxelsColored(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 96c9320edd..49d79141de 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1123,7 +1123,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } -bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { +bool VoxelTree::readFromSVOFile(const char* fileName) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { printLog("loading file %s...\n", fileName); @@ -1144,7 +1144,7 @@ bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { return false; } -void VoxelTree::writeToFileV2(const char* fileName, VoxelNode* node) const { +void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index a2302f6cc7..b63e6eb738 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -92,8 +92,8 @@ public: 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, VoxelNode* node = NULL) const; - bool readFromFileV2(const char* filename, VoxelNode* node = NULL); + void writeToSVOFile(const char* filename, VoxelNode* node = NULL) const; + bool readFromSVOFile(const char* filename); unsigned long getVoxelCount(); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index d2c88812ca..9571e4adf5 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -92,7 +92,7 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); - myTree.writeToFileV2("voxels.svo"); + myTree.writeToSVOFile("voxels.svo"); } return 0; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 4d06f60f0c..9bf4a1dcc4 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -399,10 +399,10 @@ void persistVoxelsWhenDirty() { { PerformanceWarning warn(::shouldShowAnimationDebug, - "persistVoxelsWhenDirty() - writeToFileV2()", ::shouldShowAnimationDebug); + "persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug); printf("saving voxels to file...\n"); - randomTree.writeToFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + randomTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); randomTree.clearDirtyBit(); // tree is clean after saving printf("DONE saving voxels to file...\n"); } @@ -505,7 +505,7 @@ int main(int argc, const char * argv[]) { bool persistantFileRead = false; if (::wantVoxelPersist) { printf("loading voxels from file...\n"); - persistantFileRead = ::randomTree.readFromFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + persistantFileRead = ::randomTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); ::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); unsigned long nodeCount = ::randomTree.getVoxelCount(); @@ -517,7 +517,7 @@ int main(int argc, const char * argv[]) { const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); if (voxelsFilename) { - randomTree.readFromFileV2(voxelsFilename); + randomTree.readFromSVOFile(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate From 743e1a433c00e80c388f3d61d34967d53e6ce5d4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:24:35 -0700 Subject: [PATCH 38/44] make import/export default to desktop --- interface/src/Application.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4610d889ed..56f1604e97 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1343,8 +1344,11 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { } void Application::exportVoxels() { - QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.svo", - tr("Sparse Voxel Octree Files (*.svo)")); + QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString suggestedName = desktopLocation.append("/voxels.svo"); + + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), suggestedName, + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1359,7 +1363,8 @@ void Application::exportVoxels() { } void Application::importVoxels() { - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", + QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), desktopLocation, tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); From 626874f9ecbf210722b8211c971fc41497e27f24 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 08:47:57 -0700 Subject: [PATCH 39/44] add delete key support while in select mode --- interface/src/Application.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 56f1604e97..26d7f92533 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -617,6 +617,12 @@ void Application::keyPressEvent(QKeyEvent* event) { } resizeGL(_glWidget->width(), _glWidget->height()); break; + case Qt::Key_Backspace: + case Qt::Key_Delete: + if (_selectVoxelMode->isChecked()) { + deleteVoxelUnderCursor(); + } + break; default: event->ignore(); From ce499f925a3d16b1e21c610b78cc20b774d6e8b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 09:02:34 -0700 Subject: [PATCH 40/44] add cut voxels --- interface/src/Application.cpp | 6 ++++++ interface/src/Application.h | 1 + 2 files changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 26d7f92533..6ef5d0d5bc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1413,6 +1413,11 @@ void Application::importVoxels() { _window->activateWindow(); } +void Application::cutVoxels() { + copyVoxels(); + deleteVoxelUnderCursor(); +} + void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { @@ -1545,6 +1550,7 @@ void Application::initMenu() { voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Cut Voxels", this, SLOT(cutVoxels()), Qt::CTRL | Qt::Key_X); voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); diff --git a/interface/src/Application.h b/interface/src/Application.h index edcc1d6b82..017759277c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -156,6 +156,7 @@ private slots: void chooseVoxelPaintColor(); void exportVoxels(); void importVoxels(); + void cutVoxels(); void copyVoxels(); void pasteVoxels(); From bc8eadd526b70b4e0ca624b8d541e9ae21efd140 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:22:58 -0700 Subject: [PATCH 41/44] More work on voxeltars; separated default pose from bind pose. --- interface/CMakeLists.txt | 4 +- interface/src/Application.cpp | 44 ++++++++++++++++++-- interface/src/Application.h | 9 +++++ interface/src/Avatar.h | 2 + interface/src/AvatarVoxelSystem.cpp | 63 ++++++++++++++++++++++------- interface/src/AvatarVoxelSystem.h | 23 +++++++++-- interface/src/Skeleton.cpp | 61 ++++++++++++++++++++-------- interface/src/Skeleton.h | 1 + interface/src/VoxelSystem.h | 4 +- 9 files changed, 171 insertions(+), 40 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d5da2073fb..b2984b35bb 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -63,12 +63,12 @@ if (APPLE) endif (APPLE) -find_package(Qt4 REQUIRED QtCore QtGui QtOpenGL) +find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL) include(${QT_USE_FILE}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") # run qt moc on qt-enabled headers -qt4_wrap_cpp(INTERFACE_SRCS src/Application.h) +qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h) # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8aaaf9856..57f1b89969 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -21,16 +21,23 @@ #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include +#include #include +#include #include #include +#include #include #include @@ -1122,6 +1129,31 @@ void Application::terminate() { } } +void Application::editPreferences() { + QDialog dialog(_glWidget); + dialog.setWindowTitle("Interface Preferences"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + dialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + form->addRow("Avatar URL:", avatarURL); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); + + if (dialog.exec() != QDialog::Accepted) { + return; + } + QUrl url(avatarURL->text()); + _settings->setValue("avatarURL", url); + _myAvatar.getVoxels()->loadVoxelsFromURL(url); +} + void Application::pair() { PairingHandler::sendPairRequest(); } @@ -1285,6 +1317,9 @@ void Application::initMenu() { QMenu* fileMenu = menuBar->addMenu("File"); fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q); + QMenu* editMenu = menuBar->addMenu("Edit"); + editMenu->addAction("Preferences...", this, SLOT(editPreferences())); + QMenu* pairMenu = menuBar->addMenu("Pair"); pairMenu->addAction("Pair", this, SLOT(pair())); @@ -1325,9 +1360,7 @@ void Application::initMenu() { renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true); QMenu* toolsMenu = menuBar->addMenu("Tools"); - (_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true); - _renderStatsOn->setShortcut(Qt::Key_Slash); (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(false); @@ -1381,6 +1414,9 @@ void Application::initMenu() { debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true); + + _networkAccessManager = new QNetworkAccessManager(this); + _settings = new QSettings("High Fidelity", "Interface", this); } void Application::updateFrustumRenderModeAction() { @@ -1431,6 +1467,8 @@ void Application::init() { _myCamera.setModeShiftRate(1.0f); _myAvatar.setDisplayingLookatVectors(false); + _myAvatar.getVoxels()->loadVoxelsFromURL(_settings->value("avatarURL").toUrl()); + QCursor::setPos(_headMouseX, _headMouseY); OculusManager::connect(); @@ -1727,7 +1765,7 @@ void Application::displayOculus(Camera& whichCamera) { glPopMatrix(); } - + void Application::displaySide(Camera& whichCamera) { // transform by eye offset diff --git a/interface/src/Application.h b/interface/src/Application.h index c2918f1add..1ed24683ae 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -37,6 +37,8 @@ class QGLWidget; class QKeyEvent; class QMainWindow; class QMouseEvent; +class QNetworkAccessManager; +class QSettings; class QWheelEvent; class Agent; @@ -70,6 +72,8 @@ public: Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } + QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } + /*! @fn getSettingBool @brief A function for getting boolean settings from the settings file. @@ -127,6 +131,8 @@ private slots: void idle(); void terminate(); + void editPreferences(); + void pair(); void setHead(bool head); @@ -227,6 +233,9 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; + QNetworkAccessManager* _networkAccessManager; + QSettings* _settings; + SerialInterface _serialPort; bool _displayLevels; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index c7561d3986..475fc0bc59 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -89,6 +89,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + AvatarVoxelSystem* getVoxels() { return &_voxels; } + // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key]; }; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 9e441c148c..5fdf974f71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,6 +7,12 @@ #include +#include +#include + +#include + +#include "Application.h" #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -17,7 +23,7 @@ const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXE AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), - _avatar(avatar) { + _avatar(avatar), _voxelReply(0) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -52,16 +58,6 @@ void AvatarVoxelSystem::init() { glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - for (int i = 0; i < 150; i++) { - int power = pow(2, randIntInRange(6, 8)); - float size = 1.0f / power; - _tree->createVoxel( - randIntInRange(0, power - 1) * size, - randIntInRange(0, power - 1) * size, - randIntInRange(0, power - 1) * size, size, 255, 0, 255, true); - } - setupNewVoxelsForDrawing(); - // load our skin program if this is the first avatar system to initialize if (_skinProgram != 0) { return; @@ -75,8 +71,25 @@ void AvatarVoxelSystem::init() { _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } -void AvatarVoxelSystem::render(bool texture) { - VoxelSystem::render(texture); +void AvatarVoxelSystem::removeOutOfView() { + // no-op for now +} + +void AvatarVoxelSystem::loadVoxelsFromURL(const QUrl& url) { + // cancel any current download + if (_voxelReply != 0) { + delete _voxelReply; + } + + killLocalVoxels(); + + // load the URL data asynchronously + if (!url.isValid()) { + return; + } + _voxelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url)); + connect(_voxelReply, SIGNAL(readyRead()), SLOT(readVoxelDataFromReply())); + connect(_voxelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleVoxelReplyError())); } void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -168,6 +181,25 @@ void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->disableAttributeArray(_boneWeightsLocation); } +void AvatarVoxelSystem::readVoxelDataFromReply() { + // for now, just wait until we have the full business + if (!_voxelReply->isFinished()) { + return; + } + QByteArray entirety = _voxelReply->readAll(); + _voxelReply->deleteLater(); + _voxelReply = 0; + _tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), WANT_COLOR, NO_EXISTS_BITS); + setupNewVoxelsForDrawing(); +} + +void AvatarVoxelSystem::handleVoxelReplyError() { + printLog("%s\n", _voxelReply->errorString().toAscii().constData()); + + _voxelReply->deleteLater(); + _voxelReply = 0; +} + class IndexDistance { public: IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } @@ -183,7 +215,10 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteBindPosePosition); + AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + float distance = glm::length(computeVectorFromPointToSegment(jointVertex, + _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index e3a80c3817..edeeadb17c 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -9,22 +9,32 @@ #ifndef __interface__AvatarVoxelSystem__ #define __interface__AvatarVoxelSystem__ +#include + #include "VoxelSystem.h" const int BONE_ELEMENTS_PER_VERTEX = 4; typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; +class QNetworkReply; +class QUrl; + class Avatar; -class AvatarVoxelSystem : public VoxelSystem { +class AvatarVoxelSystem : public QObject, public VoxelSystem { + Q_OBJECT + public: - + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); - virtual void render(bool texture); + virtual void removeOutOfView(); + + void loadVoxelsFromURL(const QUrl& url); + protected: virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -33,6 +43,11 @@ protected: virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void applyScaleAndBindProgram(bool texture); virtual void removeScaleAndReleaseProgram(bool texture); + +private slots: + + void readVoxelDataFromReply(); + void handleVoxelReplyError(); private: @@ -48,6 +63,8 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; + QNetworkReply* _voxelReply; + static ProgramObject* _skinProgram; static int _boneMatricesLocation; static int _boneIndicesLocation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 136cb6f619..a694b4032d 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -49,7 +49,7 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].parent = AVATAR_JOINT_RIGHT_KNEE; joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL; - // specify the default pose position + // specify the bind pose position joint[ AVATAR_JOINT_PELVIS ].bindPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); joint[ AVATAR_JOINT_TORSO ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); joint[ AVATAR_JOINT_CHEST ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); @@ -58,29 +58,58 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_LEFT_COLLAR ].bindPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_LEFT_SHOULDER ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( -0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( -0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( -0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_RIGHT_COLLAR ].bindPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_RIGHT_SHOULDER ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_LEFT_HIP ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); joint[ AVATAR_JOINT_RIGHT_HIP ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); + + // specify the default pose position + joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); + joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.14, 0.01 ); + joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.04, 0.00 ); + + joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); + joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + + joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); + joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); + joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); - // calculate bone length, absolute positions/rotations + // calculate bone length, absolute bind positions/rotations for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - joint[b].length = glm::length(joint[b].bindPosePosition); + joint[b].length = glm::length(joint[b].defaultPosePosition); if (joint[b].parent == AVATAR_JOINT_NULL) { joint[b].absoluteBindPosePosition = joint[b].bindPosePosition; @@ -106,7 +135,7 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p joint[b].position = joint[ joint[b].parent ].position; } - glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].bindPosePosition; + glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].defaultPosePosition; joint[b].position += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 78405b39ac..dd55c5fa68 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -61,6 +61,7 @@ public: { AvatarJointID parent; // which joint is this joint connected to? glm::vec3 position; // the position at the "end" of the joint - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the default pose glm::vec3 bindPosePosition; // the parent relative position when the avatar is in the "T-pose" glm::vec3 absoluteBindPosePosition; // the absolute position when the avatar is in the "T-pose" glm::quat absoluteBindPoseRotation; // the absolute rotation when the avatar is in the "T-pose" diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 3a46e19517..e310fdaf7c 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -33,7 +33,7 @@ public: virtual void init(); void simulate(float deltaTime) { }; - virtual void render(bool texture); + void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -59,7 +59,7 @@ public: void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; bool getRenderPipelineWarnings() const { return _renderWarningsOn; }; - void removeOutOfView(); + virtual void removeOutOfView(); bool hasViewChanged(); bool isViewChanging(); From 90a53bc5181ad246035fd812fc1d8cb95ca43a04 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:40:08 -0700 Subject: [PATCH 42/44] Only bind vertices within an adjustable radius. --- interface/src/Avatar.cpp | 2 +- interface/src/AvatarVoxelSystem.cpp | 29 ++++++++++++++++++++++------- interface/src/Skeleton.cpp | 3 ++- interface/src/Skeleton.h | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index fa193d3a70..a563ff6fff 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -957,7 +957,7 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 5fdf974f71..2500c9b2d4 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -202,7 +202,7 @@ void AvatarVoxelSystem::handleVoxelReplyError() { class IndexDistance { public: - IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + IndexDistance(GLubyte index = AVATAR_JOINT_PELVIS, float distance = FLT_MAX) : index(index), distance(distance) { } GLubyte index; float distance; @@ -214,11 +214,15 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; + const Skeleton& skeleton = _avatar->getSkeleton(); for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + AvatarJointID parent = skeleton.joint[i].parent; float distance = glm::length(computeVectorFromPointToSegment(jointVertex, - _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, - _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); + skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + skeleton.joint[i].absoluteBindPosePosition)); + if (distance > skeleton.joint[i].bindRadius) { + continue; + } for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down @@ -235,11 +239,22 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float totalWeight = 0.0f; for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { indices[i] = nearest[i].index; - weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); - totalWeight += weights[i]; + if (nearest[i].distance != FLT_MAX) { + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + + } else { + weights[i] = 0.0f; + } } - // normalize the weights + // if it's not attached to anything, consider it attached to the hip + if (totalWeight == 0.0f) { + weights[0] = 1.0f; + return; + } + + // ortherwise, normalize the weights for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { weights[i] /= totalWeight; } diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index a694b4032d..f22953a6c1 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,9 +18,10 @@ void Skeleton::initialize() { for (int b=0; b Date: Tue, 4 Jun 2013 15:52:39 -0700 Subject: [PATCH 43/44] Adjusted default bind radius, spring vector threshold. --- interface/src/Avatar.cpp | 3 ++- interface/src/Skeleton.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 61112c3403..4a3e8db2bc 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1076,7 +1076,8 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { + const float SMALL_SPRING_LENGTH = 0.001f; // too-small springs can change direction rapidly + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < SMALL_SPRING_LENGTH) { _bodyBall[b].rotation = orientation * _skeleton.joint[_bodyBall[b].parentJoint].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 13092648a3..b3720c8869 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -21,7 +21,7 @@ void Skeleton::initialize() { joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; - joint[b].bindRadius = 1.0f / 16; + joint[b].bindRadius = 1.0f / 8; } // specify the parental hierarchy From 93b50f44f5a8ee791bebbba87a0f19aa1bd6a0c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 15:59:07 -0700 Subject: [PATCH 44/44] Add a reasonable minimum size for the URL field. --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8aba8a613a..6f898ecae7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1158,6 +1158,7 @@ void Application::editPreferences() { layout->addLayout(form, 1); QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + avatarURL->setMinimumWidth(400); form->addRow("Avatar URL:", avatarURL); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);