diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f912761b43..80fb4c8e40 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -19,7 +19,7 @@ Script.include("../libraries/utils.js"); // // add lines where the hand ray picking is happening // -var DEBUG_HAND_RAY_PICKING = false; +var WANT_DEBUG = false; ///////////////////////////////////////////////////////////////// // @@ -49,6 +49,7 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray // near grabbing // +var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable. var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected @@ -193,22 +194,23 @@ function MyController(hand, triggerAction) { }; this.setState = function(newState) { - // print("STATE: " + this.state + " --> " + newState); + if (WANT_DEBUG) { + print("STATE: " + this.state + " --> " + newState); + } this.state = newState; } - this.debugLine = function(closePoint, farPoint, color){ - Entities.addEntity({ - type: "Line", - name: "Debug Line", - dimensions: LINE_ENTITY_DIMENSIONS, - visible: true, - position: closePoint, - linePoints: [ZERO_VEC, farPoint], - color: color, - lifetime: 0.1 - }); + Entities.addEntity({ + type: "Line", + name: "Debug Line", + dimensions: LINE_ENTITY_DIMENSIONS, + visible: true, + position: closePoint, + linePoints: [ZERO_VEC, farPoint], + color: color, + lifetime: 0.1 + }); } this.lineOn = function(closePoint, farPoint, color) { @@ -226,14 +228,13 @@ function MyController(hand, triggerAction) { }); } else { var age = Entities.getEntityProperties(this.pointer, "age").age; - Entities.editEntity(this.pointer, { + this.pointer = Entities.editEntity(this.pointer, { position: closePoint, linePoints: [ZERO_VEC, farPoint], color: color, lifetime: age + LIFETIME }); } - }; this.lineOff = function() { @@ -282,7 +283,6 @@ function MyController(hand, triggerAction) { return; } - // the trigger is being pressed, do a ray test var handPosition = this.getHandPosition(); var distantPickRay = { @@ -290,29 +290,17 @@ function MyController(hand, triggerAction) { direction: Quat.getUp(this.getHandRotation()), length: PICK_MAX_DISTANCE }; - var palmPickRay = { - origin: handPosition, - direction: Quat.getFront(this.getHandRotation()), - length: NEAR_PICK_MAX_DISTANCE - }; - - var otherPickRay = { - origin: handPosition, - direction: Quat.getRight(this.getHandRotation()), - length: NEAR_PICK_MAX_DISTANCE - }; - this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - // don't pick 60x per second. do this check after updating the line so it's not jumpy. + // don't pick 60x per second. + var pickRays = []; var now = Date.now(); - if (now - this.lastPickTime < MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { - return; + if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) { + pickRays = [distantPickRay]; + this.lastPickTime = now; } - this.lastPickTime = now; - var pickRays = [distantPickRay, palmPickRay, otherPickRay]; for (var index=0; index < pickRays.length; ++index) { var pickRay = pickRays[index]; var directionNormalized = Vec3.normalize(pickRay.direction); @@ -322,12 +310,13 @@ function MyController(hand, triggerAction) { direction: pickRay.direction }; - if (DEBUG_HAND_RAY_PICKING) + if (WANT_DEBUG) { this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), { red: 0, green: 255, blue: 0 }) + } var intersection = Entities.findRayIntersection(pickRayBacked, true); @@ -336,7 +325,6 @@ function MyController(hand, triggerAction) { var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection); this.grabbedEntity = intersection.entityID; - //this code will disabled the beam for the opposite hand of the one that grabbed it if the entity says so var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA); if (grabbableData["turnOffOppositeBeam"] === true) { @@ -345,7 +333,6 @@ function MyController(hand, triggerAction) { } else { disabledHand = RIGHT_HAND; } - } else { disabledHand = 'none'; } @@ -380,6 +367,37 @@ function MyController(hand, triggerAction) { } } } + + if (this.grabbedEntity === null) { + // forward ray test failed, try sphere test. + var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); + var minDistance = PICK_MAX_DISTANCE; + var i, props, distance, grabbableData; + for (i = 0; i < nearbyEntities.length; i++) { + var grabbableDataForCandidate = + getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA); + if (grabbableDataForCandidate.grabbable === false) { + continue; + } + var propsForCandidate = + Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]); + distance = Vec3.distance(propsForCandidate.position, handPosition); + if (distance < minDistance && propsForCandidate.name !== "pointer") { + this.grabbedEntity = nearbyEntities[i]; + minDistance = distance; + props = propsForCandidate; + grabbableData = grabbableDataForCandidate; + } + } + if (this.grabbedEntity === null) { + return; + } else if (props.locked === 0 && props.collisionsWillMove === 1) { + this.setState(STATE_NEAR_GRABBING); + } else if (props.collisionsWillMove === 0 && grabbableData.wantsTrigger) { + // We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event + this.setState(STATE_NEAR_GRABBING_NON_COLLIDING); + } + } }; this.distanceHolding = function() { @@ -441,7 +459,8 @@ function MyController(hand, triggerAction) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR); + var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * + DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR); // how far did avatar move this timestep? var currentPosition = MyAvatar.position; var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); @@ -491,7 +510,10 @@ function MyController(hand, triggerAction) { this.currentObjectTime = now; // this doubles hand rotation - var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), Quat.inverse(this.handPreviousRotation)); + var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, + handRotation, + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); this.handPreviousRotation = handRotation; this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); @@ -526,7 +548,8 @@ function MyController(hand, triggerAction) { this.lineOff(); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity", "ignoreForCollisions"]); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, + ["position", "rotation", "gravity", "ignoreForCollisions"]); this.activateEntity(this.grabbedEntity, grabbedProperties); var handRotation = this.getHandRotation(); @@ -764,9 +787,9 @@ function MyController(hand, triggerAction) { this.release = function() { - if(this.hand!==disabledHand){ + if(this.hand !== disabledHand){ //release the disabled hand when we let go with the main one - disabledHand='none'; + disabledHand = 'none'; } this.lineOff(); diff --git a/examples/toys/breakdanceCore.js b/examples/entityScripts/breakdanceCore.js similarity index 99% rename from examples/toys/breakdanceCore.js rename to examples/entityScripts/breakdanceCore.js index 655e55dfc6..0220962ec8 100644 --- a/examples/toys/breakdanceCore.js +++ b/examples/entityScripts/breakdanceCore.js @@ -1,6 +1,5 @@ // // breakdanceCore.js -// examples/toys // // This is the core breakdance game library, it can be used as part of an entity script, or an omniTool module, or bootstapped on it's own // Created by Brad Hefta-Gaub on August 24, 2015 diff --git a/examples/toys/breakdanceToy.js b/examples/entityScripts/breakdanceToy.js similarity index 100% rename from examples/toys/breakdanceToy.js rename to examples/entityScripts/breakdanceToy.js diff --git a/examples/toys/grenade.js b/examples/entityScripts/grenade.js similarity index 100% rename from examples/toys/grenade.js rename to examples/entityScripts/grenade.js diff --git a/examples/toys/magBalls.js b/examples/entityScripts/magBalls.js similarity index 97% rename from examples/toys/magBalls.js rename to examples/entityScripts/magBalls.js index e163aa5ffd..721e174676 100644 --- a/examples/toys/magBalls.js +++ b/examples/entityScripts/magBalls.js @@ -7,10 +7,10 @@ // // FIXME Script paths have to be relative to the caller, in this case libraries/OmniTool.js -Script.include("../toys/magBalls/constants.js"); -Script.include("../toys/magBalls/graph.js"); -Script.include("../toys/magBalls/edgeSpring.js"); -Script.include("../toys/magBalls/magBalls.js"); +Script.include("../entityScripts/magBalls/constants.js"); +Script.include("../entityScripts/magBalls/graph.js"); +Script.include("../entityScripts/magBalls/edgeSpring.js"); +Script.include("../entityScripts/magBalls/magBalls.js"); Script.include("avatarRelativeOverlays.js"); OmniToolModuleType = "MagBallsController" diff --git a/examples/toys/magBalls/constants.js b/examples/entityScripts/magBalls/constants.js similarity index 100% rename from examples/toys/magBalls/constants.js rename to examples/entityScripts/magBalls/constants.js diff --git a/examples/toys/magBalls/debugUtils.js b/examples/entityScripts/magBalls/debugUtils.js similarity index 100% rename from examples/toys/magBalls/debugUtils.js rename to examples/entityScripts/magBalls/debugUtils.js diff --git a/examples/toys/magBalls/edgeSpring.js b/examples/entityScripts/magBalls/edgeSpring.js similarity index 100% rename from examples/toys/magBalls/edgeSpring.js rename to examples/entityScripts/magBalls/edgeSpring.js diff --git a/examples/toys/magBalls/graph.js b/examples/entityScripts/magBalls/graph.js similarity index 100% rename from examples/toys/magBalls/graph.js rename to examples/entityScripts/magBalls/graph.js diff --git a/examples/toys/magBalls/magBalls.js b/examples/entityScripts/magBalls/magBalls.js similarity index 100% rename from examples/toys/magBalls/magBalls.js rename to examples/entityScripts/magBalls/magBalls.js diff --git a/examples/acScripts/flickeringLight.js b/examples/toybox/AC_scripts/flickeringLight.js similarity index 100% rename from examples/acScripts/flickeringLight.js rename to examples/toybox/AC_scripts/flickeringLight.js diff --git a/examples/toys/AC_scripts/originalPositionResetter.js b/examples/toybox/AC_scripts/originalPositionResetter.js similarity index 100% rename from examples/toys/AC_scripts/originalPositionResetter.js rename to examples/toybox/AC_scripts/originalPositionResetter.js diff --git a/examples/toybox/AC_scripts/toybox_sounds.js b/examples/toybox/AC_scripts/toybox_sounds.js new file mode 100644 index 0000000000..67985a5938 --- /dev/null +++ b/examples/toybox/AC_scripts/toybox_sounds.js @@ -0,0 +1,146 @@ +// +// toys/AC_scripts/toybox_sounds.js +// +// This script adds several sounds to the correct locations for toybox. +// By James B. Pollack @imgntn 10/21/2015 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var soundMap = [{ + name: 'river water', + url: "http://hifi-public.s3.amazonaws.com/ryan/Water_Lap_River_Edge_Gentle.L.wav", + audioOptions: { + position: { + x: 580, + y: 493, + z: 528 + }, + volume: 0.4, + loop: true + } +}, { + name: 'windmill', + url: "http://hifi-public.s3.amazonaws.com/ryan/WINDMILL_Mono.wav", + audioOptions: { + position: { + x: 530, + y: 516, + z: 518 + }, + volume: 0.08, + loop: true + } +}, { + name: 'insects', + url: "http://hifi-public.s3.amazonaws.com/ryan/insects3.wav", + audioOptions: { + position: { + x: 560, + y: 495, + z: 474 + }, + volume: 0.25, + loop: true + } +}, { + name: 'fireplace', + url: "http://hifi-public.s3.amazonaws.com/ryan/demo/0619_Fireplace__Tree_B.L.wav", + audioOptions: { + position: { + x: 551.61, + y: 494.88, + z: 502.00 + }, + volume: 0.25, + loop: true + } +}, { + name: 'cat purring', + url: "http://hifi-public.s3.amazonaws.com/ryan/Cat_Purring_Deep_Low_Snor.wav", + audioOptions: { + position: { + x: 551.48, + y: 495.60, + z: 502.08 + }, + volume: 0.25, + loop: true + } +}, { + name: 'dogs barking', + url: "http://hifi-public.s3.amazonaws.com/ryan/dogs_barking_1.L.wav", + audioOptions: { + position: { + x: 551.61, + y: 494.88, + z: 502.00 + }, + volume: 0.15, + loop: false + }, + playAtInterval: 60 * 1000 +}]; + +function loadSounds() { + soundMap.forEach(function(soundData) { + soundData.sound = SoundCache.getSound(soundData.url); + }); +} + +function playSound(soundData) { + if (soundData.injector) { + // try/catch in case the injector QObject has been deleted already + try { + soundData.injector.stop(); + } catch (e) {} + } + soundData.injector = Audio.playSound(soundData.sound, soundData.audioOptions); +} + +function checkDownloaded(soundData) { + if (soundData.sound.downloaded) { + + Script.clearInterval(soundData.downloadTimer); + + if (soundData.hasOwnProperty('playAtInterval')) { + soundData.playingInterval = Script.setInterval(function() { + playSound(soundData) + }, soundData.playAtInterval); + } else { + playSound(soundData); + } + + } +} + +function startCheckDownloadedTimers() { + soundMap.forEach(function(soundData) { + soundData.downloadTimer = Script.setInterval(function() { + checkDownloaded(soundData); + }, 1000); + }); +} + +Script.scriptEnding.connect(function() { + soundMap.forEach(function(soundData) { + + if (soundData.hasOwnProperty("injector")) { + soundData.injector.stop(); + } + + if (soundData.hasOwnProperty("downloadTimer")) { + Script.clearInterval(soundData.downloadTimer); + } + + if (soundData.hasOwnProperty("playingInterval")) { + Script.clearInterval(soundData.playingInterval); + } + + }); + +}); + +loadSounds(); +startCheckDownloadedTimers(); \ No newline at end of file diff --git a/examples/toys/basketball/createHoop.js b/examples/toybox/basketball/createHoop.js similarity index 93% rename from examples/toys/basketball/createHoop.js rename to examples/toybox/basketball/createHoop.js index 2beb7c9fca..792232b98f 100644 --- a/examples/toys/basketball/createHoop.js +++ b/examples/toybox/basketball/createHoop.js @@ -36,6 +36,10 @@ var hoop = Entities.addEntity({ y: 3.99, z: 3.79 }, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) compoundShapeURL: hoopCollisionHullURL -}); - +}); \ No newline at end of file diff --git a/examples/toys/basketball/createRack.js b/examples/toybox/basketball/createRack.js similarity index 84% rename from examples/toys/basketball/createRack.js rename to examples/toybox/basketball/createRack.js index f764b2ec03..cda1a115d4 100644 --- a/examples/toys/basketball/createRack.js +++ b/examples/toybox/basketball/createRack.js @@ -22,8 +22,6 @@ var DIAMETER = 0.30; var RESET_DISTANCE = 1; var MINIMUM_MOVE_LENGTH = 0.05; -var GRABBABLE_DATA_KEY = "grabbableKey"; - var rackStartPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { @@ -53,19 +51,17 @@ var rack = Entities.addEntity({ ignoreForCollisions: false, collisionSoundURL: collisionSoundURL, compoundShapeURL: rackCollisionHullURL, - // scriptURL: rackScriptURL + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) }); - -setEntityCustomData(GRABBABLE_DATA_KEY, rack, { - grabbable: false -}); - -var nonCollidingBalls = []; -var collidingBalls = []; +var balls = []; var originalBallPositions = []; -function createCollidingBalls() { +function createBalls() { var position = rackStartPosition; var i; @@ -76,9 +72,9 @@ function createCollidingBalls() { z: position.z + (DIAMETER) - (DIAMETER * i) }; - var collidingBall = Entities.addEntity({ + var ball = Entities.addEntity({ type: "Model", - name: 'Colliding Basketball', + name: 'Hifi-Basketball', shapeType: 'Sphere', position: ballPosition, dimensions: { @@ -96,16 +92,21 @@ function createCollidingBalls() { collisionsWillMove: true, ignoreForCollisions: false, modelURL: basketballURL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); - collidingBalls.push(collidingBall); + balls.push(ball); originalBallPositions.push(position); } } function testBallDistanceFromStart() { var resetCount = 0; - collidingBalls.forEach(function(ball, index) { + balls.forEach(function(ball, index) { var currentPosition = Entities.getEntityProperties(ball, "position").position; var originalPosition = originalBallPositions[index]; var distance = Vec3.subtract(originalPosition, currentPosition); @@ -117,8 +118,8 @@ function testBallDistanceFromStart() { if (moving < MINIMUM_MOVE_LENGTH) { resetCount++; if (resetCount === NUMBER_OF_BALLS) { - deleteCollidingBalls(); - createCollidingBalls(); + deleteBalls(); + createBalls(); } } }, 200) @@ -128,19 +129,19 @@ function testBallDistanceFromStart() { function deleteEntity(entityID) { if (entityID === rack) { - deleteCollidingBalls(); + deleteBalls(); Script.clearInterval(distanceCheckInterval); Entities.deletingEntity.disconnect(deleteEntity); } } -function deleteCollidingBalls() { - while (collidingBalls.length > 0) { - Entities.deleteEntity(collidingBalls.pop()); +function deleteBalls() { + while (balls.length > 0) { + Entities.deleteEntity(balls.pop()); } } -createCollidingBalls(); +createBalls(); Entities.deletingEntity.connect(deleteEntity); var distanceCheckInterval = Script.setInterval(testBallDistanceFromStart, 1000); diff --git a/examples/toys/basketball/createSingleBasketball.js b/examples/toybox/basketball/createSingleBasketball.js similarity index 100% rename from examples/toys/basketball/createSingleBasketball.js rename to examples/toybox/basketball/createSingleBasketball.js diff --git a/examples/toys/blockers/createTestBlocks.js b/examples/toybox/blockers/createTestBlocks.js similarity index 100% rename from examples/toys/blockers/createTestBlocks.js rename to examples/toybox/blockers/createTestBlocks.js diff --git a/examples/toys/bubblewand/createWand.js b/examples/toybox/bubblewand/createWand.js similarity index 100% rename from examples/toys/bubblewand/createWand.js rename to examples/toybox/bubblewand/createWand.js diff --git a/examples/toys/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js similarity index 100% rename from examples/toys/bubblewand/wand.js rename to examples/toybox/bubblewand/wand.js diff --git a/examples/toys/cat.js b/examples/toybox/cat/cat.js similarity index 100% rename from examples/toys/cat.js rename to examples/toybox/cat/cat.js diff --git a/examples/toys/doll/createDoll.js b/examples/toybox/doll/createDoll.js similarity index 100% rename from examples/toys/doll/createDoll.js rename to examples/toybox/doll/createDoll.js diff --git a/examples/toys/doll/doll.js b/examples/toybox/doll/doll.js similarity index 100% rename from examples/toys/doll/doll.js rename to examples/toybox/doll/doll.js diff --git a/examples/toys/flashlight/createFlashlight.js b/examples/toybox/flashlight/createFlashlight.js similarity index 100% rename from examples/toys/flashlight/createFlashlight.js rename to examples/toybox/flashlight/createFlashlight.js diff --git a/examples/toys/flashlight/flashlight.js b/examples/toybox/flashlight/flashlight.js similarity index 100% rename from examples/toys/flashlight/flashlight.js rename to examples/toybox/flashlight/flashlight.js diff --git a/examples/toys/lightSwitch.js b/examples/toybox/lights/lightSwitch.js similarity index 97% rename from examples/toys/lightSwitch.js rename to examples/toybox/lights/lightSwitch.js index 5c47108c94..fbd314a9af 100644 --- a/examples/toys/lightSwitch.js +++ b/examples/toybox/lights/lightSwitch.js @@ -17,7 +17,7 @@ (function () { var _this; - var utilitiesScript = Script.resolvePath("../libraries/utils.js"); + var utilitiesScript = Script.resolvePath("../../libraries/utils.js"); Script.include(utilitiesScript); LightSwitch = function () { _this = this; diff --git a/examples/toys/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js similarity index 100% rename from examples/toys/ping_pong_gun/createPingPongGun.js rename to examples/toybox/ping_pong_gun/createPingPongGun.js diff --git a/examples/toys/ping_pong_gun/createTargets.js b/examples/toybox/ping_pong_gun/createTargets.js similarity index 100% rename from examples/toys/ping_pong_gun/createTargets.js rename to examples/toybox/ping_pong_gun/createTargets.js diff --git a/examples/toys/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js similarity index 100% rename from examples/toys/ping_pong_gun/pingPongGun.js rename to examples/toybox/ping_pong_gun/pingPongGun.js diff --git a/examples/toys/ping_pong_gun/wallTarget.js b/examples/toybox/ping_pong_gun/wallTarget.js similarity index 100% rename from examples/toys/ping_pong_gun/wallTarget.js rename to examples/toybox/ping_pong_gun/wallTarget.js diff --git a/examples/toys/sprayPaintCan.js b/examples/toybox/spray_paint/sprayPaintCan.js similarity index 98% rename from examples/toys/sprayPaintCan.js rename to examples/toybox/spray_paint/sprayPaintCan.js index 1532ff19f3..4e6719af76 100644 --- a/examples/toys/sprayPaintCan.js +++ b/examples/toybox/spray_paint/sprayPaintCan.js @@ -13,7 +13,7 @@ // Script.include("../libraries/utils.js"); //Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge - Script.include("../libraries/utils.js"); + Script.include("../../libraries/utils.js"); this.spraySound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/sprayPaintSound.wav"); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index cf455ea98c..d2f5514e10 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -245,6 +245,8 @@ QByteArray AvatarActionHold::serialize() const { dataStream << _expires + getEntityServerClockSkew(); dataStream << _tag; + dataStream << _kinematic; + dataStream << _kinematicSetVelocity; }); return serializedActionArguments; @@ -278,6 +280,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { dataStream >> _expires; _expires -= getEntityServerClockSkew(); dataStream >> _tag; + dataStream >> _kinematic; + dataStream >> _kinematicSetVelocity; #if WANT_DEBUG qDebug() << "deserialize AvatarActionHold: " << _holderID diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 8f316af276..d5bf0bde8a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -482,7 +482,7 @@ void EntityTreeRenderer::deleteReleasedModels() { } RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude) { + bool precisionPicking, const QVector& entityIdsToInclude) { RayToEntityIntersectionResult result; if (_tree) { EntityTreePointer entityTree = std::static_pointer_cast(_tree); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 15c030f77e..5cd86fba21 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -130,7 +130,7 @@ private: QList _releasedModels; RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude = QVector()); + bool precisionPicking, const QVector& entityIdsToInclude = QVector()); EntityItemID _currentHoverOverEntityID; EntityItemID _currentClickingOnEntityID; diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index 36664f5457..1462a4ef88 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -52,3 +52,19 @@ QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) { quuidFromScriptValue(object, id); } + +QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& array) { + if (!array.isArray()) { + return QVector(); + } + QVector newVector; + int length = array.property("length").toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + QString uuidAsString = array.property(i).toString(); + EntityItemID fromString(uuidAsString); + newVector << fromString; + } + return newVector; +} + diff --git a/libraries/entities/src/EntityItemID.h b/libraries/entities/src/EntityItemID.h index 765082ef0b..41a11147f8 100644 --- a/libraries/entities/src/EntityItemID.h +++ b/libraries/entities/src/EntityItemID.h @@ -43,5 +43,6 @@ Q_DECLARE_METATYPE(EntityItemID); Q_DECLARE_METATYPE(QVector); QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties); void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties); +QVector qVectorEntityItemIDFromScriptValue(const QScriptValue& array); #endif // hifi_EntityItemID_h diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index 538d7dd890..06c6565d1b 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -21,8 +21,8 @@ // There is a minor performance gain when comparing/copying an existing glm::vec3 rather than // creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization. const glm::vec3 ENTITY_ITEM_ZERO_VEC3 = glm::vec3(0.0f); -const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f, 1.0f, 1.0f); -const glm::vec3 ENTITY_ITEM_HALF_VEC3 = ENTITY_ITEM_ONE_VEC3 / 2.0f; +const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f); +const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f); const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 07c932b34e..01d46e0a91 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -280,18 +280,18 @@ QVector EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) { - QVector entities = qVectorQUuidFromScriptValue(entityIdsToInclude); + QVector entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entities); } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) { - const QVector& entities = qVectorQUuidFromScriptValue(entityIdsToInclude); + const QVector& entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude); return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entities); } RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude) { + bool precisionPicking, const QVector& entityIdsToInclude) { RayToEntityIntersectionResult result; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 48f13e81bd..d764cd7bab 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -186,7 +186,7 @@ private: /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, - bool precisionPicking, const QVector& entityIdsToInclude); + bool precisionPicking, const QVector& entityIdsToInclude); EntityTreePointer _entityTree; EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 6e487cbfe3..24c13ae28e 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -448,6 +448,53 @@ bool EntityTree::findNearPointOperation(OctreeElementPointer element, void* extr // if this element doesn't contain the point, then none of its children can contain the point, so stop searching return false; } +// combines the ray cast arguments into a single object +class RayArgs { +public: + glm::vec3 origin; + glm::vec3 direction; + OctreeElementPointer& element; + float& distance; + BoxFace& face; + glm::vec3& surfaceNormal; + const QVector& entityIdsToInclude; + void** intersectedObject; + bool found; + bool precisionPicking; +}; + + +bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { + RayArgs* args = static_cast(extraData); + bool keepSearching = true; + EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast(element); + if (entityTreeElementPointer ->findRayIntersection(args->origin, args->direction, keepSearching, + args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude, + args->intersectedObject, args->precisionPicking)) { + args->found = true; + } + return keepSearching; +} + +bool EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, void** intersectedObject, + Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { + RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking }; + distance = FLT_MAX; + + bool requireLock = lockType == Octree::Lock; + bool lockResult = withReadLock([&]{ + recurseTreeWithOperation(findRayIntersectionOp, &args); + }, requireLock); + + if (accurateResult) { + *accurateResult = lockResult; // if user asked to accuracy or result, let them know this is accurate + } + + return args.found; +} + EntityItemPointer EntityTree::findClosestEntity(glm::vec3 position, float targetRadius) { FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX }; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index ff84a79088..1957787a60 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -80,6 +80,14 @@ public: virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal, + const QVector& entityIdsToInclude = QVector(), + void** intersectedObject = NULL, + Octree::lockType lockType = Octree::TryLock, + bool* accurateResult = NULL, + bool precisionPicking = false); + virtual bool rootElementHasData() const { return true; } // the root at least needs to store the number of entities in the packet/buffer diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 56ab27836c..57f49f2354 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -493,9 +493,50 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 return false; } +bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + void** intersectedObject, bool precisionPicking) { + + keepSearching = true; // assume that we will continue searching after this. + + float distanceToElementCube = std::numeric_limits::max(); + float distanceToElementDetails = distance; + BoxFace localFace; + glm::vec3 localSurfaceNormal; + + // if the ray doesn't intersect with our cube, we can stop searching! + if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) { + keepSearching = false; // no point in continuing to search + return false; // we did not intersect + } + + // by default, we only allow intersections with leaves with content + if (!canRayIntersect()) { + return false; // we don't intersect with non-leaves, and we keep searching + } + + // if the distance to the element cube is not less than the current best distance, then it's not possible + // for any details inside the cube to be closer so we don't need to consider them. + if (_cube.contains(origin) || distanceToElementCube < distance) { + + if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, + face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) { + + if (distanceToElementDetails < distance) { + distance = distanceToElementDetails; + face = localFace; + surfaceNormal = localSurfaceNormal; + return true; + } + } + } + return false; +} + bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - const QVector& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { + const QVector& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... int entityNumber = 0; @@ -607,27 +648,99 @@ EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const // TODO: change this to use better bounding shape for entity than sphere void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector& foundEntities) const { - float compareRadius = searchRadius * searchRadius; forEachEntity([&](EntityItemPointer entity) { - // For iteration like this, avoid the use of square roots by comparing distances squared - float distanceSquared = glm::length2(entity->getPosition() - searchPosition); - float otherRadius = entity->getRadius(); - if (distanceSquared < (compareRadius + (otherRadius * otherRadius))) { + + AABox entityBox = entity->getAABox(); + + // if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case + glm::vec3 penetration; + if (entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) { + + glm::vec3 dimensions = entity->getDimensions(); + + // FIXME - consider allowing the entity to determine penetration so that + // entities could presumably dull actuall hull testing if they wanted to + // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular + // can we handle the ellipsoid case better? We only currently handle perfect spheres + // with centered registration points + if (entity->getShapeType() == SHAPE_TYPE_SPHERE && + (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) { + + // NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the + // maximum bounding sphere, which is actually larger than our actual radius + float entityTrueRadius = dimensions.x / 2.0f; + + if (findSphereSpherePenetration(searchPosition, searchRadius, + entity->getCenterPosition(), entityTrueRadius, penetration)) { + foundEntities.push_back(entity); + } + } else { + // determine the worldToEntityMatrix that doesn't include scale because + // we're going to use the registration aware aa box in the entity frame + glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 registrationPoint = entity->getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint); + + AABox entityFrameBox(corner, dimensions); + + glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(searchPosition, 1.0f)); + if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, searchRadius, penetration)) { + foundEntities.push_back(entity); + } + } + } + }); +} + +void EntityTreeElement::getEntities(const AACube& cube, QVector& foundEntities) { + forEachEntity([&](EntityItemPointer entity) { + AABox entityBox = entity->getAABox(); + // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better + // FIXME - consider allowing the entity to determine penetration so that + // entities could presumably dull actuall hull testing if they wanted to + // FIXME - is there an easy way to translate the search cube into something in the + // entity frame that can be easily tested against? + // simple algorithm is probably: + // if target box is fully inside search box == yes + // if search box is fully inside target box == yes + // for each face of search box: + // translate the triangles of the face into the box frame + // test the triangles of the face against the box? + // if translated search face triangle intersect target box + // add to result + // + + // If the entities AABox touches the search cube then consider it to be found + if (entityBox.touches(cube)) { foundEntities.push_back(entity); } }); } -// TODO: change this to use better bounding shape for entity than sphere -void EntityTreeElement::getEntities(const AACube& box, QVector& foundEntities) { - AACube entityCube; +void EntityTreeElement::getEntities(const AABox& box, QVector& foundEntities) { forEachEntity([&](EntityItemPointer entity) { - float radius = entity->getRadius(); - // NOTE: we actually do cube-cube collision queries here, which is sloppy but good enough for now - // TODO: decide whether to replace entityCube-cube query with sphere-cube (requires a square root - // but will be slightly more accurate). - entityCube.setBox(entity->getPosition() - glm::vec3(radius), 2.0f * radius); - if (entityCube.touches(box)) { + AABox entityBox = entity->getAABox(); + // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better + // FIXME - consider allowing the entity to determine penetration so that + // entities could presumably dull actuall hull testing if they wanted to + // FIXME - is there an easy way to translate the search cube into something in the + // entity frame that can be easily tested against? + // simple algorithm is probably: + // if target box is fully inside search box == yes + // if search box is fully inside target box == yes + // for each face of search box: + // translate the triangles of the face into the box frame + // test the triangles of the face against the box? + // if translated search face triangle intersect target box + // add to result + // + + // If the entities AABox touches the search cube then consider it to be found + if (entityBox.touches(box)) { foundEntities.push_back(entity); } }); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 0a47542e65..57e0bea696 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -142,11 +142,14 @@ public: virtual bool deleteApproved() const { return !hasEntities(); } virtual bool canRayIntersect() const { return hasEntities(); } + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElementPointer& node, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + void** intersectedObject = NULL, bool precisionPicking = false); virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, + BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube); - virtual bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const; @@ -180,7 +183,12 @@ public: /// finds all entities that touch a box /// \param box the query box /// \param entities[out] vector of non-const EntityItemPointer - void getEntities(const AACube& box, QVector& foundEntities); + void getEntities(const AACube& cube, QVector& foundEntities); + + /// finds all entities that touch a box + /// \param box the query box + /// \param entities[out] vector of non-const EntityItemPointer + void getEntities(const AABox& box, QVector& foundEntities); EntityItemPointer getEntityWithID(uint32_t id) const; EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const; diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 352d0425bf..f1be431ce8 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -108,7 +108,7 @@ bool PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths) { bool PolyLineEntityItem::setNormals(const QVector& normals) { _normals = normals; - if (_points.size() < 2 || _normals.size() < 2) { + if (_points.size() < 2 || _normals.size() < 2 || _strokeWidths.size() < 2) { return false; } @@ -123,7 +123,8 @@ bool PolyLineEntityItem::setNormals(const QVector& normals) { _vertices.clear(); glm::vec3 v1, v2, tangent, binormal, point; - for (int i = 0; i < minVectorSize - 1; i++) { + int finalIndex = minVectorSize -1; + for (int i = 0; i < finalIndex; i++) { float width = _strokeWidths.at(i); point = _points.at(i); @@ -138,7 +139,7 @@ bool PolyLineEntityItem::setNormals(const QVector& normals) { _vertices << v1 << v2; } //for last point we can just assume binormals are same since it represents last two vertices of quad - point = _points.at(minVectorSize - 1); + point = _points.at(finalIndex); v1 = point + binormal; v2 = point - binormal; _vertices << v1 << v2; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3b6467401c..cceb3ba706 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -694,50 +694,7 @@ OctreeElementPointer Octree::getOrCreateChildElementContaining(const AACube& box return getRoot()->getOrCreateChildElementContaining(box); } -// combines the ray cast arguments into a single object -class RayArgs { -public: - glm::vec3 origin; - glm::vec3 direction; - OctreeElementPointer& element; - float& distance; - BoxFace& face; - glm::vec3& surfaceNormal; - const QVector& entityIdsToInclude; - void** intersectedObject; - bool found; - bool precisionPicking; -}; -bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { - RayArgs* args = static_cast(extraData); - bool keepSearching = true; - if (element->findRayIntersection(args->origin, args->direction, keepSearching, - args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude, - args->intersectedObject, args->precisionPicking)) { - args->found = true; - } - return keepSearching; -} - -bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, void** intersectedObject, - Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { - RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking}; - distance = FLT_MAX; - - bool requireLock = lockType == Octree::Lock; - bool lockResult = withReadLock([&]{ - recurseTreeWithOperation(findRayIntersectionOp, &args); - }, requireLock); - - if (accurateResult) { - *accurateResult = lockResult; // if user asked to accuracy or result, let them know this is accurate - } - - return args.found; -} class SphereArgs { public: diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index f0a4d2c9c0..5ebb991d49 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -298,13 +298,6 @@ public: TryLock } lockType; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - const QVector& entityIdsToInclude = QVector(), - void** intersectedObject = NULL, - Octree::lockType lockType = Octree::TryLock, - bool* accurateResult = NULL, - bool precisionPicking = false); bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 9a48079338..17ebe492ce 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -573,64 +573,6 @@ void OctreeElement::notifyUpdateHooks() { } } -bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, - void** intersectedObject, bool precisionPicking) { - - keepSearching = true; // assume that we will continue searching after this. - - float distanceToElementCube = std::numeric_limits::max(); - float distanceToElementDetails = distance; - BoxFace localFace; - glm::vec3 localSurfaceNormal; - - // if the ray doesn't intersect with our cube, we can stop searching! - if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) { - keepSearching = false; // no point in continuing to search - return false; // we did not intersect - } - - // by default, we only allow intersections with leaves with content - if (!canRayIntersect()) { - return false; // we don't intersect with non-leaves, and we keep searching - } - - // if the distance to the element cube is not less than the current best distance, then it's not possible - // for any details inside the cube to be closer so we don't need to consider them. - if (_cube.contains(origin) || distanceToElementCube < distance) { - - if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, - face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) { - - if (distanceToElementDetails < distance) { - distance = distanceToElementDetails; - face = localFace; - surfaceNormal = localSurfaceNormal; - return true; - } - } - } - return false; -} - -bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, - void** intersectedObject, bool precisionPicking, float distanceToElementCube) { - - // we did hit this element, so calculate appropriate distances - if (hasContent()) { - element = shared_from_this(); - distance = distanceToElementCube; - if (intersectedObject) { - *intersectedObject = this; - } - keepSearching = false; - return true; // we did intersect - } - return false; // we did not intersect -} bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index c132d437cd..6ccef31d4f 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -118,16 +118,6 @@ public: virtual bool deleteApproved() const { return true; } virtual bool canRayIntersect() const { return isLeaf(); } - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& node, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, - void** intersectedObject = NULL, bool precisionPicking = false); - - virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, const QVector& entityIdsToInclude, - void** intersectedObject, bool precisionPicking, float distanceToElementCube); - /// \param center center of sphere in meters /// \param radius radius of sphere in meters /// \param[out] penetration pointing into cube from sphere diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 9ab0eaecb4..008ac238d5 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -13,7 +13,6 @@ #include #include #include - #include #include "RegisteredMetaTypes.h" diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 42056f6c3b..e441db3aa6 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -14,14 +14,15 @@ var _this; - var sprayPaintScriptURL = Script.resolvePath("../examples/toys/sprayPaintCan.js"); - var catScriptURL = Script.resolvePath("../examples/toys/cat.js"); - var flashlightScriptURL = Script.resolvePath('../examples/toys/flashlight/flashlight.js'); - var pingPongScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/pingPongGun.js'); - var wandScriptURL = Script.resolvePath("../examples/toys/bubblewand/wand.js"); - var dollScriptURL = Script.resolvePath("../examples/toys/doll/doll.js"); - var lightsScriptURL = Script.resolvePath("../examples/toys/lightSwitch.js"); - var targetsScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/wallTarget.js'); + var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js"); + var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js"); + var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js'); + var pingPongScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/pingPongGun.js'); + var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); + var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); + var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); + var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); + ResetSwitch = function() { _this = this; @@ -54,7 +55,6 @@ MasterReset = function() { var resetKey = "resetMe"; - var GRABBABLE_DATA_KEY = "grabbableKey"; var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; @@ -97,8 +97,6 @@ z: 505.78 }); - - createCombinedArmChair({ x: 549.29, y: 494.9, @@ -321,7 +319,7 @@ resetMe: { resetMe: true }, - grabbable: { + grabbableKey: { invertSolidWhileHeld: true } }) @@ -487,7 +485,6 @@ grabbableKey: { invertSolidWhileHeld: true } - }) }); @@ -533,6 +530,9 @@ resetMe: true, on: true, type: "Hall Light" + }, + grabbableKey: { + wantsTrigger: true } }) }); @@ -628,6 +628,9 @@ resetMe: true, on: true, type: "Garage Light" + }, + grabbableKey: { + wantsTrigger: true } }) }); @@ -759,6 +762,7 @@ grabbableKey: { invertSolidWhileHeld: true } + }) }; var dice1 = Entities.addEntity(diceProps); @@ -851,6 +855,7 @@ grabbableKey: { invertSolidWhileHeld: true } + }) }); } @@ -1176,7 +1181,7 @@ y: 0.05, z: 0.25 } - } ]; + }]; var modelURL, entity; for (i = 0; i < blockTypes.length; i++) { diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 2ecd52f344..956db41235 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -14,20 +14,19 @@ var utilitiesScript = Script.resolvePath("../examples/libraries/utils.js"); Script.include(utilitiesScript); -var sprayPaintScriptURL = Script.resolvePath("../examples/toys/sprayPaintCan.js"); -var catScriptURL = Script.resolvePath("../examples/toys/cat.js"); -var flashlightScriptURL = Script.resolvePath('../examples/toys/flashlight/flashlight.js'); -var pingPongScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/pingPongGun.js'); -var wandScriptURL = Script.resolvePath("../examples/toys/bubblewand/wand.js"); -var dollScriptURL = Script.resolvePath("../examples/toys/doll/doll.js"); -var lightsScriptURL = Script.resolvePath("../examples/toys/lightSwitch.js"); -var targetsScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/wallTarget.js'); + var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js"); + var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js"); + var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js'); + var pingPongScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/pingPongGun.js'); + var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js"); + var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js"); + var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js"); + var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js'); MasterReset = function() { var resetKey = "resetMe"; - var GRABBABLE_DATA_KEY = "grabbableKey"; var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; @@ -294,7 +293,7 @@ MasterReset = function() { resetMe: { resetMe: true }, - grabbable: { + grabbableKey: { invertSolidWhileHeld: true } }) @@ -505,6 +504,9 @@ MasterReset = function() { resetMe: true, on: true, type: "Hall Light" + }, + grabbableKey: { + wantsTrigger: true } }) }); @@ -600,6 +602,9 @@ MasterReset = function() { resetMe: true, on: true, type: "Garage Light" + }, + grabbableKey: { + wantsTrigger: true } }) });