From 78fe89172ac221ad59e8bfab4c478234c5a62c0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 12:23:16 -0700 Subject: [PATCH] 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