From bf814410ac8bf5fd78313dd537f5d48f00d18d07 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 00:10:16 -0800 Subject: [PATCH 01/15] first cut at exposing clipboard support to JavaScript --- interface/src/Application.cpp | 48 ++++++++++++--- interface/src/Application.h | 13 +++- interface/src/ClipboardScriptingInterface.cpp | 59 +++++++++++++++++++ interface/src/ClipboardScriptingInterface.h | 31 ++++++++++ .../voxels/src/VoxelEditPacketSender.cpp | 4 +- libraries/voxels/src/VoxelEditPacketSender.h | 2 +- 6 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 interface/src/ClipboardScriptingInterface.cpp create mode 100644 interface/src/ClipboardScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b316548ad4..433158f413 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,6 +62,7 @@ #include #include "Application.h" +#include "ClipboardScriptingInterface.h" #include "DataServerClient.h" #include "InterfaceVersion.h" #include "Menu.h" @@ -1686,6 +1687,10 @@ bool Application::sendVoxelsOperation(OctreeElement* element, void* extraData) { } void Application::exportVoxels() { + exportVoxels(_mouseVoxel); +} + +void Application::exportVoxels(const VoxelDetail& sourceVoxel) { QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); QString suggestedName = desktopLocation.append("/voxels.svo"); @@ -1693,7 +1698,7 @@ void Application::exportVoxels() { tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toLocal8Bit(); const char* fileName = fileNameAscii.data(); - VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); if (selectedNode) { VoxelTree exportTree; _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); @@ -1721,11 +1726,19 @@ void Application::importVoxels() { } void Application::cutVoxels() { - copyVoxels(); - deleteVoxelUnderCursor(); + cutVoxels(_mouseVoxel); +} + +void Application::cutVoxels(const VoxelDetail& sourceVoxel) { + copyVoxels(sourceVoxel); + deleteVoxelAt(sourceVoxel); } void Application::copyVoxels() { + copyVoxels(_mouseVoxel); +} + +void Application::copyVoxels(const VoxelDetail& sourceVoxel) { // switch to and clear the clipboard first... _sharedVoxelSystem.killLocalVoxels(); if (_sharedVoxelSystem.getTree() != &_clipboard) { @@ -1734,7 +1747,7 @@ void Application::copyVoxels() { } // then copy onto it if there is something to copy - VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); if (selectedNode) { _voxels.copySubTreeIntoNewTree(selectedNode, &_sharedVoxelSystem, true); } @@ -1756,8 +1769,12 @@ void Application::pasteVoxelsToOctalCode(const unsigned char* octalCodeDestinati } void Application::pasteVoxels() { + pasteVoxels(_mouseVoxel); +} + +void Application::pasteVoxels(const VoxelDetail& sourceVoxel) { unsigned char* calculatedOctCode = NULL; - VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + VoxelTreeElement* selectedNode = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a @@ -1766,7 +1783,7 @@ void Application::pasteVoxels() { if (selectedNode) { octalCodeDestination = selectedNode->getOctalCode(); } else { - octalCodeDestination = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + octalCodeDestination = calculatedOctCode = pointToVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); } pasteVoxelsToOctalCode(octalCodeDestination); @@ -3789,18 +3806,27 @@ bool Application::maybeEditVoxelUnderCursor() { } void Application::deleteVoxelUnderCursor() { - if (_mouseVoxel.s != 0) { + deleteVoxelAt(_mouseVoxel); +} + +void Application::deleteVoxels(const VoxelDetail& voxel) { + deleteVoxelAt(voxel); +} + +void Application::deleteVoxelAt(const VoxelDetail& voxel) { + if (voxel.s != 0) { // sending delete to the server is sufficient, server will send new version so we see updates soon enough - _voxelEditSender.sendVoxelEditMessage(PacketTypeVoxelErase, _mouseVoxel); + _voxelEditSender.sendVoxelEditMessage(PacketTypeVoxelErase, voxel); // delete it locally to see the effect immediately (and in case no voxel server is present) - _voxels.deleteVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + _voxels.deleteVoxelAt(voxel.x, voxel.y, voxel.z, voxel.s); } // remember the position for drag detection _justEditedVoxel = true; } + void Application::eyedropperVoxelUnderCursor() { VoxelTreeElement* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode && selectedNode->isColored()) { @@ -4138,6 +4164,10 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->registerGlobalObject("Camera", cameraScriptable); connect(scriptEngine, SIGNAL(finished(const QString&)), cameraScriptable, SLOT(deleteLater())); + ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface(); + scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); + connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater())); + scriptEngine->registerGlobalObject("Overlays", &_overlays); QThread* workerThread = new QThread(this); diff --git a/interface/src/Application.h b/interface/src/Application.h index 0b6907e0f5..7de1b74609 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -222,13 +222,19 @@ public slots: void nodeKilled(SharedNodePointer node); void packetSent(quint64 length); - void exportVoxels(); - void importVoxels(); void cutVoxels(); void copyVoxels(); void pasteVoxels(); - void nudgeVoxels(); void deleteVoxels(); + void exportVoxels(); + void importVoxels(); + void nudgeVoxels(); + + void cutVoxels(const VoxelDetail& sourceVoxel); + void copyVoxels(const VoxelDetail& sourceVoxel); + void pasteVoxels(const VoxelDetail& sourceVoxel); + void deleteVoxels(const VoxelDetail& sourceVoxel); + void exportVoxels(const VoxelDetail& sourceVoxel); void setRenderVoxels(bool renderVoxels); void doKillLocalVoxels(); @@ -322,6 +328,7 @@ private: bool maybeEditVoxelUnderCursor(); void deleteVoxelUnderCursor(); + void deleteVoxelAt(const VoxelDetail& voxel); void eyedropperVoxelUnderCursor(); void setMenuShortcutsEnabled(bool enabled); diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp new file mode 100644 index 0000000000..c2a1a945a1 --- /dev/null +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -0,0 +1,59 @@ +// +// ClipboardScriptingInterface.cpp +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#include "Application.h" +#include "ClipboardScriptingInterface.h" + +ClipboardScriptingInterface::ClipboardScriptingInterface() { +} + +void ClipboardScriptingInterface::cutVoxels(float x, float y, float z, float s) { + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + Application::getInstance()->cutVoxels(sourceVoxel); +} + +void ClipboardScriptingInterface::copyVoxels(float x, float y, float z, float s) { + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + Application::getInstance()->copyVoxels(sourceVoxel); +} + +void ClipboardScriptingInterface::pasteVoxels(float x, float y, float z, float s) { + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + + Application::getInstance()->pasteVoxels(sourceVoxel); +} + +void ClipboardScriptingInterface::deleteVoxels(float x, float y, float z, float s) { + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + Application::getInstance()->deleteVoxels(sourceVoxel); +} + +void ClipboardScriptingInterface::exportVoxels(float x, float y, float z, float s) { + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + + Application::getInstance()->exportVoxels(sourceVoxel); +} + +void ClipboardScriptingInterface::importVoxels() { + Application::getInstance()->importVoxels(); +} + diff --git a/interface/src/ClipboardScriptingInterface.h b/interface/src/ClipboardScriptingInterface.h new file mode 100644 index 0000000000..0b2908f173 --- /dev/null +++ b/interface/src/ClipboardScriptingInterface.h @@ -0,0 +1,31 @@ +// +// ClipboardScriptingInterface.h +// interface +// +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// +// Scriptable interface for the Application clipboard +// + +#ifndef __interface__Clipboard__ +#define __interface__Clipboard__ + +#include +#include + +class ClipboardScriptingInterface : public QObject { + Q_OBJECT +public: + ClipboardScriptingInterface(); + +public slots: + void cutVoxels(float x, float y, float z, float s); + void copyVoxels(float x, float y, float z, float s); + void pasteVoxels(float x, float y, float z, float s); + void deleteVoxels(float x, float y, float z, float s); + + void exportVoxels(float x, float y, float z, float s); + void importVoxels(); +}; + +#endif // __interface__Clipboard__ diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index a6d3668207..90884f19f4 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -22,7 +22,7 @@ /// PacketTypeVoxelSet, PacketTypeVoxelSetDestructive, or PacketTypeVoxelErase. The buffer is returned to caller becomes /// responsibility of caller and MUST be deleted by caller. bool createVoxelEditMessage(PacketType command, short int sequence, - int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { + int voxelCount, const VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { bool success = true; // assume the best int messageSize = MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE; // just a guess for now @@ -102,7 +102,7 @@ bool encodeVoxelEditMessageDetails(PacketType, int voxelCount, VoxelDetail* voxe return success; } -void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, VoxelDetail& detail) { +void VoxelEditPacketSender::sendVoxelEditMessage(PacketType type, const VoxelDetail& detail) { // allows app to disable sending if for example voxels have been disabled if (!_shouldSend) { return; // bail early diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 90085635b0..4a1aa87a1c 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -19,7 +19,7 @@ class VoxelEditPacketSender : public OctreeEditPacketSender { Q_OBJECT public: /// Send voxel edit message immediately - void sendVoxelEditMessage(PacketType type, VoxelDetail& detail); + void sendVoxelEditMessage(PacketType type, const VoxelDetail& detail); /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to From 3bec67ecfd5ff369ec0aa2ae11bc0eeb937b64a2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 11:33:43 -0800 Subject: [PATCH 02/15] fix right mouse click --- libraries/script-engine/src/EventTypes.cpp | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 8fac2bcd2a..d0ba160add 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -262,10 +262,17 @@ MouseEvent::MouseEvent() : }; -MouseEvent::MouseEvent(const QMouseEvent& event) { - x = event.x(); - y = event.y(); - +MouseEvent::MouseEvent(const QMouseEvent& event) : + x(event.x()), + y(event.y()), + isLeftButton(event.buttons().testFlag(Qt::LeftButton)), + isRightButton(event.buttons().testFlag(Qt::RightButton)), + isMiddleButton(event.buttons().testFlag(Qt::MiddleButton)), + isShifted(event.modifiers().testFlag(Qt::ShiftModifier)), + isControl(event.modifiers().testFlag(Qt::ControlModifier)), + isMeta(event.modifiers().testFlag(Qt::MetaModifier)), + isAlt(event.modifiers().testFlag(Qt::AltModifier)) +{ // single button that caused the event switch (event.button()) { case Qt::LeftButton: @@ -284,16 +291,6 @@ MouseEvent::MouseEvent(const QMouseEvent& event) { button = "NONE"; break; } - // button pressed state - isLeftButton = isLeftButton || (event.buttons().testFlag(Qt::LeftButton)); - isRightButton = isRightButton || (event.buttons().testFlag(Qt::RightButton)); - isMiddleButton = isMiddleButton || (event.buttons().testFlag(Qt::MiddleButton)); - - // keyboard modifiers - isShifted = event.modifiers().testFlag(Qt::ShiftModifier); - isMeta = event.modifiers().testFlag(Qt::MetaModifier); - isControl = event.modifiers().testFlag(Qt::ControlModifier); - isAlt = event.modifiers().testFlag(Qt::AltModifier); } QScriptValue mouseEventToScriptValue(QScriptEngine* engine, const MouseEvent& event) { From 2a57080191390a863e1386f628e22af269da98b5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 15:06:10 -0800 Subject: [PATCH 03/15] add clipboard example --- examples/clipboardExample.js | 142 +++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 examples/clipboardExample.js diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js new file mode 100644 index 0000000000..c6864a91b3 --- /dev/null +++ b/examples/clipboardExample.js @@ -0,0 +1,142 @@ +// +// clipboardExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 1/28/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Clipboard class +// +// + +var selectedVoxel = { x: 0, y: 0, z: 0, s: 0 }; +var selectedSize = 4; + +function printKeyEvent(eventName, event) { + print(eventName); + print(" event.key=" + event.key); + print(" event.text=" + event.text); + print(" event.isShifted=" + event.isShifted); + print(" event.isControl=" + event.isControl); + print(" event.isMeta=" + event.isMeta); + print(" event.isAlt=" + event.isAlt); + print(" event.isKeypad=" + event.isKeypad); +} + + +function keyPressEvent(event) { + var debug = true; + if (debug) { + printKeyEvent("keyPressEvent", event); + } +} + +function keyReleaseEvent(event) { + var debug = false; + if (debug) { + printKeyEvent("keyReleaseEvent", event); + } + + // Note: this sample uses Alt+ as the key codes for these clipboard items + if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { + print("the Alt+C key was pressed"); + Clipboard.copyVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if ((event.key == 8776 || event.key == 88 || event.text == "X" || event.text == "x") && event.isAlt) { + print("the Alt+X key was pressed"); + Clipboard.cutVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if ((event.key == 8730 || event.key == 86 || event.text == "V" || event.text == "v") && event.isAlt) { + print("the Alt+V key was pressed"); + Clipboard.pasteVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if (event.text == "DELETE" || event.text == "BACKSPACE") { + print("the DELETE/BACKSPACE key was pressed"); + Clipboard.deleteVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { + print("the Alt+C key was pressed"); + Clipboard.copyVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } +} + +// Map keyPress and mouse move events to our callbacks +Controller.keyPressEvent.connect(keyPressEvent); +Controller.keyReleaseEvent.connect(keyReleaseEvent); + +var selectCube = Overlays.addOverlay("cube", { + position: { x: 0, y: 0, z: 0}, + size: selectedSize, + color: { red: 255, green: 255, blue: 0}, + alpha: 1, + solid: false, + visible: false, + lineWidth: 4 + }); + + +function mouseMoveEvent(event) { + + var pickRay = Camera.computePickRay(event.x, event.y); + + var debug = false; + if (debug) { + print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y); + print("called Camera.computePickRay()"); + print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z); + print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z); + } + + var intersection = Voxels.findRayIntersection(pickRay); + + if (intersection.intersects) { + if (debug) { + print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + + intersection.voxel.green + ", " + intersection.voxel.blue); + print("intersection voxel.x/y/z/s=" + intersection.voxel.x + ", " + + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); + print("intersection face=" + intersection.face); + print("intersection distance=" + intersection.distance); + print("intersection intersection.x/y/z=" + intersection.intersection.x + ", " + + intersection.intersection.y + ", " + intersection.intersection.z); + } + + + + var x = Math.floor(intersection.voxel.x / selectedSize) * selectedSize; + var y = Math.floor(intersection.voxel.y / selectedSize) * selectedSize; + var z = Math.floor(intersection.voxel.z / selectedSize) * selectedSize; + selectedVoxel = { x: x, y: y, z: z, s: selectedSize }; + Overlays.editOverlay(selectCube, { position: selectedVoxel, size: selectedSize, visible: true } ); + } else { + Overlays.editOverlay(selectCube, { visible: false } ); + selectedVoxel = { x: 0, y: 0, z: 0, s: 0 }; + } +} + +Controller.mouseMoveEvent.connect(mouseMoveEvent); + +function wheelEvent(event) { + var debug = false; + if (debug) { + print("wheelEvent"); + print(" event.x,y=" + event.x + ", " + event.y); + print(" event.delta=" + event.delta); + print(" event.orientation=" + event.orientation); + print(" event.isLeftButton=" + event.isLeftButton); + print(" event.isRightButton=" + event.isRightButton); + print(" event.isMiddleButton=" + event.isMiddleButton); + print(" event.isShifted=" + event.isShifted); + print(" event.isControl=" + event.isControl); + print(" event.isMeta=" + event.isMeta); + print(" event.isAlt=" + event.isAlt); + } +} + +Controller.wheelEvent.connect(wheelEvent); + +function scriptEnding() { + Overlays.deleteOverlay(selectCube); +} + +Script.scriptEnding.connect(scriptEnding); From 7662264af83d1d2e7d65df75bba13ba8aeed8617 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 17:48:38 -0800 Subject: [PATCH 04/15] more work on clipboard example --- examples/clipboardExample.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js index c6864a91b3..8afe5ad315 100644 --- a/examples/clipboardExample.js +++ b/examples/clipboardExample.js @@ -32,7 +32,7 @@ function keyPressEvent(event) { } function keyReleaseEvent(event) { - var debug = false; + var debug = true; if (debug) { printKeyEvent("keyReleaseEvent", event); } @@ -54,9 +54,14 @@ function keyReleaseEvent(event) { print("the DELETE/BACKSPACE key was pressed"); Clipboard.deleteVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { - print("the Alt+C key was pressed"); - Clipboard.copyVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + + if ((event.text == "E" || event.text == "e") && event.isMeta) { + print("the Ctl+E key was pressed"); + Clipboard.exportVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if ((event.text == "I" || event.text == "i") && event.isMeta) { + print("the Ctl+I key was pressed"); + Clipboard.importVoxels(); } } From f6fba54dda963cae9284f5a3b4ee18735886308a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 17:49:00 -0800 Subject: [PATCH 05/15] improved text mapping in keyboard events --- libraries/script-engine/src/EventTypes.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index d0ba160add..b06e53e0dd 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -104,6 +104,16 @@ KeyEvent::KeyEvent(const QKeyEvent& event) { text = "HELP"; } else if (key == Qt::Key_CapsLock) { text = "CAPS LOCK"; + } else if (key >= Qt::Key_A && key <= Qt::Key_Z && (isMeta || isControl || isAlt)) { + // this little bit of hacker will fix the text character keys like a-z in cases of control/alt/meta where + // qt doesn't always give you the key characters and will sometimes give you crazy non-printable characters + const int lowerCaseAdjust = 0x20; + QString unicode; + if (isShifted) { + text = QString(QChar(key)); + } else { + text = QString(QChar(key + lowerCaseAdjust)); + } } } From 91d79f65f203839c200d422d973873c7213b228d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 17:57:28 -0800 Subject: [PATCH 06/15] fix crash on import from JS --- examples/clipboardExample.js | 4 ++-- interface/src/ClipboardScriptingInterface.cpp | 4 +++- libraries/script-engine/src/EventTypes.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js index 8afe5ad315..e468c7ab95 100644 --- a/examples/clipboardExample.js +++ b/examples/clipboardExample.js @@ -25,14 +25,14 @@ function printKeyEvent(eventName, event) { function keyPressEvent(event) { - var debug = true; + var debug = false; if (debug) { printKeyEvent("keyPressEvent", event); } } function keyReleaseEvent(event) { - var debug = true; + var debug = false; if (debug) { printKeyEvent("keyReleaseEvent", event); } diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp index c2a1a945a1..7faedd1bce 100644 --- a/interface/src/ClipboardScriptingInterface.cpp +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -50,10 +50,12 @@ void ClipboardScriptingInterface::exportVoxels(float x, float y, float z, float z / (float)TREE_SCALE, s / (float)TREE_SCALE }; + // TODO: should we be calling invokeMethod() in all these cases? Application::getInstance()->exportVoxels(sourceVoxel); } void ClipboardScriptingInterface::importVoxels() { - Application::getInstance()->importVoxels(); + QMetaObject::invokeMethod(Application::getInstance(), "importVoxels"); } + diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index b06e53e0dd..c8451d84a7 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -105,7 +105,7 @@ KeyEvent::KeyEvent(const QKeyEvent& event) { } else if (key == Qt::Key_CapsLock) { text = "CAPS LOCK"; } else if (key >= Qt::Key_A && key <= Qt::Key_Z && (isMeta || isControl || isAlt)) { - // this little bit of hacker will fix the text character keys like a-z in cases of control/alt/meta where + // this little bit of hackery will fix the text character keys like a-z in cases of control/alt/meta where // qt doesn't always give you the key characters and will sometimes give you crazy non-printable characters const int lowerCaseAdjust = 0x20; QString unicode; From 0e8cab7349aa49d80e0c512ffba8b4088c7d2a4b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 20:09:35 -0800 Subject: [PATCH 07/15] added Clipboard.nudgeVoxel() and added support for calling clipboard opertations with VoxelDetail as well as xyzs --- examples/clipboardExample.js | 14 +++--- interface/src/Application.cpp | 12 +++--- interface/src/Application.h | 1 + interface/src/ClipboardScriptingInterface.cpp | 43 ++++++++++++++++--- interface/src/ClipboardScriptingInterface.h | 22 +++++++--- 5 files changed, 72 insertions(+), 20 deletions(-) diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js index e468c7ab95..81f0daae10 100644 --- a/examples/clipboardExample.js +++ b/examples/clipboardExample.js @@ -40,29 +40,33 @@ function keyReleaseEvent(event) { // Note: this sample uses Alt+ as the key codes for these clipboard items if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { print("the Alt+C key was pressed"); - Clipboard.copyVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if ((event.key == 8776 || event.key == 88 || event.text == "X" || event.text == "x") && event.isAlt) { print("the Alt+X key was pressed"); - Clipboard.cutVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if ((event.key == 8730 || event.key == 86 || event.text == "V" || event.text == "v") && event.isAlt) { print("the Alt+V key was pressed"); - Clipboard.pasteVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if (event.text == "DELETE" || event.text == "BACKSPACE") { print("the DELETE/BACKSPACE key was pressed"); - Clipboard.deleteVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if ((event.text == "E" || event.text == "e") && event.isMeta) { print("the Ctl+E key was pressed"); - Clipboard.exportVoxels(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } if ((event.text == "I" || event.text == "i") && event.isMeta) { print("the Ctl+I key was pressed"); Clipboard.importVoxels(); } + if ((event.key == 78 || event.text == "N" || event.text == "n") && event.isMeta) { + print("the Ctl+N key was pressed, nudging to left 1 meter"); + Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); + } } // Map keyPress and mouse move events to our callbacks diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index faa0a9cff0..dfd98863a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1847,12 +1847,14 @@ void Application::nudgeVoxels() { // calculate nudgeVec glm::vec3 nudgeVec(_nudgeGuidePosition.x - _nudgeVoxel.x, _nudgeGuidePosition.y - _nudgeVoxel.y, _nudgeGuidePosition.z - _nudgeVoxel.z); - VoxelTreeElement* nodeToNudge = _voxels.getVoxelAt(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s); + nudgeVoxelsByVector(_nudgeVoxel, nudgeVec); + } +} - if (nodeToNudge) { - _voxels.getTree()->nudgeSubTree(nodeToNudge, nudgeVec, _voxelEditSender); - _nudgeStarted = false; - } +void Application::nudgeVoxelsByVector(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { + VoxelTreeElement* nodeToNudge = _voxels.getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); + if (nodeToNudge) { + _voxels.getTree()->nudgeSubTree(nodeToNudge, nudgeVec, _voxelEditSender); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index d5e1e25f62..abe51b8bb1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -240,6 +240,7 @@ public slots: void pasteVoxels(const VoxelDetail& sourceVoxel); void deleteVoxels(const VoxelDetail& sourceVoxel); void exportVoxels(const VoxelDetail& sourceVoxel); + void nudgeVoxelsByVector(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); void setRenderVoxels(bool renderVoxels); void doKillLocalVoxels(); diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp index 7faedd1bce..644ea84cdb 100644 --- a/interface/src/ClipboardScriptingInterface.cpp +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -11,7 +11,11 @@ ClipboardScriptingInterface::ClipboardScriptingInterface() { } -void ClipboardScriptingInterface::cutVoxels(float x, float y, float z, float s) { +void ClipboardScriptingInterface::cutVoxel(const VoxelDetail& sourceVoxel) { + cutVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); +} + +void ClipboardScriptingInterface::cutVoxel(float x, float y, float z, float s) { VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, @@ -19,7 +23,11 @@ void ClipboardScriptingInterface::cutVoxels(float x, float y, float z, float s) Application::getInstance()->cutVoxels(sourceVoxel); } -void ClipboardScriptingInterface::copyVoxels(float x, float y, float z, float s) { +void ClipboardScriptingInterface::copyVoxel(const VoxelDetail& sourceVoxel) { + copyVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); +} + +void ClipboardScriptingInterface::copyVoxel(float x, float y, float z, float s) { VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, @@ -27,7 +35,11 @@ void ClipboardScriptingInterface::copyVoxels(float x, float y, float z, float s) Application::getInstance()->copyVoxels(sourceVoxel); } -void ClipboardScriptingInterface::pasteVoxels(float x, float y, float z, float s) { +void ClipboardScriptingInterface::pasteVoxel(const VoxelDetail& destinationVoxel) { + pasteVoxel(destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); +} + +void ClipboardScriptingInterface::pasteVoxel(float x, float y, float z, float s) { VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, @@ -36,7 +48,11 @@ void ClipboardScriptingInterface::pasteVoxels(float x, float y, float z, float s Application::getInstance()->pasteVoxels(sourceVoxel); } -void ClipboardScriptingInterface::deleteVoxels(float x, float y, float z, float s) { +void ClipboardScriptingInterface::deleteVoxel(const VoxelDetail& sourceVoxel) { + deleteVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); +} + +void ClipboardScriptingInterface::deleteVoxel(float x, float y, float z, float s) { VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, @@ -44,7 +60,11 @@ void ClipboardScriptingInterface::deleteVoxels(float x, float y, float z, float Application::getInstance()->deleteVoxels(sourceVoxel); } -void ClipboardScriptingInterface::exportVoxels(float x, float y, float z, float s) { +void ClipboardScriptingInterface::exportVoxel(const VoxelDetail& sourceVoxel) { + exportVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s); +} + +void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s) { VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, y / (float)TREE_SCALE, z / (float)TREE_SCALE, @@ -58,4 +78,17 @@ void ClipboardScriptingInterface::importVoxels() { QMetaObject::invokeMethod(Application::getInstance(), "importVoxels"); } +void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { + nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); +} + +void ClipboardScriptingInterface::nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec) { + glm::vec3 nudgeVecInTreeSpace = nudgeVec / (float)TREE_SCALE; + VoxelDetail sourceVoxel = { x / (float)TREE_SCALE, + y / (float)TREE_SCALE, + z / (float)TREE_SCALE, + s / (float)TREE_SCALE }; + + Application::getInstance()->nudgeVoxelsByVector(sourceVoxel, nudgeVecInTreeSpace); +} diff --git a/interface/src/ClipboardScriptingInterface.h b/interface/src/ClipboardScriptingInterface.h index 0b2908f173..99747f56f6 100644 --- a/interface/src/ClipboardScriptingInterface.h +++ b/interface/src/ClipboardScriptingInterface.h @@ -19,13 +19,25 @@ public: ClipboardScriptingInterface(); public slots: - void cutVoxels(float x, float y, float z, float s); - void copyVoxels(float x, float y, float z, float s); - void pasteVoxels(float x, float y, float z, float s); - void deleteVoxels(float x, float y, float z, float s); + void cutVoxel(const VoxelDetail& sourceVoxel); + void cutVoxel(float x, float y, float z, float s); + + void copyVoxel(const VoxelDetail& sourceVoxel); + void copyVoxel(float x, float y, float z, float s); + + void pasteVoxel(const VoxelDetail& destinationVoxel); + void pasteVoxel(float x, float y, float z, float s); + + void deleteVoxel(const VoxelDetail& sourceVoxel); + void deleteVoxel(float x, float y, float z, float s); + + void exportVoxel(const VoxelDetail& sourceVoxel); + void exportVoxel(float x, float y, float z, float s); - void exportVoxels(float x, float y, float z, float s); void importVoxels(); + + void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); + void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); }; #endif // __interface__Clipboard__ From f506c215907042a731209b86a2ace812cb247415 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 20:57:58 -0800 Subject: [PATCH 08/15] add line preview mode to editVoxels.js and make that the default mode --- examples/editVoxels.js | 295 +++++++++++++++++++++++++++++++---------- 1 file changed, 224 insertions(+), 71 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index c67ff0dcfa..f5d8612be9 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -72,6 +72,10 @@ audioOptions.volume = 0.5; var editToolsOn = false; // starts out off +// previewAsVoxel - by default, we will preview adds/deletes/recolors as just 4 lines on the intersecting face. But if you +// the preview to show a full voxel then set this to true and the voxel will be displayed for voxel editing +var previewAsVoxel = false; + var voxelPreview = Overlays.addOverlay("cube", { position: { x: 0, y: 0, z: 0}, size: 1, @@ -81,6 +85,42 @@ var voxelPreview = Overlays.addOverlay("cube", { visible: false, lineWidth: 4 }); + +var linePreviewTop = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false, + lineWidth: 1 + }); + +var linePreviewBottom = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false, + lineWidth: 1 + }); + +var linePreviewLeft = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false, + lineWidth: 1 + }); + +var linePreviewRight = Overlays.addOverlay("line3d", { + position: { x: 0, y: 0, z: 0}, + end: { x: 0, y: 0, z: 0}, + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false, + lineWidth: 1 + }); // These will be our "overlay IDs" @@ -146,83 +186,186 @@ var trackAsDelete = false; var trackAsRecolor = false; function showPreviewVoxel() { - if (editToolsOn) { - var voxelColor; + var voxelColor; - var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); - var intersection = Voxels.findRayIntersection(pickRay); + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + var intersection = Voxels.findRayIntersection(pickRay); - if (whichColor == -1) { - // Copy mode - use clicked voxel color - voxelColor = { red: intersection.voxel.red, - green: intersection.voxel.green, - blue: intersection.voxel.blue }; - } else { - voxelColor = { red: colors[whichColor].red, - green: colors[whichColor].green, - blue: colors[whichColor].blue }; + if (whichColor == -1) { + // Copy mode - use clicked voxel color + voxelColor = { red: intersection.voxel.red, + green: intersection.voxel.green, + blue: intersection.voxel.blue }; + } else { + voxelColor = { red: colors[whichColor].red, + green: colors[whichColor].green, + blue: colors[whichColor].blue }; + } + + var guidePosition; + + if (trackAsDelete) { + guidePosition = { x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z }; + + Overlays.editOverlay(voxelPreview, { + position: guidePosition, + size: intersection.voxel.s, + visible: true, + color: { red: 255, green: 0, blue: 0 }, + solid: false, + alpha: 1 + }); + } else if (trackAsRecolor) { + guidePosition = { x: intersection.voxel.x - 0.001, + y: intersection.voxel.y - 0.001, + z: intersection.voxel.z - 0.001 }; + + Overlays.editOverlay(voxelPreview, { + position: guidePosition, + size: intersection.voxel.s + 0.002, + visible: true, + color: voxelColor, + solid: true, + alpha: 0.8 + }); + } else if (!isExtruding) { + guidePosition = { x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z }; + + if (intersection.face == "MIN_X_FACE") { + guidePosition.x -= intersection.voxel.s; + } else if (intersection.face == "MAX_X_FACE") { + guidePosition.x += intersection.voxel.s; + } else if (intersection.face == "MIN_Y_FACE") { + guidePosition.y -= intersection.voxel.s; + } else if (intersection.face == "MAX_Y_FACE") { + guidePosition.y += intersection.voxel.s; + } else if (intersection.face == "MIN_Z_FACE") { + guidePosition.z -= intersection.voxel.s; + } else if (intersection.face == "MAX_Z_FACE") { + guidePosition.z += intersection.voxel.s; } - var guidePosition; - - if (trackAsDelete) { - guidePosition = { x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z }; - Overlays.editOverlay(voxelPreview, { - position: guidePosition, - size: intersection.voxel.s, - visible: true, - color: { red: 255, green: 0, blue: 0 }, - solid: false, - alpha: 1 - }); - } else if (trackAsRecolor) { - guidePosition = { x: intersection.voxel.x - 0.001, - y: intersection.voxel.y - 0.001, - z: intersection.voxel.z - 0.001 }; + Overlays.editOverlay(voxelPreview, { + position: guidePosition, + size: intersection.voxel.s, + visible: true, + color: voxelColor, + solid: true, + alpha: 0.7 + }); + } else if (isExtruding) { + Overlays.editOverlay(voxelPreview, { visible: false }); + } +} - Overlays.editOverlay(voxelPreview, { - position: guidePosition, - size: intersection.voxel.s + 0.002, - visible: true, - color: voxelColor, - solid: true, - alpha: 0.8 - }); - } else if (!isExtruding) { - guidePosition = { x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z }; - - if (intersection.face == "MIN_X_FACE") { - guidePosition.x -= intersection.voxel.s; - } else if (intersection.face == "MAX_X_FACE") { - guidePosition.x += intersection.voxel.s; - } else if (intersection.face == "MIN_Y_FACE") { - guidePosition.y -= intersection.voxel.s; - } else if (intersection.face == "MAX_Y_FACE") { - guidePosition.y += intersection.voxel.s; - } else if (intersection.face == "MIN_Z_FACE") { - guidePosition.z -= intersection.voxel.s; - } else if (intersection.face == "MAX_Z_FACE") { - guidePosition.z += intersection.voxel.s; - } +function showPreviewLines() { + var voxelColor; - Overlays.editOverlay(voxelPreview, { - position: guidePosition, - size: intersection.voxel.s, - visible: true, - color: voxelColor, - solid: true, - alpha: 0.7 - }); - } else if (isExtruding) { + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + var intersection = Voxels.findRayIntersection(pickRay); + + if (intersection.intersects) { + + // TODO: add support for changing size here + var previewVoxelSize = intersection.voxel.s; + + var x = Math.floor(intersection.intersection.x / previewVoxelSize) * previewVoxelSize; + var y = Math.floor(intersection.intersection.y / previewVoxelSize) * previewVoxelSize; + var z = Math.floor(intersection.intersection.z / previewVoxelSize) * previewVoxelSize; + previewVoxel = { x: x, y: y, z: z, s: previewVoxelSize }; + + var bottomLeft; + var bottomRight; + var topLeft; + var topRight; + + if (intersection.face == "MIN_X_FACE") { + + bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; + topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; + topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z + previewVoxel.s }; + + } else if (intersection.face == "MAX_X_FACE") { + + // because we intersected with the MAX_X face, our previewVoxel will be the voxel to the +X side of the + // voxel we intersect, so we don't need to adjust the x coordinates + bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; + topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; + topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z + previewVoxel.s }; + + } else if (intersection.face == "MIN_Y_FACE") { + + bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; + topRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; + + } else if (intersection.face == "MAX_Y_FACE") { + + bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; + topRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; + + } else if (intersection.face == "MIN_Z_FACE") { + + bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; + topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; + + } else if (intersection.face == "MAX_Z_FACE") { + + bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; + bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; + topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; + topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; + + } + + Overlays.editOverlay(linePreviewTop, { position: topLeft, end: topRight, visible: true }); + Overlays.editOverlay(linePreviewBottom, { position: bottomLeft, end: bottomRight, visible: true }); + Overlays.editOverlay(linePreviewLeft, { position: topLeft, end: bottomLeft, visible: true }); + Overlays.editOverlay(linePreviewRight, { position: topRight, end: bottomRight, visible: true }); + + } else { + Overlays.editOverlay(linePreviewTop, { visible: false }); + Overlays.editOverlay(linePreviewBottom, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + Overlays.editOverlay(linePreviewRight, { visible: false }); + } +} + +function showPreviewGuides() { + if (editToolsOn) { + if (previewAsVoxel) { + showPreviewVoxel(); + + // make sure alternative is hidden + Overlays.editOverlay(linePreviewTop, { visible: false }); + Overlays.editOverlay(linePreviewBottom, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + Overlays.editOverlay(linePreviewRight, { visible: false }); + } else { + showPreviewLines(); + + // make sure alternative is hidden Overlays.editOverlay(voxelPreview, { visible: false }); } } else { + // make sure all previews are off Overlays.editOverlay(voxelPreview, { visible: false }); + Overlays.editOverlay(linePreviewTop, { visible: false }); + Overlays.editOverlay(linePreviewBottom, { visible: false }); + Overlays.editOverlay(linePreviewLeft, { visible: false }); + Overlays.editOverlay(linePreviewRight, { visible: false }); } } @@ -231,24 +374,24 @@ function trackMouseEvent(event) { trackLastMouseY = event.y; trackAsDelete = event.isControl; trackAsRecolor = event.isShifted; - showPreviewVoxel(); + showPreviewGuides(); } function trackKeyPressEvent(event) { if (event.text == "CONTROL") { trackAsDelete = true; - showPreviewVoxel(); + showPreviewGuides(); } if (event.text == "SHIFT") { trackAsRecolor = true; } - showPreviewVoxel(); + showPreviewGuides(); } function trackKeyReleaseEvent(event) { if (event.text == "CONTROL") { trackAsDelete = false; - showPreviewVoxel(); + showPreviewGuides(); } if (event.text == "SHIFT") { trackAsRecolor = false; @@ -260,7 +403,13 @@ function trackKeyReleaseEvent(event) { moveTools(); Audio.playSound(clickSound, audioOptions); } - showPreviewVoxel(); + + // on F1 toggle the preview mode between cubes and lines + if (event.text == "F1") { + previewAsVoxel = !previewAsVoxel; + } + + showPreviewGuides(); } function mousePressEvent(event) { @@ -533,6 +682,10 @@ Controller.keyReleaseEvent.connect(keyReleaseEvent); function scriptEnding() { Overlays.deleteOverlay(voxelPreview); + Overlays.deleteOverlay(linePreviewTop); + Overlays.deleteOverlay(linePreviewBottom); + Overlays.deleteOverlay(linePreviewLeft); + Overlays.deleteOverlay(linePreviewRight); for (s = 0; s < numColors; s++) { Overlays.deleteOverlay(swatches[s]); } From cbf1b095524d5e4ee4f93204f5f6cb73079013ae Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 21:07:52 -0800 Subject: [PATCH 09/15] fix small bug in line preview mode --- examples/editVoxels.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index f5d8612be9..db6091f245 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -271,8 +271,9 @@ function showPreviewLines() { if (intersection.intersects) { - // TODO: add support for changing size here - var previewVoxelSize = intersection.voxel.s; + // TODO: add support for changing size here, if you set this size to any arbitrary size, + // the preview should correctly handle it + var previewVoxelSize = intersection.voxel.s; var x = Math.floor(intersection.intersection.x / previewVoxelSize) * previewVoxelSize; var y = Math.floor(intersection.intersection.y / previewVoxelSize) * previewVoxelSize; @@ -285,16 +286,14 @@ function showPreviewLines() { var topRight; if (intersection.face == "MIN_X_FACE") { - + previewVoxel.x = Math.floor(intersection.voxel.x / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z + previewVoxel.s }; } else if (intersection.face == "MAX_X_FACE") { - - // because we intersected with the MAX_X face, our previewVoxel will be the voxel to the +X side of the - // voxel we intersect, so we don't need to adjust the x coordinates + previewVoxel.x = Math.floor((intersection.voxel.x + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; @@ -302,6 +301,7 @@ function showPreviewLines() { } else if (intersection.face == "MIN_Y_FACE") { + previewVoxel.y = Math.floor(intersection.voxel.y / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; @@ -309,6 +309,7 @@ function showPreviewLines() { } else if (intersection.face == "MAX_Y_FACE") { + previewVoxel.y = Math.floor((intersection.voxel.y + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; @@ -316,6 +317,7 @@ function showPreviewLines() { } else if (intersection.face == "MIN_Z_FACE") { + previewVoxel.z = Math.floor(intersection.voxel.z / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; @@ -323,6 +325,7 @@ function showPreviewLines() { } else if (intersection.face == "MAX_Z_FACE") { + previewVoxel.z = Math.floor((intersection.voxel.z + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; From 61d9ea44af782f06b15ffc75f7b7922400941af5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 22:17:19 -0800 Subject: [PATCH 10/15] add tool palette and eye dropper mode --- examples/editVoxels.js | 149 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 143 insertions(+), 6 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index db6091f245..d15c9d33d9 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -155,6 +155,68 @@ for (s = 0; s < numColors; s++) { } +// These will be our tool palette overlays +var numberOfTools = 5; +var toolHeight = 40; +var toolWidth = 62; +var toolsHeight = toolHeight * numberOfTools; +var toolsX = 0; +var toolsY = (windowDimensions.y - toolsHeight) / 2; + +var addToolAt = 0; +var deleteToolAt = 1; +var recolorToolAt = 2; +var eyedropperToolAt = 3; +var selectToolAt = 4; +var toolSelectedColor = { red: 255, green: 255, blue: 255 }; +var notSelectedColor = { red: 128, green: 128, blue: 128 }; + +var addTool = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight * addToolAt, width: toolWidth, height: toolHeight }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + color: toolSelectedColor, + visible: false, + alpha: 0.9 + }); + +var deleteTool = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight * deleteToolAt, width: toolWidth, height: toolHeight }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + color: toolSelectedColor, + visible: false, + alpha: 0.9 + }); + +var recolorTool = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight * recolorToolAt, width: toolWidth, height: toolHeight }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + color: toolSelectedColor, + visible: false, + alpha: 0.9 + }); + +var eyedropperTool = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight * eyedropperToolAt, width: toolWidth, height: toolHeight }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + color: toolSelectedColor, + visible: false, + alpha: 0.9 + }); + +var selectTool = Overlays.addOverlay("image", { + x: 0, y: 0, width: toolWidth, height: toolHeight, + subImage: { x: 0, y: toolHeight * selectToolAt, width: toolWidth, height: toolHeight }, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/hifi-interface-tools.svg", + color: toolSelectedColor, + visible: false, + alpha: 0.9 + }); + + function setAudioPosition() { var camera = Camera.getPosition(); var forwardVector = Quat.getFront(MyAvatar.orientation); @@ -184,6 +246,7 @@ var trackLastMouseX = 0; var trackLastMouseY = 0; var trackAsDelete = false; var trackAsRecolor = false; +var trackAsEyedropper = false; function showPreviewVoxel() { var voxelColor; @@ -217,7 +280,7 @@ function showPreviewVoxel() { solid: false, alpha: 1 }); - } else if (trackAsRecolor) { + } else if (trackAsRecolor || trackAsEyedropper) { guidePosition = { x: intersection.voxel.x - 0.001, y: intersection.voxel.y - 0.001, z: intersection.voxel.z - 0.001 }; @@ -264,7 +327,6 @@ function showPreviewVoxel() { function showPreviewLines() { - var voxelColor; var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); var intersection = Voxels.findRayIntersection(pickRay); @@ -377,16 +439,22 @@ function trackMouseEvent(event) { trackLastMouseY = event.y; trackAsDelete = event.isControl; trackAsRecolor = event.isShifted; + trackAsEyedropper = event.isMeta; showPreviewGuides(); } function trackKeyPressEvent(event) { if (event.text == "CONTROL") { trackAsDelete = true; - showPreviewGuides(); + moveTools(); } if (event.text == "SHIFT") { trackAsRecolor = true; + moveTools(); + } + if (event.text == "META") { + trackAsEyedropper = true; + moveTools(); } showPreviewGuides(); } @@ -394,10 +462,15 @@ function trackKeyPressEvent(event) { function trackKeyReleaseEvent(event) { if (event.text == "CONTROL") { trackAsDelete = false; - showPreviewGuides(); + moveTools(); } if (event.text == "SHIFT") { trackAsRecolor = false; + moveTools(); + } + if (event.text == "META") { + trackAsEyedropper = false; + moveTools(); } // on TAB release, toggle our tool state @@ -447,12 +520,21 @@ function mousePressEvent(event) { orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); - } else if (trackAsDelete || event.isRightButton) { + } else if (trackAsDelete || (event.isRightButton && !trackAsEyedropper)) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); - + } else if (trackAsEyedropper) { + + print("Grab color!!!"); + if (whichColor != -1) { + colors[whichColor].red = intersection.voxel.red; + colors[whichColor].green = intersection.voxel.green; + colors[whichColor].blue = intersection.voxel.blue; + moveTools(); + } + } else if (trackAsRecolor) { // Recolor Voxel Voxels.setVoxel(intersection.voxel.x, @@ -643,6 +725,7 @@ function mouseReleaseEvent(event) { } function moveTools() { + // move the swatches swatchesX = (windowDimensions.x - swatchesWidth) / 2; swatchesY = windowDimensions.y - swatchHeight; @@ -665,6 +748,55 @@ function moveTools() { visible: editToolsOn }); } + + // move the tools + toolsY = (windowDimensions.y - toolsHeight) / 2; + addToolColor = notSelectedColor; + deleteToolColor = notSelectedColor; + recolorToolColor = notSelectedColor; + eyedropperToolColor = notSelectedColor; + selectToolColor = notSelectedColor; + + if (trackAsDelete) { + deleteToolColor = toolSelectedColor; + } else if (trackAsRecolor) { + recolorToolColor = toolSelectedColor; + } else if (trackAsEyedropper) { + eyedropperToolColor = toolSelectedColor; + } else { + addToolColor = toolSelectedColor; + } + + Overlays.editOverlay(addTool, { + x: 0, y: toolsY + (toolHeight * addToolAt), width: toolWidth, height: toolHeight, + color: addToolColor, + visible: editToolsOn + }); + + Overlays.editOverlay(deleteTool, { + x: 0, y: toolsY + (toolHeight * deleteToolAt), width: toolWidth, height: toolHeight, + color: deleteToolColor, + visible: editToolsOn + }); + + Overlays.editOverlay(recolorTool, { + x: 0, y: toolsY + (toolHeight * recolorToolAt), width: toolWidth, height: toolHeight, + color: recolorToolColor, + visible: editToolsOn + }); + + Overlays.editOverlay(eyedropperTool, { + x: 0, y: toolsY + (toolHeight * eyedropperToolAt), width: toolWidth, height: toolHeight, + color: eyedropperToolColor, + visible: editToolsOn + }); + + Overlays.editOverlay(selectTool, { + x: 0, y: toolsY + (toolHeight * selectToolAt), width: toolWidth, height: toolHeight, + color: selectToolColor, + visible: editToolsOn + }); + } @@ -692,6 +824,11 @@ function scriptEnding() { for (s = 0; s < numColors; s++) { Overlays.deleteOverlay(swatches[s]); } + Overlays.deleteOverlay(addTool); + Overlays.deleteOverlay(deleteTool); + Overlays.deleteOverlay(recolorTool); + Overlays.deleteOverlay(eyedropperTool); + Overlays.deleteOverlay(selectTool); } Script.scriptEnding.connect(scriptEnding); From cbacf5f328ef4742a3268d5891edfc46d08cd2b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 22:30:28 -0800 Subject: [PATCH 11/15] correctly draw tools when in orbit mode --- examples/editVoxels.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index d15c9d33d9..eea5faf1fc 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -247,6 +247,7 @@ var trackLastMouseY = 0; var trackAsDelete = false; var trackAsRecolor = false; var trackAsEyedropper = false; +var trackAsOrbit = false; function showPreviewVoxel() { var voxelColor; @@ -293,6 +294,8 @@ function showPreviewVoxel() { solid: true, alpha: 0.8 }); + } else if (trackAsOrbit) { + Overlays.editOverlay(voxelPreview, { visible: false }); } else if (!isExtruding) { guidePosition = { x: intersection.voxel.x, y: intersection.voxel.y, @@ -440,6 +443,7 @@ function trackMouseEvent(event) { trackAsDelete = event.isControl; trackAsRecolor = event.isShifted; trackAsEyedropper = event.isMeta; + trackAsOrbit = event.isAlt; showPreviewGuides(); } @@ -456,6 +460,10 @@ function trackKeyPressEvent(event) { trackAsEyedropper = true; moveTools(); } + if (event.text == "ALT") { + trackAsOrbit = true; + moveTools(); + } showPreviewGuides(); } @@ -472,6 +480,10 @@ function trackKeyReleaseEvent(event) { trackAsEyedropper = false; moveTools(); } + if (event.text == "ALT") { + trackAsOrbit = false; + moveTools(); + } // on TAB release, toggle our tool state if (event.text == "TAB") { @@ -763,6 +775,8 @@ function moveTools() { recolorToolColor = toolSelectedColor; } else if (trackAsEyedropper) { eyedropperToolColor = toolSelectedColor; + } else if (trackAsOrbit) { + // nothing gets selected in this case... } else { addToolColor = toolSelectedColor; } From 546ab51ed58f0165e4d528a8c06dafc9d927e093 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 22:37:43 -0800 Subject: [PATCH 12/15] add click support to color swatchs in editVoxels.js --- examples/editVoxels.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index eea5faf1fc..82481a84e6 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -506,11 +506,23 @@ function mousePressEvent(event) { if (!editToolsOn) { return; } - - if (event.isRightButton) { - // debugging of right button click on mac... - print(">>>> RIGHT BUTTON <<<<<"); + + var clickedOnSwatch = false; + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + // if the user clicked on one of the color swatches, update the selectedSwatch + for (s = 0; s < numColors; s++) { + if (clickedOverlay == swatches[s]) { + whichColor = s; + moveTools(); + clickedOnSwatch = true; + } } + if (clickedOnSwatch) { + return; // no further processing + } + + trackMouseEvent(event); // used by preview support mouseX = event.x; mouseY = event.y; From 66d757863cc673db0b42c9d03412b1cea9f0f364 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 19 Feb 2014 23:52:29 -0800 Subject: [PATCH 13/15] adding first cut at voxel size slider to editVoxels.js --- examples/editVoxels.js | 145 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 129 insertions(+), 16 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 82481a84e6..001f74a563 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -123,12 +123,16 @@ var linePreviewRight = Overlays.addOverlay("line3d", { }); +// these will be used below +var sliderWidth = 158; +var sliderHeight = 35; + // These will be our "overlay IDs" var swatches = new Array(); var swatchHeight = 54; var swatchWidth = 31; var swatchesWidth = swatchWidth * numColors; -var swatchesX = (windowDimensions.x - swatchesWidth) / 2; +var swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2; var swatchesY = windowDimensions.y - swatchHeight; // create the overlays, position them in a row, set their colors, and for the selected one, use a different source image @@ -215,6 +219,69 @@ var selectTool = Overlays.addOverlay("image", { visible: false, alpha: 0.9 }); + + +// This will create a couple of image overlays that make a "slider", we will demonstrate how to trap mouse messages to +// move the slider + +// see above... +//var sliderWidth = 158; +//var sliderHeight = 35; + +var sliderX = swatchesX + swatchesWidth; +var sliderY = windowDimensions.y - sliderHeight; +var slider = Overlays.addOverlay("image", { + // alternate form of expressing bounds + bounds: { x: sliderX, y: sliderY, width: sliderWidth, height: sliderHeight}, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/slider.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false + }); + + +// The slider is handled in the mouse event callbacks. +var isMovingSlider = false; +var thumbClickOffsetX = 0; + +// This is the thumb of our slider +var minThumbX = 30; // relative to the x of the slider +var maxThumbX = minThumbX + 65; +var thumbX = (minThumbX + maxThumbX) / 2; +var thumbY = sliderY + 9; +var thumb = Overlays.addOverlay("image", { + x: sliderX + thumbX, + y: thumbY, + width: 18, + height: 17, + imageURL: "https://s3-us-west-1.amazonaws.com/highfidelity-public/images/thumb.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false + }); + +var pointerVoxelScale = 0; // this is the voxel scale used for click to add or delete +var pointerVoxelScaleSet = false; // if voxel scale has not yet been set, we use the intersection size + +var pointerVoxelScaleSteps = 10; // the number of slider position steps +var pointerVoxelScaleOriginStep = 4; // the position of slider for the 1 meter size voxel +var pointerVoxelScaleMin = Math.pow(2, (1-pointerVoxelScaleOriginStep)); +var pointerVoxelScaleMax = Math.pow(2, (pointerVoxelScaleSteps-pointerVoxelScaleOriginStep)); + +function calcThumbFromScale(scale) { + var scaleLog = Math.log(scale)/Math.log(2); + var thumbStep = scaleLog + pointerVoxelScaleOriginStep; + if (thumbStep < 1) { + thumbStep = 1; + } + if (thumbStep > pointerVoxelScaleSteps) { + thumbStep = pointerVoxelScaleSteps; + } + thumbX = (((maxThumbX - minThumbX) / pointerVoxelScaleSteps) * (thumbStep - 1)) + minThumbX; + Overlays.editOverlay(thumb, { x: thumbX + sliderX } ); +} + + function setAudioPosition() { @@ -255,6 +322,11 @@ function showPreviewVoxel() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); var intersection = Voxels.findRayIntersection(pickRay); + // if the user hasn't updated the + if (!pointerVoxelScaleSet) { + calcThumbFromScale(intersection.voxel.s); + } + if (whichColor == -1) { // Copy mode - use clicked voxel color voxelColor = { red: intersection.voxel.red, @@ -335,6 +407,11 @@ function showPreviewLines() { var intersection = Voxels.findRayIntersection(pickRay); if (intersection.intersects) { + + // if the user hasn't updated the + if (!pointerVoxelScaleSet) { + calcThumbFromScale(intersection.voxel.s); + } // TODO: add support for changing size here, if you set this size to any arbitrary size, // the preview should correctly handle it @@ -509,17 +586,24 @@ function mousePressEvent(event) { var clickedOnSwatch = false; var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - - // if the user clicked on one of the color swatches, update the selectedSwatch - for (s = 0; s < numColors; s++) { - if (clickedOverlay == swatches[s]) { - whichColor = s; - moveTools(); - clickedOnSwatch = true; - } - } - if (clickedOnSwatch) { + + // If the user clicked on the thumb, handle the slider logic + if (clickedOverlay == thumb) { + isMovingSlider = true; + thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb return; // no further processing + } else { + // if the user clicked on one of the color swatches, update the selectedSwatch + for (s = 0; s < numColors; s++) { + if (clickedOverlay == swatches[s]) { + whichColor = s; + moveTools(); + clickedOnSwatch = true; + } + } + if (clickedOnSwatch) { + return; // no further processing + } } @@ -530,6 +614,11 @@ function mousePressEvent(event) { var intersection = Voxels.findRayIntersection(pickRay); audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); if (intersection.intersects) { + // if the user hasn't updated the + if (!pointerVoxelScaleSet) { + calcThumbFromScale(intersection.voxel.s); + } + if (event.isAlt) { // start orbit camera! var cameraPosition = Camera.getPosition(); @@ -668,8 +757,21 @@ function keyReleaseEvent(event) { key_alt = false; key_shift = false; } + + function mouseMoveEvent(event) { - if (isOrbiting) { + if (isMovingSlider) { + thumbX = (event.x - thumbClickOffsetX) - sliderX; + if (thumbX < minThumbX) { + thumbX = minThumbX; + } + if (thumbX > maxThumbX) { + thumbX = maxThumbX; + } + // TODO: hook this up to the voxel size in some meaningful way + Overlays.editOverlay(thumb, { x: thumbX + sliderX } ); + + } else if (isOrbiting) { var cameraOrientation = Camera.getOrientation(); var origEulers = Quat.safeEulerAngles(cameraOrientation); var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); @@ -684,8 +786,7 @@ function mouseMoveEvent(event) { Camera.setPosition(orbitPosition); mouseX = event.x; mouseY = event.y; - } - if (isAdding) { + } else if (isAdding) { // Watch the drag direction to tell which way to 'extrude' this voxel if (!isExtruding) { var pickRay = Camera.computePickRay(event.x, event.y); @@ -734,6 +835,10 @@ function mouseReleaseEvent(event) { return; } + if (isMovingSlider) { + isMovingSlider = false; + } + if (isOrbiting) { var cameraOrientation = Camera.getOrientation(); var eulers = Quat.safeEulerAngles(cameraOrientation); @@ -750,7 +855,7 @@ function mouseReleaseEvent(event) { function moveTools() { // move the swatches - swatchesX = (windowDimensions.x - swatchesWidth) / 2; + swatchesX = (windowDimensions.x - (swatchesWidth + sliderWidth)) / 2; swatchesY = windowDimensions.y - swatchHeight; // create the overlays, position them in a row, set their colors, and for the selected one, use a different source image @@ -823,6 +928,15 @@ function moveTools() { visible: editToolsOn }); + + sliderX = swatchesX + swatchesWidth; + sliderY = windowDimensions.y - sliderHeight; + Overlays.editOverlay(slider, { x: sliderX, y: sliderY, visible: editToolsOn }); + + // This is the thumb of our slider + thumbY = sliderY + 9; + Overlays.editOverlay(thumb, { x: sliderX + thumbX, y: thumbY, visible: editToolsOn }); + } @@ -830,7 +944,6 @@ function update() { var newWindowDimensions = Controller.getViewportDimensions(); if (newWindowDimensions.x != windowDimensions.x || newWindowDimensions.y != windowDimensions.y) { windowDimensions = newWindowDimensions; - print("window resized..."); moveTools(); } } From 7cab5013cc5af2aaf8ed14a9e34e93d6ad4c4aea Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Feb 2014 01:20:56 -0800 Subject: [PATCH 14/15] more work to wire up voxel size slider and +/- keys --- examples/editVoxels.js | 79 ++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 001f74a563..8ac22413b3 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -247,6 +247,7 @@ var thumbClickOffsetX = 0; // This is the thumb of our slider var minThumbX = 30; // relative to the x of the slider var maxThumbX = minThumbX + 65; +var thumbExtents = maxThumbX - minThumbX; var thumbX = (minThumbX + maxThumbX) / 2; var thumbY = sliderY + 9; var thumb = Overlays.addOverlay("image", { @@ -263,10 +264,11 @@ var thumb = Overlays.addOverlay("image", { var pointerVoxelScale = 0; // this is the voxel scale used for click to add or delete var pointerVoxelScaleSet = false; // if voxel scale has not yet been set, we use the intersection size -var pointerVoxelScaleSteps = 10; // the number of slider position steps -var pointerVoxelScaleOriginStep = 4; // the position of slider for the 1 meter size voxel +var pointerVoxelScaleSteps = 8; // the number of slider position steps +var pointerVoxelScaleOriginStep = 3; // the position of slider for the 1 meter size voxel var pointerVoxelScaleMin = Math.pow(2, (1-pointerVoxelScaleOriginStep)); var pointerVoxelScaleMax = Math.pow(2, (pointerVoxelScaleSteps-pointerVoxelScaleOriginStep)); +var thumbDeltaPerStep = thumbExtents / (pointerVoxelScaleSteps - 1); function calcThumbFromScale(scale) { var scaleLog = Math.log(scale)/Math.log(2); @@ -277,12 +279,22 @@ function calcThumbFromScale(scale) { if (thumbStep > pointerVoxelScaleSteps) { thumbStep = pointerVoxelScaleSteps; } - thumbX = (((maxThumbX - minThumbX) / pointerVoxelScaleSteps) * (thumbStep - 1)) + minThumbX; + thumbX = (thumbDeltaPerStep * (thumbStep - 1)) + minThumbX; Overlays.editOverlay(thumb, { x: thumbX + sliderX } ); } - - +function calcScaleFromThumb(newThumbX) { + // newThumbX is the pixel location relative to start of slider, + // we need to figure out the actual offset in the allowed slider area + thumbAt = newThumbX - minThumbX; + thumbStep = Math.floor((thumbAt/ thumbExtents) * (pointerVoxelScaleSteps-1)) + 1; + pointerVoxelScale = Math.pow(2, (thumbStep-pointerVoxelScaleOriginStep)); + // now reset the display accordingly... + calcThumbFromScale(pointerVoxelScale); + + // if the user moved the thumb, then they are fixing the voxel scale + pointerVoxelScaleSet = true; +} function setAudioPosition() { var camera = Camera.getPosition(); @@ -326,6 +338,14 @@ function showPreviewVoxel() { if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } + + var previewVoxelSize; + if (pointerVoxelScaleSet) { + previewVoxelSize = pointerVoxelScale; + } else { + previewVoxelSize = intersection.voxel.s; + } + if (whichColor == -1) { // Copy mode - use clicked voxel color @@ -347,7 +367,7 @@ function showPreviewVoxel() { Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: intersection.voxel.s, + size: previewVoxelSize, visible: true, color: { red: 255, green: 0, blue: 0 }, solid: false, @@ -360,7 +380,7 @@ function showPreviewVoxel() { Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: intersection.voxel.s + 0.002, + size: previewVoxelSize + 0.002, visible: true, color: voxelColor, solid: true, @@ -374,22 +394,22 @@ function showPreviewVoxel() { z: intersection.voxel.z }; if (intersection.face == "MIN_X_FACE") { - guidePosition.x -= intersection.voxel.s; + guidePosition.x -= previewVoxelSize; } else if (intersection.face == "MAX_X_FACE") { guidePosition.x += intersection.voxel.s; } else if (intersection.face == "MIN_Y_FACE") { - guidePosition.y -= intersection.voxel.s; + guidePosition.y -= previewVoxelSize; } else if (intersection.face == "MAX_Y_FACE") { guidePosition.y += intersection.voxel.s; } else if (intersection.face == "MIN_Z_FACE") { - guidePosition.z -= intersection.voxel.s; + guidePosition.z -= previewVoxelSize; } else if (intersection.face == "MAX_Z_FACE") { guidePosition.z += intersection.voxel.s; } Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: intersection.voxel.s, + size: previewVoxelSize, visible: true, color: voxelColor, solid: true, @@ -415,7 +435,12 @@ function showPreviewLines() { // TODO: add support for changing size here, if you set this size to any arbitrary size, // the preview should correctly handle it - var previewVoxelSize = intersection.voxel.s; + var previewVoxelSize; + if (pointerVoxelScaleSet) { + previewVoxelSize = pointerVoxelScale; + } else { + previewVoxelSize = intersection.voxel.s; + } var x = Math.floor(intersection.intersection.x / previewVoxelSize) * previewVoxelSize; var y = Math.floor(intersection.intersection.y / previewVoxelSize) * previewVoxelSize; @@ -545,6 +570,17 @@ function trackKeyPressEvent(event) { } function trackKeyReleaseEvent(event) { + if (event.text == "ESC") { + pointerVoxelScaleSet = false; + } + if (event.text == "-") { + thumbX -= thumbDeltaPerStep; + calcScaleFromThumb(thumbX); + } + if (event.text == "+") { + thumbX += thumbDeltaPerStep; + calcScaleFromThumb(thumbX); + } if (event.text == "CONTROL") { trackAsDelete = false; moveTools(); @@ -618,6 +654,14 @@ function mousePressEvent(event) { if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } + + // TODO: This would be a good place to use the "set" voxel size... but the add/delete/color logic below assumes that + // the "edit" size is the same as the intersect.voxel.s. So we need to fix that to really wire up the voxel size + // slider + var editVoxelSize = intersection.voxel.s; + if (pointerVoxelScaleSet) { + //editVoxelSize = pointerVoxelScale; + } if (event.isAlt) { // start orbit camera! @@ -635,7 +679,7 @@ function mousePressEvent(event) { } else if (trackAsDelete || (event.isRightButton && !trackAsEyedropper)) { // Delete voxel - Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); + Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, editVoxelSize); Audio.playSound(deleteSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); } else if (trackAsEyedropper) { @@ -653,7 +697,7 @@ function mousePressEvent(event) { Voxels.setVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, - intersection.voxel.s, + editVoxelSize, colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue); Audio.playSound(changeColorSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); @@ -665,7 +709,7 @@ function mousePressEvent(event) { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, - s: intersection.voxel.s, + s: editVoxelSize, red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; @@ -674,7 +718,7 @@ function mousePressEvent(event) { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, - s: intersection.voxel.s, + s: editVoxelSize, red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; @@ -768,8 +812,7 @@ function mouseMoveEvent(event) { if (thumbX > maxThumbX) { thumbX = maxThumbX; } - // TODO: hook this up to the voxel size in some meaningful way - Overlays.editOverlay(thumb, { x: thumbX + sliderX } ); + calcScaleFromThumb(thumbX); } else if (isOrbiting) { var cameraOrientation = Camera.getOrientation(); From d04166811e0e0105c6443ae0c048facd1f300948 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 20 Feb 2014 02:24:26 -0800 Subject: [PATCH 15/15] wired up voxel size slider to actually change voxel size --- examples/editVoxels.js | 280 +++++++++++++++++++---------------------- 1 file changed, 130 insertions(+), 150 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 8ac22413b3..81e3000566 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -328,6 +328,110 @@ var trackAsRecolor = false; var trackAsEyedropper = false; var trackAsOrbit = false; +function calculateVoxelFromIntersection(intersection, operation) { + //print("calculateVoxelFromIntersection() operation="+operation); + var resultVoxel; + + var voxelSize; + if (pointerVoxelScaleSet) { + voxelSize = pointerVoxelScale; + } else { + voxelSize = intersection.voxel.s; + } + + // first, calculate the enclosed voxel of size voxelSize that the intersection point falls inside of. + // if you have a voxelSize that's smaller than the voxel you're intersecting, this calculation will result + // in the subvoxel that the intersection point falls in + var x = Math.floor(intersection.intersection.x / voxelSize) * voxelSize; + var y = Math.floor(intersection.intersection.y / voxelSize) * voxelSize; + var z = Math.floor(intersection.intersection.z / voxelSize) * voxelSize; + resultVoxel = { x: x, y: y, z: z, s: voxelSize }; + highlightAt = { x: x, y: y, z: z, s: voxelSize }; + + // now we also want to calculate the "edge square" for the face for this voxel + if (intersection.face == "MIN_X_FACE") { + highlightAt.x = intersection.voxel.x; + resultVoxel.x = intersection.voxel.x; + if (operation == "add") { + resultVoxel.x -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize }; + + } else if (intersection.face == "MAX_X_FACE") { + highlightAt.x = intersection.voxel.x + intersection.voxel.s; + resultVoxel.x = intersection.voxel.x + intersection.voxel.s; + if (operation != "add") { + resultVoxel.x -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize }; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z + voxelSize }; + + } else if (intersection.face == "MIN_Y_FACE") { + + highlightAt.y = intersection.voxel.y; + resultVoxel.y = intersection.voxel.y; + + if (operation == "add") { + resultVoxel.y -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z + voxelSize}; + + } else if (intersection.face == "MAX_Y_FACE") { + + highlightAt.y = intersection.voxel.y + intersection.voxel.s; + resultVoxel.y = intersection.voxel.y + intersection.voxel.s; + if (operation != "add") { + resultVoxel.y -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z + voxelSize }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z + voxelSize}; + + } else if (intersection.face == "MIN_Z_FACE") { + + highlightAt.z = intersection.voxel.z; + resultVoxel.z = intersection.voxel.z; + + if (operation == "add") { + resultVoxel.z -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y + voxelSize, z: highlightAt.z}; + + } else if (intersection.face == "MAX_Z_FACE") { + + highlightAt.z = intersection.voxel.z + intersection.voxel.s; + resultVoxel.z = intersection.voxel.z + intersection.voxel.s; + if (operation != "add") { + resultVoxel.z -= voxelSize; + } + + resultVoxel.bottomLeft = {x: highlightAt.x, y: highlightAt.y, z: highlightAt.z }; + resultVoxel.bottomRight = {x: highlightAt.x + voxelSize , y: highlightAt.y, z: highlightAt.z}; + resultVoxel.topLeft = {x: highlightAt.x, y: highlightAt.y + voxelSize, z: highlightAt.z }; + resultVoxel.topRight = {x: highlightAt.x + voxelSize , y: highlightAt.y + voxelSize, z: highlightAt.z}; + + } + + return resultVoxel; +} + function showPreviewVoxel() { var voxelColor; @@ -338,14 +442,6 @@ function showPreviewVoxel() { if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } - - var previewVoxelSize; - if (pointerVoxelScaleSet) { - previewVoxelSize = pointerVoxelScale; - } else { - previewVoxelSize = intersection.voxel.s; - } - if (whichColor == -1) { // Copy mode - use clicked voxel color @@ -361,26 +457,21 @@ function showPreviewVoxel() { var guidePosition; if (trackAsDelete) { - guidePosition = { x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z }; - + guidePosition = calculateVoxelFromIntersection(intersection,"delete"); Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: previewVoxelSize, + size: guidePosition.s, visible: true, color: { red: 255, green: 0, blue: 0 }, solid: false, alpha: 1 }); } else if (trackAsRecolor || trackAsEyedropper) { - guidePosition = { x: intersection.voxel.x - 0.001, - y: intersection.voxel.y - 0.001, - z: intersection.voxel.z - 0.001 }; + guidePosition = calculateVoxelFromIntersection(intersection,"recolor"); Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: previewVoxelSize + 0.002, + size: guidePosition.s + 0.002, visible: true, color: voxelColor, solid: true, @@ -389,27 +480,11 @@ function showPreviewVoxel() { } else if (trackAsOrbit) { Overlays.editOverlay(voxelPreview, { visible: false }); } else if (!isExtruding) { - guidePosition = { x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z }; - - if (intersection.face == "MIN_X_FACE") { - guidePosition.x -= previewVoxelSize; - } else if (intersection.face == "MAX_X_FACE") { - guidePosition.x += intersection.voxel.s; - } else if (intersection.face == "MIN_Y_FACE") { - guidePosition.y -= previewVoxelSize; - } else if (intersection.face == "MAX_Y_FACE") { - guidePosition.y += intersection.voxel.s; - } else if (intersection.face == "MIN_Z_FACE") { - guidePosition.z -= previewVoxelSize; - } else if (intersection.face == "MAX_Z_FACE") { - guidePosition.z += intersection.voxel.s; - } + guidePosition = calculateVoxelFromIntersection(intersection,"add"); Overlays.editOverlay(voxelPreview, { position: guidePosition, - size: previewVoxelSize, + size: guidePosition.s, visible: true, color: voxelColor, solid: true, @@ -420,7 +495,6 @@ function showPreviewVoxel() { } } - function showPreviewLines() { var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); @@ -432,78 +506,12 @@ function showPreviewLines() { if (!pointerVoxelScaleSet) { calcThumbFromScale(intersection.voxel.s); } - - // TODO: add support for changing size here, if you set this size to any arbitrary size, - // the preview should correctly handle it - var previewVoxelSize; - if (pointerVoxelScaleSet) { - previewVoxelSize = pointerVoxelScale; - } else { - previewVoxelSize = intersection.voxel.s; - } - var x = Math.floor(intersection.intersection.x / previewVoxelSize) * previewVoxelSize; - var y = Math.floor(intersection.intersection.y / previewVoxelSize) * previewVoxelSize; - var z = Math.floor(intersection.intersection.z / previewVoxelSize) * previewVoxelSize; - previewVoxel = { x: x, y: y, z: z, s: previewVoxelSize }; - - var bottomLeft; - var bottomRight; - var topLeft; - var topRight; - - if (intersection.face == "MIN_X_FACE") { - previewVoxel.x = Math.floor(intersection.voxel.x / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; - topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; - topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z + previewVoxel.s }; - - } else if (intersection.face == "MAX_X_FACE") { - previewVoxel.x = Math.floor((intersection.voxel.x + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s }; - topLeft = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z }; - topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z + previewVoxel.s }; - - } else if (intersection.face == "MIN_Y_FACE") { - - previewVoxel.y = Math.floor(intersection.voxel.y / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; - topRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; - - } else if (intersection.face == "MAX_Y_FACE") { - - previewVoxel.y = Math.floor((intersection.voxel.y + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; - topRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z + previewVoxel.s}; - - } else if (intersection.face == "MIN_Z_FACE") { - - previewVoxel.z = Math.floor(intersection.voxel.z / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; - topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; - - } else if (intersection.face == "MAX_Z_FACE") { - - previewVoxel.z = Math.floor((intersection.voxel.z + intersection.voxel.s) / previewVoxelSize) * previewVoxelSize; - bottomLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y, z: previewVoxel.z }; - bottomRight = {x: previewVoxel.x, y: previewVoxel.y, z: previewVoxel.z }; - topLeft = {x: previewVoxel.x + previewVoxel.s, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; - topRight = {x: previewVoxel.x, y: previewVoxel.y + previewVoxel.s, z: previewVoxel.z}; - - } - - Overlays.editOverlay(linePreviewTop, { position: topLeft, end: topRight, visible: true }); - Overlays.editOverlay(linePreviewBottom, { position: bottomLeft, end: bottomRight, visible: true }); - Overlays.editOverlay(linePreviewLeft, { position: topLeft, end: bottomLeft, visible: true }); - Overlays.editOverlay(linePreviewRight, { position: topRight, end: bottomRight, visible: true }); + resultVoxel = calculateVoxelFromIntersection(intersection,""); + Overlays.editOverlay(linePreviewTop, { position: resultVoxel.topLeft, end: resultVoxel.topRight, visible: true }); + Overlays.editOverlay(linePreviewBottom, { position: resultVoxel.bottomLeft, end: resultVoxel.bottomRight, visible: true }); + Overlays.editOverlay(linePreviewLeft, { position: resultVoxel.topLeft, end: resultVoxel.bottomLeft, visible: true }); + Overlays.editOverlay(linePreviewRight, { position: resultVoxel.topRight, end: resultVoxel.bottomRight, visible: true }); } else { Overlays.editOverlay(linePreviewTop, { visible: false }); @@ -655,14 +663,6 @@ function mousePressEvent(event) { calcThumbFromScale(intersection.voxel.s); } - // TODO: This would be a good place to use the "set" voxel size... but the add/delete/color logic below assumes that - // the "edit" size is the same as the intersect.voxel.s. So we need to fix that to really wire up the voxel size - // slider - var editVoxelSize = intersection.voxel.s; - if (pointerVoxelScaleSet) { - //editVoxelSize = pointerVoxelScale; - } - if (event.isAlt) { // start orbit camera! var cameraPosition = Camera.getPosition(); @@ -679,12 +679,11 @@ function mousePressEvent(event) { } else if (trackAsDelete || (event.isRightButton && !trackAsEyedropper)) { // Delete voxel - Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, editVoxelSize); + voxelDetails = calculateVoxelFromIntersection(intersection,"delete"); + Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); Audio.playSound(deleteSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); } else if (trackAsEyedropper) { - - print("Grab color!!!"); if (whichColor != -1) { colors[whichColor].red = intersection.voxel.red; colors[whichColor].green = intersection.voxel.green; @@ -694,10 +693,11 @@ function mousePressEvent(event) { } else if (trackAsRecolor) { // Recolor Voxel - Voxels.setVoxel(intersection.voxel.x, - intersection.voxel.y, - intersection.voxel.z, - editVoxelSize, + voxelDetails = calculateVoxelFromIntersection(intersection,"recolor"); + + // doing this erase then set will make sure we only recolor just the target voxel + Voxels.eraseVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s); + Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, colors[whichColor].red, colors[whichColor].green, colors[whichColor].blue); Audio.playSound(changeColorSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false }); @@ -705,43 +705,23 @@ function mousePressEvent(event) { // Add voxel on face if (whichColor == -1) { // Copy mode - use clicked voxel color - var newVoxel = { - x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z, - s: editVoxelSize, + newColor = { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; } else { - var newVoxel = { - x: intersection.voxel.x, - y: intersection.voxel.y, - z: intersection.voxel.z, - s: editVoxelSize, + newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; } - if (intersection.face == "MIN_X_FACE") { - newVoxel.x -= newVoxel.s; - } else if (intersection.face == "MAX_X_FACE") { - newVoxel.x += newVoxel.s; - } else if (intersection.face == "MIN_Y_FACE") { - newVoxel.y -= newVoxel.s; - } else if (intersection.face == "MAX_Y_FACE") { - newVoxel.y += newVoxel.s; - } else if (intersection.face == "MIN_Z_FACE") { - newVoxel.z -= newVoxel.s; - } else if (intersection.face == "MAX_Z_FACE") { - newVoxel.z += newVoxel.s; - } - - Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); - lastVoxelPosition = { x: newVoxel.x, y: newVoxel.y, z: newVoxel.z }; - lastVoxelColor = { red: newVoxel.red, green: newVoxel.green, blue: newVoxel.blue }; - lastVoxelScale = newVoxel.s; + voxelDetails = calculateVoxelFromIntersection(intersection,"add"); + Voxels.setVoxel(voxelDetails.x, voxelDetails.y, voxelDetails.z, voxelDetails.s, + newColor.red, newColor.green, newColor.blue); + lastVoxelPosition = { x: voxelDetails.x, y: voxelDetails.y, z: voxelDetails.z }; + lastVoxelColor = { red: newColor.red, green: newColor.green, blue: newColor.blue }; + lastVoxelScale = voxelDetails.s; Audio.playSound(addSound, audioOptions); Overlays.editOverlay(voxelPreview, { visible: false });