diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt index 5a696afc10..77969e06e5 100644 --- a/animation-server/CMakeLists.txt +++ b/animation-server/CMakeLists.txt @@ -13,7 +13,6 @@ include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/SetupHifiProject.cmake) - setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared library diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 05a1b4ea65..896b709e2a 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -171,7 +171,7 @@ void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::T QStringList multiConfigList = configString.split(";", QString::SkipEmptyParts); - const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*(\\w+)"; + const QString ASSIGNMENT_CONFIG_POOL_REGEX = "--pool\\s*([\\w-]+)"; QRegExp poolRegex(ASSIGNMENT_CONFIG_POOL_REGEX); // read each config to a payload for this type of assignment diff --git a/examples/addVoxelOnMouseClickExample.js b/examples/addVoxelOnMouseClickExample.js new file mode 100644 index 0000000000..244a017ae4 --- /dev/null +++ b/examples/addVoxelOnMouseClickExample.js @@ -0,0 +1,62 @@ +// +// addVoxelOnMouseClickExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/6/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Camera and Voxels class to implement +// clicking on a voxel and adding a new voxel on the clicked on face +// +// + +function mousePressEvent(event) { + print("mousePressEvent event.x,y=" + event.x + ", " + event.y); + var pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Voxels.findRayIntersection(pickRay); + if (intersection.intersects) { + + // Note: due to the current C++ "click on voxel" behavior, these values may be the animated color for the voxel + print("clicked on voxel.red/green/blue=" + intersection.voxel.red + ", " + + intersection.voxel.green + ", " + intersection.voxel.blue); + print("clicked on voxel.x/y/z/s=" + intersection.voxel.x + ", " + + intersection.voxel.y + ", " + intersection.voxel.z+ ": " + intersection.voxel.s); + print("clicked on face=" + intersection.face); + print("clicked on distance=" + intersection.distance); + + var newVoxel = { + x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z, + s: intersection.voxel.s, + red: 255, + green: 0, + blue: 255 }; + + 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; + } + + print("Voxels.setVoxel("+newVoxel.x + ", " + + newVoxel.y + ", " + newVoxel.z + ", " + newVoxel.s + ", " + + newVoxel.red + ", " + newVoxel.green + ", " + newVoxel.blue + ")" ); + + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); + } +} + +Controller.mousePressEvent.connect(mousePressEvent); + +function scriptEnding() { +} +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/rayPickExample.js b/examples/rayPickExample.js new file mode 100644 index 0000000000..1c79d7cd6a --- /dev/null +++ b/examples/rayPickExample.js @@ -0,0 +1,31 @@ +// +// rayPickExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/6/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Camera class +// +// + +function mouseMoveEvent(event) { + print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y); + var pickRay = Camera.computePickRay(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 pickRay = Camera.computePickRay(event.x, event.y); + var intersection = Voxels.findRayIntersection(pickRay); + if (intersection.intersects) { + print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", " + + intersection.voxel.green + ", " + intersection.voxel.blue); + } +} + +Controller.mouseMoveEvent.connect(mouseMoveEvent); + +function scriptEnding() { +} +Script.scriptEnding.connect(scriptEnding); + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3f32c6be09..6119c83e66 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4101,6 +4101,7 @@ void Application::loadScript(const QString& fileNameString) { // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so // we can use the same ones from the application. scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); + scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree()); scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 4bfb2a2de1..0358f169b8 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -81,7 +81,6 @@ QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) QScriptValue direction = vec3toScriptValue(engine, pickRay.direction); obj.setProperty("direction", direction); return obj; - } void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 91eb3848c7..130a48cdeb 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -46,5 +46,4 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); - #endif diff --git a/libraries/voxels/CMakeLists.txt b/libraries/voxels/CMakeLists.txt index da97e83ec9..8a3b0d7325 100644 --- a/libraries/voxels/CMakeLists.txt +++ b/libraries/voxels/CMakeLists.txt @@ -9,11 +9,12 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cm set(TARGET_NAME voxels) find_package(Qt5Widgets REQUIRED) +find_package(Qt5Script REQUIRED) include(${MACRO_DIR}/SetupHifiLibrary.cmake) setup_hifi_library(${TARGET_NAME}) -qt5_use_modules(${TARGET_NAME} Widgets) +qt5_use_modules(${TARGET_NAME} Widgets Script) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/voxels/src/VoxelDetail.cpp b/libraries/voxels/src/VoxelDetail.cpp index d4ab5cafcb..8d9f7df0c5 100644 --- a/libraries/voxels/src/VoxelDetail.cpp +++ b/libraries/voxels/src/VoxelDetail.cpp @@ -9,6 +9,7 @@ void registerVoxelMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, voxelDetailToScriptValue, voxelDetailFromScriptValue); + qScriptRegisterMetaType(engine, rayToVoxelIntersectionResultToScriptValue, rayToVoxelIntersectionResultFromScriptValue); } QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& voxelDetail) { @@ -33,5 +34,71 @@ void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& voxelDe voxelDetail.blue = object.property("blue").toVariant().toInt(); } +RayToVoxelIntersectionResult::RayToVoxelIntersectionResult() : + intersects(false), + voxel(), + distance(0), + face() +{ +}; + +QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& value) { + QScriptValue obj = engine->newObject(); + obj.setProperty("intersects", value.intersects); + QScriptValue voxelValue = voxelDetailToScriptValue(engine, value.voxel); + obj.setProperty("voxel", voxelValue); + obj.setProperty("distance", value.distance); + + QString faceName = ""; + // handle BoxFace + switch (value.face) { + case MIN_X_FACE: + faceName = "MIN_X_FACE"; + break; + case MAX_X_FACE: + faceName = "MAX_X_FACE"; + break; + case MIN_Y_FACE: + faceName = "MIN_Y_FACE"; + break; + case MAX_Y_FACE: + faceName = "MAX_Y_FACE"; + break; + case MIN_Z_FACE: + faceName = "MIN_Z_FACE"; + break; + case MAX_Z_FACE: + faceName = "MAX_Z_FACE"; + break; + } + obj.setProperty("face", faceName); + return obj; +} + +void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& value) { + value.intersects = object.property("intersects").toVariant().toBool(); + QScriptValue voxelValue = object.property("voxel"); + if (voxelValue.isValid()) { + voxelDetailFromScriptValue(voxelValue, value.voxel); + } + value.distance = object.property("distance").toVariant().toFloat(); + + QString faceName = object.property("face").toVariant().toString(); + if (faceName == "MIN_X_FACE") { + value.face = MIN_X_FACE; + } else if (faceName == "MAX_X_FACE") { + value.face = MAX_X_FACE; + } else if (faceName == "MIN_Y_FACE") { + value.face = MIN_Y_FACE; + } else if (faceName == "MAX_Y_FACE") { + value.face = MAX_Y_FACE; + } else if (faceName == "MIN_Z_FACE") { + value.face = MIN_Z_FACE; + } else { + value.face = MAX_Z_FACE; + }; +} + + diff --git a/libraries/voxels/src/VoxelDetail.h b/libraries/voxels/src/VoxelDetail.h index ca1ff3940b..9da2e40776 100644 --- a/libraries/voxels/src/VoxelDetail.h +++ b/libraries/voxels/src/VoxelDetail.h @@ -12,6 +12,7 @@ #include +#include #include #include "VoxelConstants.h" @@ -32,5 +33,18 @@ void registerVoxelMetaTypes(QScriptEngine* engine); QScriptValue voxelDetailToScriptValue(QScriptEngine* engine, const VoxelDetail& color); void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& color); +class RayToVoxelIntersectionResult { +public: + RayToVoxelIntersectionResult(); + bool intersects; + VoxelDetail voxel; + float distance; + BoxFace face; +}; + +Q_DECLARE_METATYPE(RayToVoxelIntersectionResult) + +QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& results); +void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& results); #endif /* defined(__hifi__VoxelDetail__) */ \ No newline at end of file diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index d82912c44b..af5f8ce3c2 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -41,3 +41,25 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale getVoxelPacketSender()->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &deleteVoxelDetail); } + +RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersection(const PickRay& ray) { + RayToVoxelIntersectionResult result; + if (_tree) { + if (_tree->tryLockForRead()) { + OctreeElement* element; + result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face); + if (result.intersects) { + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + result.voxel.x = voxel->getCorner().x; + result.voxel.y = voxel->getCorner().y; + result.voxel.z = voxel->getCorner().z; + result.voxel.s = voxel->getScale(); + result.voxel.red = voxel->getColor()[0]; + result.voxel.green = voxel->getColor()[1]; + result.voxel.blue = voxel->getColor()[2]; + } + _tree->unlock(); + } + } + return result; +} diff --git a/libraries/voxels/src/VoxelsScriptingInterface.h b/libraries/voxels/src/VoxelsScriptingInterface.h index 877383e0b0..f87e8d0a4c 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.h +++ b/libraries/voxels/src/VoxelsScriptingInterface.h @@ -12,18 +12,22 @@ #include #include +#include #include "VoxelConstants.h" #include "VoxelEditPacketSender.h" +#include "VoxelTree.h" /// handles scripting of voxel commands from JS passed to assigned clients class VoxelsScriptingInterface : public OctreeScriptingInterface { Q_OBJECT -public: +public: + VoxelsScriptingInterface() : _tree(NULL) {}; VoxelEditPacketSender* getVoxelPacketSender() { return (VoxelEditPacketSender*)getPacketSender(); } virtual NodeType_t getServerNodeType() const { return NodeType::VoxelServer; } virtual OctreeEditPacketSender* createPacketSender() { return new VoxelEditPacketSender(); } + void setVoxelTree(VoxelTree* tree) { _tree = tree; } public slots: /// queues the creation of a voxel which will be sent by calling process on the PacketSender @@ -53,8 +57,12 @@ public slots: /// \param scale the scale of the voxel (in meter units) void eraseVoxel(float x, float y, float z, float scale); + /// If the scripting context has visible voxels, this will determine a ray intersection + RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray); + private: void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails); + VoxelTree* _tree; }; #endif /* defined(__hifi__VoxelsScriptingInterface__) */ diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index 38e1dd6efc..e0aa0750d2 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -13,9 +13,11 @@ include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/SetupHifiProject.cmake) - setup_hifi_project(${TARGET_NAME} TRUE) +find_package(Qt5Script REQUIRED) +qt5_use_modules(${TARGET_NAME} Script) + # link in the shared library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})