From 71b7f9ee38a4d18fdbfe5d5ad9d5e7c5490718e3 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 21 Sep 2015 19:14:24 -0700 Subject: [PATCH 01/25] Apostrophe key resets animation state. --- interface/src/avatar/MyAvatar.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ae483988e3..75da84961b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -149,6 +149,23 @@ void MyAvatar::reset() { eulers.x = 0.0f; eulers.z = 0.0f; setOrientation(glm::quat(eulers)); + + // This should be simpler when we have only graph animations always on. + bool isRig = _rig->getEnableRig(); + bool isGraph = _rig->getEnableAnimGraph(); + qApp->setRawAvatarUpdateThreading(false); + setEnableRigAnimations(true); + _skeletonModel.simulate(0.1f); // non-zero + setEnableRigAnimations(false); + _skeletonModel.simulate(0.1f); + if (isRig) { + setEnableRigAnimations(true); + Menu::getInstance()->setIsOptionChecked(MenuOption::EnableRigAnimations, true); + } else if (isGraph) { + setEnableAnimGraph(true); + Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, true); + } + qApp->setRawAvatarUpdateThreading(); } void MyAvatar::update(float deltaTime) { From b9db495ebf78e85ada8f1b5faf1fa954fe6ecfbb Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 22 Sep 2015 09:38:06 -0700 Subject: [PATCH 02/25] Modified handControllerGrab script to trigger entity touch events for non-physical entities --- examples/controllers/handControllerGrab.js | 100 +++++++++++++++------ 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index f57e79e974..0fa32baf53 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -29,9 +29,21 @@ var TRIGGER_ON_VALUE = 0.2; var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses -var INTERSECT_COLOR = {red: 250, green: 10, blue: 10}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = {x: 1000, y: 1000, z: 1000}; +var NO_INTERSECT_COLOR = { + red: 10, + green: 10, + blue: 255 +}; // line color when pick misses +var INTERSECT_COLOR = { + red: 250, + green: 10, + blue: 10 +}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { + x: 1000, + y: 1000, + z: 1000 +}; var LINE_LENGTH = 500; @@ -54,7 +66,11 @@ var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things var RIGHT_HAND = 1; var LEFT_HAND = 0; -var ZERO_VEC = {x: 0, y: 0, z: 0}; +var ZERO_VEC = { + x: 0, + y: 0, + z: 0 +}; var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; var MSEC_PER_SEC = 1000.0; @@ -68,7 +84,9 @@ var STATE_DISTANCE_HOLDING = 1; var STATE_CONTINUE_DISTANCE_HOLDING = 2; var STATE_NEAR_GRABBING = 3; var STATE_CONTINUE_NEAR_GRABBING = 4; -var STATE_RELEASE = 5; +var STATE_NEAR_TOUCHING = 5; +var STATE_CONTINUE_NEAR_TOUCHING = 6; +var STATE_RELEASE = 7; var GRAB_USER_DATA_KEY = "grabKey"; @@ -93,7 +111,7 @@ function controller(hand, triggerAction) { this.triggerValue = 0; // rolling average of trigger value this.update = function() { - switch(this.state) { + switch (this.state) { case STATE_SEARCHING: this.search(); break; @@ -109,6 +127,12 @@ function controller(hand, triggerAction) { case STATE_CONTINUE_NEAR_GRABBING: this.continueNearGrabbing(); break; + case STATE_NEAR_TOUCHING: + this.nearTouching(); + break; + case STATE_CONTINUE_NEAR_TOUCHING: + this.continueNearTouching(); + break; case STATE_RELEASE: this.release(); break; @@ -125,14 +149,14 @@ function controller(hand, triggerAction) { dimensions: LINE_ENTITY_DIMENSIONS, visible: true, position: closePoint, - linePoints: [ ZERO_VEC, farPoint ], + linePoints: [ZERO_VEC, farPoint], color: color, lifetime: LIFETIME }); } else { Entities.editEntity(this.pointer, { position: closePoint, - linePoints: [ ZERO_VEC, farPoint ], + linePoints: [ZERO_VEC, farPoint], color: color, lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME }); @@ -171,7 +195,10 @@ function controller(hand, triggerAction) { // the trigger is being pressed, do a ray test var handPosition = this.getHandPosition(); - var pickRay = {origin: handPosition, direction: Quat.getUp(this.getHandRotation())}; + var pickRay = { + origin: handPosition, + direction: Quat.getUp(this.getHandRotation()) + }; var intersection = Entities.findRayIntersection(pickRay, true); if (intersection.intersects && intersection.properties.collisionsWillMove === 1 && @@ -189,24 +216,25 @@ function controller(hand, triggerAction) { this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } } else { - // forward ray test failed, try sphere test. + // forward ray test failed, try sphere test. var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); var minDistance = GRAB_RADIUS; var grabbedEntity = null; for (var i = 0; i < nearbyEntities.length; i++) { var props = Entities.getEntityProperties(nearbyEntities[i]); var distance = Vec3.distance(props.position, handPosition); - if (distance < minDistance && props.name !== "pointer" && - props.collisionsWillMove === 1 && - props.locked === 0) { + if (distance < minDistance && props.name !== "pointer") { this.grabbedEntity = nearbyEntities[i]; minDistance = distance; } } if (this.grabbedEntity === null) { this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); - } else { + } else if (props.locked === 0 && props.collisionsWillMove === 1) { this.state = STATE_NEAR_GRABBING; + } else if (props.collisionsWillMove === 0) { + // We have grabbed a non-physical object, so we want to trigger a touch event as opposed to a grab event + this.state = STATE_NEAR_TOUCHING; } } } @@ -215,7 +243,7 @@ function controller(hand, triggerAction) { this.distanceHolding = function() { var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]); + var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]); // add the action and initialize some variables this.currentObjectPosition = grabbedProperties.position; @@ -263,8 +291,8 @@ function controller(hand, triggerAction) { // 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); + handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, + DISTANCE_HOLDING_RADIUS_FACTOR); var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition); this.handPreviousPosition = handControllerPosition; @@ -281,16 +309,18 @@ function controller(hand, triggerAction) { // this doubles hand rotation var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, - DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - Quat.inverse(this.handPreviousRotation)); + DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), + Quat.inverse(this.handPreviousRotation)); this.handPreviousRotation = handRotation; this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); Entities.updateAction(this.grabbedEntity, this.actionID, { - targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + targetPosition: this.currentObjectPosition, + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + targetRotation: this.currentObjectRotation, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME }); } @@ -339,6 +369,23 @@ function controller(hand, triggerAction) { this.currentObjectTime = Date.now(); } + this.nearTouching = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + Entities.callEntityMethod(this.grabbedEntity, "startNearTouch") + this.state = STATE_CONTINUE_NEAR_TOUCHING; + } + + this.continueNearTouching = function() { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + Entities.callEntityMethod(this.grabbedEntity, "continueNearTouch"); + } + this.continueNearGrabbing = function() { if (!this.triggerSmoothedSqueezed()) { @@ -367,9 +414,8 @@ function controller(hand, triggerAction) { // value would otherwise give the held object time to slow down. if (this.triggerSqueezed()) { this.grabbedVelocity = - Vec3.sum(Vec3.multiply(this.grabbedVelocity, - (1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)), - Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)); + Vec3.sum(Vec3.multiply(this.grabbedVelocity, (1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)), + Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)); } if (useMultiplier) { @@ -389,7 +435,9 @@ function controller(hand, triggerAction) { // the action will tend to quickly bring an object's velocity to zero. now that // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(this.grabbedEntity, {velocity: this.grabbedVelocity}); + Entities.editEntity(this.grabbedEntity, { + velocity: this.grabbedVelocity + }); this.deactivateEntity(this.grabbedEntity); this.grabbedVelocity = ZERO_VEC; @@ -438,4 +486,4 @@ function cleanup() { Script.scriptEnding.connect(cleanup); -Script.update.connect(update) +Script.update.connect(update) \ No newline at end of file From 42a2125336a7edfba03b9e662f1e175ef85fd7ff Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Tue, 22 Sep 2015 13:29:54 -0700 Subject: [PATCH 03/25] Only asking for needed props --- examples/controllers/handControllerGrab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0fa32baf53..af1c97da68 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -216,12 +216,12 @@ function controller(hand, triggerAction) { this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } } else { - // forward ray test failed, try sphere test. + // forward ray test failed, try sphere test. var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); var minDistance = GRAB_RADIUS; var grabbedEntity = null; for (var i = 0; i < nearbyEntities.length; i++) { - var props = Entities.getEntityProperties(nearbyEntities[i]); + var props = Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]); var distance = Vec3.distance(props.position, handPosition); if (distance < minDistance && props.name !== "pointer") { this.grabbedEntity = nearbyEntities[i]; From 1e09c2501c9b33f5311be4c7402df89481af4edf Mon Sep 17 00:00:00 2001 From: James Pollack Date: Tue, 22 Sep 2015 14:21:14 -0700 Subject: [PATCH 04/25] This updates the flashlight to have sounds when it turns on and off --- examples/toys/flashlight/flashlight.js | 50 ++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/examples/toys/flashlight/flashlight.js b/examples/toys/flashlight/flashlight.js index 0465266b1c..5afaed829c 100644 --- a/examples/toys/flashlight/flashlight.js +++ b/examples/toys/flashlight/flashlight.js @@ -18,6 +18,8 @@ (function() { Script.include("../../libraries/utils.js"); + var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; + var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; var _this; @@ -78,7 +80,7 @@ this.hand = 'LEFT'; }, startNearGrab: function() { - if (!_this.hasSpotlight) { + if (!this.hasSpotlight) { //this light casts the beam this.spotlight = Entities.addEntity({ @@ -117,21 +119,7 @@ cutoff: 90, // in degrees }); - this.debugBox = Entities.addEntity({ - type: 'Box', - color: { - red: 255, - blue: 0, - green: 0 - }, - dimensions: { - x: 0.25, - y: 0.25, - z: 0.25 - }, - ignoreForCollisions:true - }) - + this.hasSpotlight = true; } @@ -158,7 +146,7 @@ this.glowLight = null; this.spotlight = null; this.whichHand = null; - + this.lightOn = false; } }, updateLightPositions: function() { @@ -181,11 +169,6 @@ rotation: glowLightTransform.q, }) - // Entities.editEntity(this.debugBox, { - // position: lightTransform.p, - // rotation: lightTransform.q, - // }) - }, changeLightWithTriggerPressure: function(flashLightHand) { @@ -203,6 +186,7 @@ return }, turnLightOff: function() { + this.playSoundAtCurrentPosition(false); Entities.editEntity(this.spotlight, { intensity: 0 }); @@ -210,8 +194,12 @@ intensity: 0 }); this.lightOn = false + + }, turnLightOn: function() { + this.playSoundAtCurrentPosition(true); + Entities.editEntity(this.glowLight, { intensity: 2 }); @@ -225,6 +213,23 @@ // * remembering our entityID, so we can access it in cases where we're called without an entityID preload: function(entityID) { this.entityID = entityID; + this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); + this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); + + }, + playSoundAtCurrentPosition: function(playOnSound) { + var position = Entities.getEntityProperties(this.entityID, "position").position; + + var audioProperties = { + volume: 0.5, + position: position + } + if (playOnSound) { + Audio.playSound(this.ON_SOUND, audioProperties) + } else { + Audio.playSound(this.OFF_SOUND, audioProperties) + + } }, // unload() will be called when our entity is no longer available. It may be because we were deleted, @@ -238,6 +243,7 @@ this.glowLight = null; this.spotlight = null; this.whichHand = null; + this.lightOn = false; } From fa1d5be3100a50b18884eddbbb071764d52179f0 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Tue, 22 Sep 2015 18:20:23 -0700 Subject: [PATCH 05/25] Reduce volume, JSLint, Coding standards --- examples/toys/flashlight/createFlashlight.js | 41 ++++-------- examples/toys/flashlight/flashlight.js | 70 +++++++++----------- 2 files changed, 47 insertions(+), 64 deletions(-) diff --git a/examples/toys/flashlight/createFlashlight.js b/examples/toys/flashlight/createFlashlight.js index 38907efa75..7c04433979 100644 --- a/examples/toys/flashlight/createFlashlight.js +++ b/examples/toys/flashlight/createFlashlight.js @@ -11,7 +11,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - +/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ Script.include("https://hifi-public.s3.amazonaws.com/scripts/utilities.js"); @@ -19,31 +19,18 @@ var scriptURL = Script.resolvePath('flashlight.js?123123'); var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"; -var center = Vec3.sum(Vec3.sum(MyAvatar.position, { - x: 0, - y: 0.5, - z: 0 -}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); +var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); var flashlight = Entities.addEntity({ - type: "Model", - modelURL: modelURL, - position: center, - dimensions: { - x: 0.08, - y: 0.30, - z: 0.08 - }, - collisionsWillMove: true, - shapeType: 'box', - script: scriptURL -}); - - -function cleanup() { - //commenting out the line below makes this persistent. to delete at cleanup, uncomment - //Entities.deleteEntity(flashlight); -} - - -Script.scriptEnding.connect(cleanup); \ No newline at end of file + type: "Model", + modelURL: modelURL, + position: center, + dimensions: { + x: 0.08, + y: 0.30, + z: 0.08 + }, + collisionsWillMove: true, + shapeType: 'box', + script: scriptURL +}); \ No newline at end of file diff --git a/examples/toys/flashlight/flashlight.js b/examples/toys/flashlight/flashlight.js index 5afaed829c..5563001d07 100644 --- a/examples/toys/flashlight/flashlight.js +++ b/examples/toys/flashlight/flashlight.js @@ -14,20 +14,18 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - -(function() { +/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ +(function () { Script.include("../../libraries/utils.js"); var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; - var _this; - // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) - Flashlight = function() { - _this = this; - }; + function Flashlight() { + return; + } //if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will var DISABLE_LIGHT_THRESHOLD = 0.7; @@ -48,7 +46,7 @@ x: 0, y: -0.1, z: 0 - } + }; // Evaluate the world light entity positions and orientations from the model ones function evalLightWorldTransform(modelPos, modelRot) { @@ -57,14 +55,14 @@ p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; - }; + } function glowLightWorldTransform(modelPos, modelRot) { return { p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, GLOW_LIGHT_POSITION)), q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) }; - }; + } Flashlight.prototype = { @@ -73,13 +71,13 @@ whichHand: null, hasSpotlight: false, spotlight: null, - setRightHand: function() { + setRightHand: function () { this.hand = 'RIGHT'; }, - setLeftHand: function() { + setLeftHand: function () { this.hand = 'LEFT'; }, - startNearGrab: function() { + startNearGrab: function () { if (!this.hasSpotlight) { //this light casts the beam @@ -125,10 +123,10 @@ } }, - setWhichHand: function() { + setWhichHand: function () { this.whichHand = this.hand; }, - continueNearGrab: function() { + continueNearGrab: function () { if (this.whichHand === null) { //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten this.setWhichHand(); @@ -137,7 +135,7 @@ this.changeLightWithTriggerPressure(this.whichHand); } }, - releaseGrab: function() { + releaseGrab: function () { //delete the lights and reset state if (this.hasSpotlight) { Entities.deleteEntity(this.spotlight); @@ -149,7 +147,7 @@ this.lightOn = false; } }, - updateLightPositions: function() { + updateLightPositions: function () { var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); //move the two lights along the vectors we set above @@ -161,16 +159,16 @@ Entities.editEntity(this.spotlight, { position: lightTransform.p, rotation: lightTransform.q, - }) + }); Entities.editEntity(this.glowLight, { position: glowLightTransform.p, rotation: glowLightTransform.q, - }) + }); }, - changeLightWithTriggerPressure: function(flashLightHand) { + changeLightWithTriggerPressure: function (flashLightHand) { var handClickString = flashLightHand + "_HAND_CLICK"; @@ -183,9 +181,9 @@ } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { this.turnLightOn(); } - return + return; }, - turnLightOff: function() { + turnLightOff: function () { this.playSoundAtCurrentPosition(false); Entities.editEntity(this.spotlight, { intensity: 0 @@ -193,11 +191,9 @@ Entities.editEntity(this.glowLight, { intensity: 0 }); - this.lightOn = false - - + this.lightOn = false; }, - turnLightOn: function() { + turnLightOn: function () { this.playSoundAtCurrentPosition(true); Entities.editEntity(this.glowLight, { @@ -206,35 +202,35 @@ Entities.editEntity(this.spotlight, { intensity: 2 }); - this.lightOn = true + this.lightOn = true; }, // preload() will be called when the entity has become visible (or known) to the interface // it gives us a chance to set our local JavaScript object up. In this case it means: // * remembering our entityID, so we can access it in cases where we're called without an entityID - preload: function(entityID) { + preload: function (entityID) { this.entityID = entityID; this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); }, - playSoundAtCurrentPosition: function(playOnSound) { + playSoundAtCurrentPosition: function (playOnSound) { var position = Entities.getEntityProperties(this.entityID, "position").position; var audioProperties = { - volume: 0.5, + volume: 0.25, position: position - } - if (playOnSound) { - Audio.playSound(this.ON_SOUND, audioProperties) - } else { - Audio.playSound(this.OFF_SOUND, audioProperties) + }; + if (playOnSound) { + Audio.playSound(this.ON_SOUND, audioProperties); + } else { + Audio.playSound(this.OFF_SOUND, audioProperties); } }, // unload() will be called when our entity is no longer available. It may be because we were deleted, // or because we've left the domain or quit the application. - unload: function(entityID) { + unload: function () { if (this.hasSpotlight) { Entities.deleteEntity(this.spotlight); @@ -252,4 +248,4 @@ // entity scripts always need to return a newly constructed object of our type return new Flashlight(); -}) \ No newline at end of file +}); \ No newline at end of file From 6b468ee87bcd409bd701d1c98af88f7b67f4523e Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 13:10:25 -0700 Subject: [PATCH 06/25] Add the doll --- examples/toys/doll/createDoll.js | 41 +++++++++++ examples/toys/doll/doll.js | 117 +++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 examples/toys/doll/createDoll.js create mode 100644 examples/toys/doll/doll.js diff --git a/examples/toys/doll/createDoll.js b/examples/toys/doll/createDoll.js new file mode 100644 index 0000000000..fef55bd95b --- /dev/null +++ b/examples/toys/doll/createDoll.js @@ -0,0 +1,41 @@ +/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ + +function createDoll() { + var modelURL = "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx"; + var scriptURL = Script.resolvePath("doll.js"); + var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 + }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); + + var naturalDimensions = { + x: 1.63, + y: 1.67, + z: 0.26 + }; + var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15); + var doll = Entities.addEntity({ + type: "Model", + name: "doll", + modelURL: modelURL, + script: scriptURL, + position: center, + shapeType: 'box', + dimensions: desiredDimensions, + gravity: { + x: 0, + y: 0, + z: 0 + }, + velocity: { + x: 0, + y: 0, + z: 0 + }, + collisionsWillMove: true + }); + return doll; +} + +createDoll(); \ No newline at end of file diff --git a/examples/toys/doll/doll.js b/examples/toys/doll/doll.js new file mode 100644 index 0000000000..1417798799 --- /dev/null +++ b/examples/toys/doll/doll.js @@ -0,0 +1,117 @@ +// doll.js +// +// Script Type: Entity +// Created by Eric Levin on 9/21/15. +// Copyright 2015 High Fidelity, Inc. +// +// This entity script breathes movement and sound- one might even say life- into a doll. +// This entity script plays an animation and a sound while you hold +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ +(function () { + Script.include("../../utilities.js"); + Script.include("../../libraries/utils.js"); + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + var Doll = function () { + this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; + + }; + + Doll.prototype = { + startAnimationSetting: JSON.stringify({ + running: true, + fps: 30, + startFrame: 0, + lastFrame: 128, + startAutomatically: true + }), + stopAnimationSetting: JSON.stringify({ + running: false, + }), + audioInjector: null, + isGrabbed: false, + leftHand: false, + rightHand: false, + handIsSet: false, + setLeftHand: function () { + if (this.handIsSet === false) { + this.leftHand = true; + this.rightHand = false; + this.setHand = 'left'; + this.handIsSet = true; + } else { + this.currentHand = 'left' + } + }, + setRightHand: function () { + if (this.handIsSet === false) { + this.rightHand = true; + this.leftHand = false; + this.setHand = 'right'; + this.handIsSet = true; + } else { + this.currentHand = 'right' + } + }, + startNearGrab: function () { + if (this.isGrabbed === false) { + Entities.editEntity(this.entityID, { + animationURL: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", + animationSettings: this.startAnimationSetting + }); + + var position = Entities.getEntityProperties(this.entityID, "position").position; + this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], { + position: position, + volume: 0.1 + }); + this.isGrabbed = true; + } + + }, + continueNearGrab: function () { + if (this.setHand === this.currentHand) { + print('CONTINUING GRAB IN HAND') + var position = Entities.getEntityProperties(this.entityID, "position").position; + this.audioInjector.options.position = position; + }else{ + print('NOT SAME HAND GRABBING') + } + + }, + + releaseGrab: function () { + if (this.isGrabbed === true) { + this.audioInjector.stop(); + Entities.editEntity(this.entityID, { + animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", + }); + this.isGrabbed = false; + } + if(this.setHand===this.currentHand){ + print('SAME HAND LET GO') + } + else{ + print('DIFFERENT HAND KEEP HOLDING') + } + + }, + + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * connecting to the update signal so we can check our grabbed state + preload: function (entityID) { + this.entityID = entityID; + + }, + }; + + // entity scripts always need to return a newly constructed object of our type + return new Doll(); +}); \ No newline at end of file From ba44390f79fc51ce26c31efb50e5b6d22d450e31 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 13:20:21 -0700 Subject: [PATCH 07/25] Rename touch to grab non colliding --- examples/controllers/handControllerGrab.js | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index af1c97da68..bb806e14f1 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -84,10 +84,11 @@ var STATE_DISTANCE_HOLDING = 1; var STATE_CONTINUE_DISTANCE_HOLDING = 2; var STATE_NEAR_GRABBING = 3; var STATE_CONTINUE_NEAR_GRABBING = 4; -var STATE_NEAR_TOUCHING = 5; -var STATE_CONTINUE_NEAR_TOUCHING = 6; +var STATE_NEAR_GRABBING_NON_COLLIDING = 5; +var STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING = 6; var STATE_RELEASE = 7; + var GRAB_USER_DATA_KEY = "grabKey"; function controller(hand, triggerAction) { @@ -127,11 +128,11 @@ function controller(hand, triggerAction) { case STATE_CONTINUE_NEAR_GRABBING: this.continueNearGrabbing(); break; - case STATE_NEAR_TOUCHING: - this.nearTouching(); + case STATE_NEAR_GRABBING_NON_COLLIDING: + this.nearGrabbingNonColliding(); break; - case STATE_CONTINUE_NEAR_TOUCHING: - this.continueNearTouching(); + case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: + this.continueNearGrabbingNonColliding(); break; case STATE_RELEASE: this.release(); @@ -233,8 +234,8 @@ function controller(hand, triggerAction) { } else if (props.locked === 0 && props.collisionsWillMove === 1) { this.state = STATE_NEAR_GRABBING; } else if (props.collisionsWillMove === 0) { - // We have grabbed a non-physical object, so we want to trigger a touch event as opposed to a grab event - this.state = STATE_NEAR_TOUCHING; + // We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event + this.state = STATE_NEAR_GRABBING_NON_COLLIDING; } } } @@ -369,21 +370,21 @@ function controller(hand, triggerAction) { this.currentObjectTime = Date.now(); } - this.nearTouching = function() { + this.nearGrabbingNonColliding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; } - Entities.callEntityMethod(this.grabbedEntity, "startNearTouch") - this.state = STATE_CONTINUE_NEAR_TOUCHING; + Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding") + this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING; } - this.continueNearTouching = function() { + this.continueNearGrabNonColliding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; } - Entities.callEntityMethod(this.grabbedEntity, "continueNearTouch"); + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabNonColliding"); } From 381a24951e68ccff1b4ce52bdd350cd20be70dea Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 16:56:46 -0700 Subject: [PATCH 08/25] Update grab script to handle touching, better naming for non colliding grab functions --- examples/controllers/handControllerGrab.js | 266 ++++++++++++------- examples/entityScripts/changeColorOnTouch.js | 71 +++++ 2 files changed, 243 insertions(+), 94 deletions(-) create mode 100644 examples/entityScripts/changeColorOnTouch.js diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index bb806e14f1..5818815bb2 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -8,11 +8,10 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ Script.include("../libraries/utils.js"); - ///////////////////////////////////////////////////////////////// // // these tune time-averaging and "on" value for analog trigger @@ -110,40 +109,40 @@ function controller(hand, triggerAction) { this.state = 0; this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value - - this.update = function() { + var _this = this; + this.update = function () { switch (this.state) { - case STATE_SEARCHING: - this.search(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - this.nearGrabbing(); - break; - case STATE_CONTINUE_NEAR_GRABBING: - this.continueNearGrabbing(); - break; - case STATE_NEAR_GRABBING_NON_COLLIDING: - this.nearGrabbingNonColliding(); - break; - case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: - this.continueNearGrabbingNonColliding(); - break; - case STATE_RELEASE: - this.release(); - break; + case STATE_SEARCHING: + this.search(); + this.touchTest(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + this.nearGrabbing(); + break; + case STATE_CONTINUE_NEAR_GRABBING: + this.continueNearGrabbing(); + break; + case STATE_NEAR_GRABBING_NON_COLLIDING: + this.nearGrabbingNonColliding(); + break; + case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: + this.continueNearGrabbingNonColliding(); + break; + case STATE_RELEASE: + this.release(); + break; } - } - - - this.lineOn = function(closePoint, farPoint, color) { + }; + _this.pointerIDs = []; + this.lineOn = function (closePoint, farPoint, color) { // draw a line - if (this.pointer == null) { + if (this.pointer === null) { this.pointer = Entities.addEntity({ type: "Line", name: "pointer", @@ -154,6 +153,7 @@ function controller(hand, triggerAction) { color: color, lifetime: LIFETIME }); + _this.pointerIDs.push(this.pointer); } else { Entities.editEntity(this.pointer, { position: closePoint, @@ -162,33 +162,40 @@ function controller(hand, triggerAction) { lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME }); } - } + + }; - this.lineOff = function() { - if (this.pointer != null) { + this.lineOff = function () { + if (this.pointer !== null) { Entities.deleteEntity(this.pointer); } + var index = _this.pointerIDs.indexOf(this.pointer); + if (index > -1) { + _this.pointerIDs.splice(index, 1); + } this.pointer = null; - } + }; - this.triggerSmoothedSqueezed = function() { + this.triggerSmoothedSqueezed = function () { var triggerValue = Controller.getActionValue(this.triggerAction); // smooth out trigger value this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); return this.triggerValue > TRIGGER_ON_VALUE; - } + }; - this.triggerSqueezed = function() { + this.triggerSqueezed = function () { var triggerValue = Controller.getActionValue(this.triggerAction); return triggerValue > TRIGGER_ON_VALUE; - } + }; + + + this.search = function () { - this.search = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -220,10 +227,10 @@ function controller(hand, triggerAction) { // forward ray test failed, try sphere test. var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS); var minDistance = GRAB_RADIUS; - var grabbedEntity = null; - for (var i = 0; i < nearbyEntities.length; i++) { - var props = Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]); - var distance = Vec3.distance(props.position, handPosition); + var i, props, distance; + for (i = 0; i < nearbyEntities.length; i++) { + props = Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]); + distance = Vec3.distance(props.position, handPosition); if (distance < minDistance && props.name !== "pointer") { this.grabbedEntity = nearbyEntities[i]; minDistance = distance; @@ -238,10 +245,11 @@ function controller(hand, triggerAction) { this.state = STATE_NEAR_GRABBING_NON_COLLIDING; } } - } + + }; - this.distanceHolding = function() { + this.distanceHolding = function () { var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]); @@ -259,25 +267,26 @@ function controller(hand, triggerAction) { targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME }); - if (this.actionID == NULL_ACTION_ID) { + if (this.actionID === NULL_ACTION_ID) { this.actionID = null; } - if (this.actionID != null) { + if (this.actionID !== null) { this.state = STATE_CONTINUE_DISTANCE_HOLDING; this.activateEntity(this.grabbedEntity); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - if (this.hand === RIGHT_HAND) { Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); } else { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } } - } + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); - this.continueDistanceHolding = function() { + }; + + + this.continueDistanceHolding = function () { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -323,10 +332,10 @@ function controller(hand, triggerAction) { targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME }); - } + }; - this.nearGrabbing = function() { + this.nearGrabbing = function () { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -344,51 +353,34 @@ function controller(hand, triggerAction) { var objectRotation = grabbedProperties.rotation; var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); - currentObjectPosition = grabbedProperties.position; + var currentObjectPosition = grabbedProperties.position; var offset = Vec3.subtract(currentObjectPosition, handPosition); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); this.actionID = Entities.addAction("hold", this.grabbedEntity, { - hand: this.hand == RIGHT_HAND ? "right" : "left", + hand: this.hand === RIGHT_HAND ? "right" : "left", timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: offsetPosition, relativeRotation: offsetRotation }); - if (this.actionID == NULL_ACTION_ID) { + if (this.actionID === NULL_ACTION_ID) { this.actionID = null; } else { this.state = STATE_CONTINUE_NEAR_GRABBING; - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); if (this.hand === RIGHT_HAND) { Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); } else { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } + Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); + } this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm); this.currentObjectTime = Date.now(); - } + }; - this.nearGrabbingNonColliding = function() { - if (!this.triggerSmoothedSqueezed()) { - this.state = STATE_RELEASE; - return; - } - Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding") - this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING; - } - - this.continueNearGrabNonColliding = function() { - if (!this.triggerSmoothedSqueezed()) { - this.state = STATE_RELEASE; - return; - } - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabNonColliding"); - } - - - this.continueNearGrabbing = function() { + this.continueNearGrabbing = function () { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -405,10 +397,96 @@ function controller(hand, triggerAction) { this.currentHandControllerPosition = handControllerPosition; this.currentObjectTime = now; Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - } + }; + this.nearGrabbingNonColliding = function () { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + Entities.callEntityMethod(this.grabbedEntity, "startNearGrabNonColliding"); + this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING; + }; - this.computeReleaseVelocity = function(deltaPosition, deltaTime, useMultiplier) { + this.continueNearGrabbingNonColliding = function () { + if (!this.triggerSmoothedSqueezed()) { + this.state = STATE_RELEASE; + return; + } + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding"); + }; + + _this.allTouchedIDs = {}; + this.touchTest = function () { + //print('touch test'); + var maxDistance = 0.05; + var leftHandPosition = MyAvatar.getLeftPalmPosition(); + var rightHandPosition = MyAvatar.getRightPalmPosition(); + var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); + var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); + var ids = []; + if (leftEntities.length !== 0) { + leftEntities.forEach(function (entity) { + ids.push(entity); + }); + + } + if (rightEntities.length !== 0) { + rightEntities.forEach(function (entity) { + ids.push(entity); + }); + } + + ids.forEach(function (id) { + + var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); + if (props.name === 'pointer') { + return; + } else { + var entityMinPoint = props.boundingBox.brn; + var entityMaxPoint = props.boundingBox.tfl; + var leftIsTouching = pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint); + var rightIsTouching = pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint); + + if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === undefined) { + // we haven't been touched before, but either right or left is touching us now + _this.allTouchedIDs[id] = true; + _this.startTouch(id); + } else if ((leftIsTouching || rightIsTouching) && _this.allTouchedIDs[id] === true) { + // we have been touched before and are still being touched + // continue touch + _this.continueTouch(id); + } else if (_this.allTouchedIDs[id] === true) { + delete _this.allTouchedIDs[id]; + _this.stopTouch(id); + + } else { + //we are in another state + return; + } + } + + }); + + }; + + this.startTouch = function (entityID) { + // print('START TOUCH' + entityID); + Entities.callEntityMethod(entityID, "startTouch"); + }; + + this.continueTouch = function (entityID) { + // print('CONTINUE TOUCH' + entityID); + Entities.callEntityMethod(entityID, "continueTouch"); + }; + + this.stopTouch = function (entityID) { + // print('STOP TOUCH' + entityID); + Entities.callEntityMethod(entityID, "stopTouch"); + + }; + + this.computeReleaseVelocity = function (deltaPosition, deltaTime, useMultiplier) { if (deltaTime > 0.0 && !vec3equal(deltaPosition, ZERO_VEC)) { var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger @@ -423,13 +501,13 @@ function controller(hand, triggerAction) { this.grabbedVelocity = Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER); } } - } + }; - this.release = function() { + this.release = function () { this.lineOff(); - if (this.grabbedEntity != null && this.actionID != null) { + if (this.grabbedEntity !== null && this.actionID !== null) { Entities.deleteAction(this.grabbedEntity, this.actionID); Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); } @@ -445,28 +523,28 @@ function controller(hand, triggerAction) { this.grabbedEntity = null; this.actionID = null; this.state = STATE_SEARCHING; - } + }; - this.cleanup = function() { - release(); - } + this.cleanup = function () { + this.release(); + }; - this.activateEntity = function(entity) { + this.activateEntity = function () { var data = { activated: true, avatarId: MyAvatar.sessionUUID }; setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); - } + }; - this.deactivateEntity = function(entity) { + this.deactivateEntity = function () { var data = { activated: false, avatarId: null }; setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); - } + }; } @@ -487,4 +565,4 @@ function cleanup() { Script.scriptEnding.connect(cleanup); -Script.update.connect(update) \ No newline at end of file +Script.update.connect(update); \ No newline at end of file diff --git a/examples/entityScripts/changeColorOnTouch.js b/examples/entityScripts/changeColorOnTouch.js new file mode 100644 index 0000000000..b3082fa9d5 --- /dev/null +++ b/examples/entityScripts/changeColorOnTouch.js @@ -0,0 +1,71 @@ +// +// changeColorOnTouch.js +// examples/entityScripts +// +// Created by Brad Hefta-Gaub on 11/1/14. +// Additions by James B. Pollack @imgntn on 9/23/2015 +// Copyright 2014 High Fidelity, Inc. +// +// ATTENTION: Requires you to run handControllerGrab.js +// This is an example of an entity script which when assigned to a non-model entity like a box or sphere, will +// change the color of the entity when you touch it. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function () { + ChangeColorOnTouch = function () { + this.oldColor = {}; + this.oldColorKnown = false; + }; + + ChangeColorOnTouch.prototype = { + + storeOldColor: function (entityID) { + var oldProperties = Entities.getEntityProperties(entityID); + this.oldColor = oldProperties.color; + this.oldColorKnown = true; + print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); + }, + + preload: function (entityID) { + print("preload"); + this.entityID = entityID; + this.storeOldColor(entityID); + }, + + startTouch: function () { + print("startTouch"); + if (!this.oldColorKnown) { + this.storeOldColor(this.entityID); + } + Entities.editEntity(this.entityID, { + color: { + red: 0, + green: 255, + blue: 255 + } + }); + }, + + continueTouch: function () { + //unused here + return; + }, + + stopTouch: function () { + print("stopTouch"); + if (this.oldColorKnown) { + print("leave restoring old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); + Entities.editEntity(this.entityID, { + color: this.oldColor + }); + } + } + + + }; + + return new ChangeColorOnTouch(); +}) \ No newline at end of file From 82f178a3532a878c1a4cf74b1d4f31f08ba7dab1 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 17:43:08 -0700 Subject: [PATCH 09/25] tweaks --- examples/toys/doll/doll.js | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/examples/toys/doll/doll.js b/examples/toys/doll/doll.js index 1417798799..835685e6bb 100644 --- a/examples/toys/doll/doll.js +++ b/examples/toys/doll/doll.js @@ -38,24 +38,14 @@ rightHand: false, handIsSet: false, setLeftHand: function () { - if (this.handIsSet === false) { - this.leftHand = true; - this.rightHand = false; - this.setHand = 'left'; - this.handIsSet = true; - } else { + this.currentHand = 'left' - } + }, setRightHand: function () { - if (this.handIsSet === false) { - this.rightHand = true; - this.leftHand = false; - this.setHand = 'right'; - this.handIsSet = true; - } else { + this.currentHand = 'right' - } + }, startNearGrab: function () { if (this.isGrabbed === false) { @@ -70,18 +60,17 @@ volume: 0.1 }); this.isGrabbed = true; + this.initialHand = this.hand; + print('INITIAL HAND:::' +this.initialHand) } }, continueNearGrab: function () { - if (this.setHand === this.currentHand) { + print('CONTINUING GRAB IN HAND') var position = Entities.getEntityProperties(this.entityID, "position").position; this.audioInjector.options.position = position; - }else{ - print('NOT SAME HAND GRABBING') - } - + }, releaseGrab: function () { @@ -92,12 +81,7 @@ }); this.isGrabbed = false; } - if(this.setHand===this.currentHand){ - print('SAME HAND LET GO') - } - else{ - print('DIFFERENT HAND KEEP HOLDING') - } + }, From 37ecd180545dcec7b6812af728c270518eceaaf7 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 17:44:28 -0700 Subject: [PATCH 10/25] put distant grab inside of conditional --- examples/controllers/handControllerGrab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5818815bb2..c6c1befda7 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -279,8 +279,9 @@ function controller(hand, triggerAction) { } else { Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); } + Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); } - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + }; From 7efd15c3a214e8b39a8864a290ff21b2898ef978 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Wed, 23 Sep 2015 18:01:18 -0700 Subject: [PATCH 11/25] Update doll to stop screaming when released, use only one hand a a time, spatialize audio position --- examples/toys/doll/createDoll.js | 11 ++++++++ examples/toys/doll/doll.js | 45 +++++++++++++------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/examples/toys/doll/createDoll.js b/examples/toys/doll/createDoll.js index fef55bd95b..8cb93a15df 100644 --- a/examples/toys/doll/createDoll.js +++ b/examples/toys/doll/createDoll.js @@ -1,3 +1,14 @@ +// createDoll.js +// +// Script Type: Entity +// Created by James B. Pollack @imgntn 9/23/2015 +// Copyright 2015 High Fidelity, Inc. +// +// ATTENTION: requires that you run handController.js +// Creates a doll entity in front of you. +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ function createDoll() { diff --git a/examples/toys/doll/doll.js b/examples/toys/doll/doll.js index 835685e6bb..12a41d5e98 100644 --- a/examples/toys/doll/doll.js +++ b/examples/toys/doll/doll.js @@ -4,8 +4,8 @@ // Created by Eric Levin on 9/21/15. // Copyright 2015 High Fidelity, Inc. // -// This entity script breathes movement and sound- one might even say life- into a doll. -// This entity script plays an animation and a sound while you hold +// ATTENTION: requires that you run handController.js +// This entity script plays an animation and a sound while you hold it. // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // @@ -14,11 +14,9 @@ Script.include("../../utilities.js"); Script.include("../../libraries/utils.js"); - // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember - // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + // this is the "constructor" for the entity as a JS object we don't do much here var Doll = function () { this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; - }; Doll.prototype = { @@ -34,19 +32,14 @@ }), audioInjector: null, isGrabbed: false, - leftHand: false, - rightHand: false, - handIsSet: false, setLeftHand: function () { - - this.currentHand = 'left' - + this.hand = 'left'; }, + setRightHand: function () { - - this.currentHand = 'right' - + this.hand = 'right'; }, + startNearGrab: function () { if (this.isGrabbed === false) { Entities.editEntity(this.entityID, { @@ -61,38 +54,36 @@ }); this.isGrabbed = true; this.initialHand = this.hand; - print('INITIAL HAND:::' +this.initialHand) + } - }, + continueNearGrab: function () { - - print('CONTINUING GRAB IN HAND') - var position = Entities.getEntityProperties(this.entityID, "position").position; - this.audioInjector.options.position = position; - + var position = Entities.getEntityProperties(this.entityID, "position").position; + var audioOptions = { + position: position + }; + this.audioInjector.options = audioOptions; }, releaseGrab: function () { - if (this.isGrabbed === true) { + if (this.isGrabbed === true && this.hand === this.initialHand) { this.audioInjector.stop(); + Entities.editEntity(this.entityID, { + animationSettings: this.stopAnimationSetting + }); Entities.editEntity(this.entityID, { animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", }); this.isGrabbed = false; } - - }, - // preload() will be called when the entity has become visible (or known) to the interface // it gives us a chance to set our local JavaScript object up. In this case it means: // * remembering our entityID, so we can access it in cases where we're called without an entityID - // * connecting to the update signal so we can check our grabbed state preload: function (entityID) { this.entityID = entityID; - }, }; From 17e3e9394fbae1af48e93eefc8acb4ef45fc3604 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 24 Sep 2015 12:33:11 -0700 Subject: [PATCH 12/25] allow head translation for 3rd person screenie IK --- .../defaultAvatar_full/avatar-animation.json | 3 +- interface/src/avatar/MyAvatar.cpp | 1 - .../animation/src/AnimInverseKinematics.cpp | 133 ++++++++++-------- .../animation/src/AnimInverseKinematics.h | 24 +++- libraries/animation/src/AnimNodeLoader.cpp | 3 +- libraries/animation/src/AnimOverlay.cpp | 4 +- libraries/animation/src/Rig.cpp | 2 + 7 files changed, 101 insertions(+), 69 deletions(-) diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index 550a95e980..edde635176 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -31,7 +31,8 @@ { "jointName": "Head", "positionVar": "headPosition", - "rotationVar": "headRotation" + "rotationVar": "headRotation", + "typeVar": "headType" } ] }, diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c499f9f5bb..00ced2eb13 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -141,7 +141,6 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { } void MyAvatar::reset() { - _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index e31f7795f3..7f32d8a2fa 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -42,9 +42,8 @@ void AnimInverseKinematics::loadPoses(const AnimPoseVec& poses) { void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) const { int numJoints = (int)_relativePoses.size(); - absolutePoses.clear(); - absolutePoses.resize(numJoints); assert(numJoints <= _skeleton->getNumJoints()); + assert(numJoints == (int)absolutePoses.size()); for (int i = 0; i < numJoints; ++i) { int parentIndex = _skeleton->getParentIndex(i); if (parentIndex < 0) { @@ -55,7 +54,11 @@ void AnimInverseKinematics::computeAbsolutePoses(AnimPoseVec& absolutePoses) con } } -void AnimInverseKinematics::setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar) { +void AnimInverseKinematics::setTargetVars( + const QString& jointName, + const QString& positionVar, + const QString& rotationVar, + const QString& typeVar) { // if there are dups, last one wins. bool found = false; for (auto& targetVar: _targetVarVec) { @@ -63,13 +66,14 @@ void AnimInverseKinematics::setTargetVars(const QString& jointName, const QStrin // update existing targetVar targetVar.positionVar = positionVar; targetVar.rotationVar = rotationVar; + targetVar.typeVar = typeVar; found = true; break; } } if (!found) { // create a new entry - _targetVarVec.push_back(IKTargetVar(jointName, positionVar, rotationVar)); + _targetVarVec.push_back(IKTargetVar(jointName, positionVar, rotationVar, typeVar)); } } @@ -86,6 +90,7 @@ static int findRootJointInSkeleton(AnimSkeleton::ConstPointer skeleton, int inde void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector& targets) { // build a list of valid targets from _targetVarVec and animVars + _maxTargetIndex = -1; bool removeUnfoundJoints = false; for (auto& targetVar : _targetVarVec) { if (targetVar.jointIndex == -1) { @@ -100,14 +105,17 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: removeUnfoundJoints = true; } } else { - // TODO: get this done without a double-lookup of each var in animVars IKTarget target; AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, _relativePoses); target.pose.trans = animVars.lookup(targetVar.positionVar, defaultPose.trans); target.pose.rot = animVars.lookup(targetVar.rotationVar, defaultPose.rot); + target.setType(animVars.lookup(targetVar.typeVar, QString(""))); target.rootIndex = targetVar.rootIndex; target.index = targetVar.jointIndex; targets.push_back(target); + if (target.index > _maxTargetIndex) { + _maxTargetIndex = target.index; + } } } @@ -129,9 +137,10 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: } } -void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vector& targets) { +void AnimInverseKinematics::solveWithCyclicCoordinateDescent(const std::vector& targets) { // compute absolute poses that correspond to relative target poses AnimPoseVec absolutePoses; + absolutePoses.resize(_relativePoses.size()); computeAbsolutePoses(absolutePoses); // clear the accumulators before we start the IK solver @@ -139,25 +148,23 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vectorgetParentIndex(tipIndex); - while (pivotIndex != -1 && error > ACCEPTABLE_RELATIVE_ERROR) { + float fractionDenominator = 1.0f; + while (pivotIndex != -1) { // compute the two lines that should be aligned glm::vec3 jointPosition = absolutePoses[pivotIndex].trans; glm::vec3 leverArm = tip - jointPosition; @@ -166,59 +173,60 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vector EPSILON) { + glm::quat deltaRotation; + const float MIN_AXIS_LENGTH = 1.0e-4f; + if (axisLength > MIN_AXIS_LENGTH) { // compute deltaRotation for alignment (brings tip closer to target) axis /= axisLength; float angle = acosf(glm::dot(leverArm, targetLine) / (glm::length(leverArm) * glm::length(targetLine))); // NOTE: even when axisLength is not zero (e.g. lever-arm and pivot-arm are not quite aligned) it is // still possible for the angle to be zero so we also check that to avoid unnecessary calculations. - if (angle > EPSILON) { + const float MIN_ADJUSTMENT_ANGLE = 1.0e-4f; + if (angle > MIN_ADJUSTMENT_ANGLE) { // reduce angle by half: slows convergence but adds stability to IK solution - angle = 0.5f * angle; - glm::quat deltaRotation = glm::angleAxis(angle, axis); - - int parentIndex = _skeleton->getParentIndex(pivotIndex); - if (parentIndex == -1) { - // TODO? apply constraints to root? - // TODO? harvest the root's transform as movement of entire skeleton? - } else { - // compute joint's new parent-relative rotation - // Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q - glm::quat newRot = glm::normalize(glm::inverse( - absolutePoses[parentIndex].rot) * - deltaRotation * - absolutePoses[pivotIndex].rot); - RotationConstraint* constraint = getConstraint(pivotIndex); - if (constraint) { - bool constrained = constraint->apply(newRot); - if (constrained) { - // the constraint will modify the movement of the tip so we have to compute the modified - // model-frame deltaRotation - // Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^ - deltaRotation = absolutePoses[parentIndex].rot * - newRot * - glm::inverse(absolutePoses[pivotIndex].rot); - } - } - // store the rotation change in the accumulator - _accumulators[pivotIndex].add(newRot); - } - // this joint has been changed so we check to see if it has the lowest index - if (pivotIndex < lowestMovedIndex) { - lowestMovedIndex = pivotIndex; - } - - // keep track of tip's new position as we descend towards root - tip = jointPosition + deltaRotation * leverArm; - error = glm::length(targetPose.trans - tip); + angle /= fractionDenominator; + deltaRotation = glm::angleAxis(angle, axis); } } + fractionDenominator++; + + int parentIndex = _skeleton->getParentIndex(pivotIndex); + if (parentIndex == -1) { + // TODO? apply constraints to root? + // TODO? harvest the root's transform as movement of entire skeleton? + } else { + // compute joint's new parent-relative rotation + // Q' = dQ * Q and Q = Qp * q --> q' = Qp^ * dQ * Q + glm::quat newRot = glm::normalize(glm::inverse( + absolutePoses[parentIndex].rot) * + deltaRotation * + absolutePoses[pivotIndex].rot); + RotationConstraint* constraint = getConstraint(pivotIndex); + if (constraint) { + bool constrained = constraint->apply(newRot); + if (constrained) { + // the constraint will modify the movement of the tip so we have to compute the modified + // model-frame deltaRotation + // Q' = Qp^ * dQ * Q --> dQ = Qp * Q' * Q^ + deltaRotation = absolutePoses[parentIndex].rot * + newRot * + glm::inverse(absolutePoses[pivotIndex].rot); + } + } + // store the rotation change in the accumulator + _accumulators[pivotIndex].add(newRot); + } + // this joint has been changed so we check to see if it has the lowest index + if (pivotIndex < lowestMovedIndex) { + lowestMovedIndex = pivotIndex; + } + + // keep track of tip's new position as we descend towards root + tip = jointPosition + deltaRotation * leverArm; + pivotIndex = _skeleton->getParentIndex(pivotIndex); } - if (largestError < error) { - largestError = error; - } } ++numLoops; @@ -238,7 +246,7 @@ void AnimInverseKinematics::solveWithCyclicCoordinateDescent(std::vector ACCEPTABLE_RELATIVE_ERROR && numLoops < MAX_IK_LOOPS && usecTimestampNow() < expiry); + } while (numLoops < MAX_IK_LOOPS); // finally set the relative rotation of each tip to agree with absolute target rotation for (auto& target: targets) { @@ -380,7 +388,7 @@ void AnimInverseKinematics::initConstraints() { } } - _constraints.clear(); + clearConstraints(); for (int i = 0; i < numJoints; ++i) { // compute the joint's baseName and remember whether its prefix was "Left" or not QString baseName = _skeleton->getJointName(i); @@ -639,9 +647,12 @@ void AnimInverseKinematics::setSkeletonInternal(AnimSkeleton::ConstPointer skele targetVar.jointIndex = -1; } - _maxTargetIndex = 0; + _maxTargetIndex = -1; + + for (auto& accumulator: _accumulators) { + accumulator.clearAndClean(); + } - _accumulators.clear(); if (skeleton) { initConstraints(); } else { diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 70808f5919..9d0fd0f557 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -31,20 +31,33 @@ public: void loadPoses(const AnimPoseVec& poses); void computeAbsolutePoses(AnimPoseVec& absolutePoses) const; - void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar); + void setTargetVars(const QString& jointName, const QString& positionVar, const QString& rotationVar, const QString& typeVar); virtual const AnimPoseVec& evaluate(const AnimVariantMap& animVars, float dt, AnimNode::Triggers& triggersOut) override; virtual const AnimPoseVec& overlay(const AnimVariantMap& animVars, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) override; protected: struct IKTarget { + enum class Type { + RotationAndPosition, + RotationOnly + }; AnimPose pose; int index; int rootIndex; + Type type = Type::RotationAndPosition; + + void setType(const QString& typeVar) { + if (typeVar == "RotationOnly") { + type = Type::RotationOnly; + } else { + type = Type::RotationAndPosition; + } + } }; void computeTargets(const AnimVariantMap& animVars, std::vector& targets); - void solveWithCyclicCoordinateDescent(std::vector& targets); + void solveWithCyclicCoordinateDescent(const std::vector& targets); virtual void setSkeletonInternal(AnimSkeleton::ConstPointer skeleton); // for AnimDebugDraw rendering @@ -55,15 +68,20 @@ protected: void initConstraints(); struct IKTargetVar { - IKTargetVar(const QString& jointNameIn, const QString& positionVarIn, const QString& rotationVarIn) : + IKTargetVar(const QString& jointNameIn, + const QString& positionVarIn, + const QString& rotationVarIn, + const QString& typeVarIn) : positionVar(positionVarIn), rotationVar(rotationVarIn), + typeVar(typeVarIn), jointName(jointNameIn), jointIndex(-1), rootIndex(-1) {} QString positionVar; QString rotationVar; + QString typeVar; QString jointName; int jointIndex; // cached joint index int rootIndex; // cached root index diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index b2afae4728..147025f1cf 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -342,8 +342,9 @@ AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QS READ_STRING(jointName, targetObj, id, jsonUrl, nullptr); READ_STRING(positionVar, targetObj, id, jsonUrl, nullptr); READ_STRING(rotationVar, targetObj, id, jsonUrl, nullptr); + READ_OPTIONAL_STRING(typeVar, targetObj); - node->setTargetVars(jointName, positionVar, rotationVar); + node->setTargetVars(jointName, positionVar, rotationVar, typeVar); }; return node; diff --git a/libraries/animation/src/AnimOverlay.cpp b/libraries/animation/src/AnimOverlay.cpp index 08c4304b08..8f60b972ce 100644 --- a/libraries/animation/src/AnimOverlay.cpp +++ b/libraries/animation/src/AnimOverlay.cpp @@ -51,8 +51,8 @@ const AnimPoseVec& AnimOverlay::evaluate(const AnimVariantMap& animVars, float d _alpha = animVars.lookup(_alphaVar, _alpha); if (_children.size() >= 2) { - auto underPoses = _children[1]->evaluate(animVars, dt, triggersOut); - auto overPoses = _children[0]->overlay(animVars, dt, triggersOut, underPoses); + auto& underPoses = _children[1]->evaluate(animVars, dt, triggersOut); + auto& overPoses = _children[0]->overlay(animVars, dt, triggersOut, underPoses); if (underPoses.size() > 0 && underPoses.size() == overPoses.size()) { _poses.resize(underPoses.size()); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index f1e81df64e..770e857c4a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1065,6 +1065,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { _animVars.set("headPosition", headPos); _animVars.set("headRotation", headRot); + _animVars.set("headType", QString("RotationAndPosition")); _animVars.set("neckPosition", neckPos); _animVars.set("neckRotation", neckRot); @@ -1077,6 +1078,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { _animVars.unset("headPosition"); _animVars.set("headRotation", realLocalHeadOrientation); + _animVars.set("headType", QString("RotationOnly")); _animVars.unset("neckPosition"); _animVars.unset("neckRotation"); } From 59da684eb94dc59e82f95d66cee6d8457a659407 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 24 Sep 2015 13:15:03 -0700 Subject: [PATCH 13/25] make IKTarget::setType() a one-liner --- interface/src/avatar/MyAvatar.cpp | 1 + libraries/animation/src/AnimInverseKinematics.h | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 00ced2eb13..c499f9f5bb 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -141,6 +141,7 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { } void MyAvatar::reset() { + _skeletonModel.reset(); getHead()->reset(); _targetVelocity = glm::vec3(0.0f); diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index 9d0fd0f557..121b35bd9d 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -47,13 +47,7 @@ protected: int rootIndex; Type type = Type::RotationAndPosition; - void setType(const QString& typeVar) { - if (typeVar == "RotationOnly") { - type = Type::RotationOnly; - } else { - type = Type::RotationAndPosition; - } - } + void setType(const QString& typeVar) { type = ((typeVar == "RotationOnly") ? Type::RotationOnly : Type::RotationAndPosition); } }; void computeTargets(const AnimVariantMap& animVars, std::vector& targets); From c1f8cbd1a3c34b26f69336e34a175065a82047c3 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 14:07:15 -0700 Subject: [PATCH 14/25] Remove space before function calls, add spaces before functions --- examples/toys/flashlight/flashlight.js | 82 ++++++++++++-------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/examples/toys/flashlight/flashlight.js b/examples/toys/flashlight/flashlight.js index 5563001d07..9836579afd 100644 --- a/examples/toys/flashlight/flashlight.js +++ b/examples/toys/flashlight/flashlight.js @@ -15,9 +15,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -(function () { +(function() { Script.include("../../libraries/utils.js"); + var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; @@ -31,22 +32,10 @@ var DISABLE_LIGHT_THRESHOLD = 0.7; // These constants define the Spotlight position and orientation relative to the model - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); + var MODEL_LIGHT_POSITION = { x: 0, y: -0.3, z: 0 }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }); - var GLOW_LIGHT_POSITION = { - x: 0, - y: -0.1, - z: 0 - }; + var GLOW_LIGHT_POSITION = { x: 0, y: -0.1, z: 0}; // Evaluate the world light entity positions and orientations from the model ones function evalLightWorldTransform(modelPos, modelRot) { @@ -64,20 +53,21 @@ }; } - Flashlight.prototype = { lightOn: false, hand: null, whichHand: null, hasSpotlight: false, spotlight: null, - setRightHand: function () { + setRightHand: function() { this.hand = 'RIGHT'; }, - setLeftHand: function () { + + setLeftHand: function() { this.hand = 'LEFT'; }, - startNearGrab: function () { + + startNearGrab: function() { if (!this.hasSpotlight) { //this light casts the beam @@ -117,16 +107,17 @@ cutoff: 90, // in degrees }); - this.hasSpotlight = true; } }, - setWhichHand: function () { + + setWhichHand: function() { this.whichHand = this.hand; }, - continueNearGrab: function () { + + continueNearGrab: function() { if (this.whichHand === null) { //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten this.setWhichHand(); @@ -135,7 +126,8 @@ this.changeLightWithTriggerPressure(this.whichHand); } }, - releaseGrab: function () { + + releaseGrab: function() { //delete the lights and reset state if (this.hasSpotlight) { Entities.deleteEntity(this.spotlight); @@ -147,29 +139,28 @@ this.lightOn = false; } }, - updateLightPositions: function () { + + updateLightPositions: function() { var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); //move the two lights along the vectors we set above var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation); - //move them with the entity model Entities.editEntity(this.spotlight, { position: lightTransform.p, rotation: lightTransform.q, }); - Entities.editEntity(this.glowLight, { position: glowLightTransform.p, rotation: glowLightTransform.q, }); }, - changeLightWithTriggerPressure: function (flashLightHand) { + changeLightWithTriggerPressure: function(flashLightHand) { var handClickString = flashLightHand + "_HAND_CLICK"; var handClick = Controller.findAction(handClickString); @@ -183,7 +174,8 @@ } return; }, - turnLightOff: function () { + + turnLightOff: function() { this.playSoundAtCurrentPosition(false); Entities.editEntity(this.spotlight, { intensity: 0 @@ -193,7 +185,8 @@ }); this.lightOn = false; }, - turnLightOn: function () { + + turnLightOn: function() { this.playSoundAtCurrentPosition(true); Entities.editEntity(this.glowLight, { @@ -204,16 +197,8 @@ }); this.lightOn = true; }, - // preload() will be called when the entity has become visible (or known) to the interface - // it gives us a chance to set our local JavaScript object up. In this case it means: - // * remembering our entityID, so we can access it in cases where we're called without an entityID - preload: function (entityID) { - this.entityID = entityID; - this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); - this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); - }, - playSoundAtCurrentPosition: function (playOnSound) { + playSoundAtCurrentPosition: function(playOnSound) { var position = Entities.getEntityProperties(this.entityID, "position").position; var audioProperties = { @@ -228,10 +213,21 @@ } }, - // unload() will be called when our entity is no longer available. It may be because we were deleted, - // or because we've left the domain or quit the application. - unload: function () { + preload: function(entityID) { + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * preloading sounds + this.entityID = entityID; + this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); + this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); + + }, + + unload: function() { + // unload() will be called when our entity is no longer available. It may be because we were deleted, + // or because we've left the domain or quit the application. if (this.hasSpotlight) { Entities.deleteEntity(this.spotlight); Entities.deleteEntity(this.glowLight); @@ -242,8 +238,8 @@ this.lightOn = false; } - }, + }; // entity scripts always need to return a newly constructed object of our type From 83a8636a3668870ae6aecced4f0d7f6459fd8736 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 14:49:28 -0700 Subject: [PATCH 15/25] Remove whitespace, batch entity edits --- examples/toys/doll/createDoll.js | 19 +++++------- examples/toys/doll/doll.js | 51 ++++++++++++++++---------------- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/examples/toys/doll/createDoll.js b/examples/toys/doll/createDoll.js index 8cb93a15df..ffd840f4ea 100644 --- a/examples/toys/doll/createDoll.js +++ b/examples/toys/doll/createDoll.js @@ -4,7 +4,6 @@ // Created by James B. Pollack @imgntn 9/23/2015 // Copyright 2015 High Fidelity, Inc. // -// ATTENTION: requires that you run handController.js // Creates a doll entity in front of you. // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -13,19 +12,15 @@ function createDoll() { var modelURL = "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx"; - var scriptURL = Script.resolvePath("doll.js"); - var center = Vec3.sum(Vec3.sum(MyAvatar.position, { - x: 0, - y: 0.5, - z: 0 - }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); - var naturalDimensions = { - x: 1.63, - y: 1.67, - z: 0.26 - }; + var scriptURL = Script.resolvePath("doll.js"); + + var center = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); + + var naturalDimensions = { x: 1.63, y: 1.67, z: 0.26}; + var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15); + var doll = Entities.addEntity({ type: "Model", name: "doll", diff --git a/examples/toys/doll/doll.js b/examples/toys/doll/doll.js index 12a41d5e98..d47dd483ec 100644 --- a/examples/toys/doll/doll.js +++ b/examples/toys/doll/doll.js @@ -2,20 +2,22 @@ // // Script Type: Entity // Created by Eric Levin on 9/21/15. +// Additions by James B. Pollack @imgntn on 9/24/15 // Copyright 2015 High Fidelity, Inc. // -// ATTENTION: requires that you run handController.js // This entity script plays an animation and a sound while you hold it. // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// Known issues: If you pass the doll between hands, animation can get into a weird state. We want to prevent the animation from starting again when you switch hands, but when you switch mid-animation your hand at release is still the first hand and not the current hand. /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -(function () { + +(function() { Script.include("../../utilities.js"); Script.include("../../libraries/utils.js"); // this is the "constructor" for the entity as a JS object we don't do much here - var Doll = function () { + var Doll = function() { this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")]; }; @@ -27,21 +29,20 @@ lastFrame: 128, startAutomatically: true }), - stopAnimationSetting: JSON.stringify({ - running: false, - }), + stopAnimationSetting: JSON.stringify({running: false}), audioInjector: null, isGrabbed: false, - setLeftHand: function () { + setLeftHand: function() { this.hand = 'left'; }, - setRightHand: function () { + setRightHand: function() { this.hand = 'right'; }, - startNearGrab: function () { + startNearGrab: function() { if (this.isGrabbed === false) { + Entities.editEntity(this.entityID, { animationURL: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx", animationSettings: this.startAnimationSetting @@ -52,41 +53,41 @@ position: position, volume: 0.1 }); + this.isGrabbed = true; this.initialHand = this.hand; } }, - continueNearGrab: function () { - var position = Entities.getEntityProperties(this.entityID, "position").position; + continueNearGrab: function() { + var props = Entities.getEntityProperties(this.entityID, "position"); var audioOptions = { - position: position + position: props.position }; this.audioInjector.options = audioOptions; }, - releaseGrab: function () { - if (this.isGrabbed === true && this.hand === this.initialHand) { - this.audioInjector.stop(); - Entities.editEntity(this.entityID, { - animationSettings: this.stopAnimationSetting - }); + releaseGrab: function() { + if (this.isGrabbed === true && this.hand === this.initialHand) { + + this.audioInjector.stop(); + Entities.editEntity(this.entityID, { + animationSettings: this.stopAnimationSetting, animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", }); - this.isGrabbed = false; - } + this.isGrabbed = false; + } }, - // preload() will be called when the entity has become visible (or known) to the interface - // it gives us a chance to set our local JavaScript object up. In this case it means: - // * remembering our entityID, so we can access it in cases where we're called without an entityID - preload: function (entityID) { + preload: function(entityID) { + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID this.entityID = entityID; }, }; - // entity scripts always need to return a newly constructed object of our type return new Doll(); }); \ No newline at end of file From 9eb3b56e5da5ee3eb4b04df4bfc3c54287f24b7e Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 15:03:02 -0700 Subject: [PATCH 16/25] Remove space before and after function calls, add spaces btw functions --- examples/controllers/handControllerGrab.js | 165 +++++++------------ examples/entityScripts/changeColorOnTouch.js | 38 ++--- 2 files changed, 82 insertions(+), 121 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index c6c1befda7..df7f67169c 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -2,6 +2,7 @@ // examples // // Created by Eric Levin on 9/2/15 +// Additions by James B. Pollack @imgntn on 9/24/2015 // Copyright 2015 High Fidelity, Inc. // // Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. @@ -28,21 +29,9 @@ var TRIGGER_ON_VALUE = 0.2; var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var NO_INTERSECT_COLOR = { - red: 10, - green: 10, - blue: 255 -}; // line color when pick misses -var INTERSECT_COLOR = { - red: 250, - green: 10, - blue: 10 -}; // line color when pick hits -var LINE_ENTITY_DIMENSIONS = { - x: 1000, - y: 1000, - z: 1000 -}; +var NO_INTERSECT_COLOR = { red: 10, green: 10, blue: 255}; // line color when pick misses +var INTERSECT_COLOR = { red: 250, green: 10, blue: 10}; // line color when pick hits +var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000, z: 1000}; var LINE_LENGTH = 500; @@ -65,11 +54,7 @@ var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things var RIGHT_HAND = 1; var LEFT_HAND = 0; -var ZERO_VEC = { - x: 0, - y: 0, - z: 0 -}; +var ZERO_VEC = { x: 0, y: 0, z: 0}; var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; var MSEC_PER_SEC = 1000.0; @@ -89,8 +74,7 @@ var STATE_RELEASE = 7; var GRAB_USER_DATA_KEY = "grabKey"; - -function controller(hand, triggerAction) { +function MyController(hand, triggerAction) { this.hand = hand; if (this.hand === RIGHT_HAND) { this.getHandPosition = MyAvatar.getRightPalmPosition; @@ -99,6 +83,7 @@ function controller(hand, triggerAction) { this.getHandPosition = MyAvatar.getLeftPalmPosition; this.getHandRotation = MyAvatar.getLeftPalmRotation; } + this.triggerAction = triggerAction; this.palm = 2 * hand; // this.tip = 2 * hand + 1; // unused, but I'm leaving this here for fear it will be needed @@ -110,37 +95,38 @@ function controller(hand, triggerAction) { this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value var _this = this; - this.update = function () { + + this.update = function() { switch (this.state) { - case STATE_SEARCHING: - this.search(); - this.touchTest(); - break; - case STATE_DISTANCE_HOLDING: - this.distanceHolding(); - break; - case STATE_CONTINUE_DISTANCE_HOLDING: - this.continueDistanceHolding(); - break; - case STATE_NEAR_GRABBING: - this.nearGrabbing(); - break; - case STATE_CONTINUE_NEAR_GRABBING: - this.continueNearGrabbing(); - break; - case STATE_NEAR_GRABBING_NON_COLLIDING: - this.nearGrabbingNonColliding(); - break; - case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: - this.continueNearGrabbingNonColliding(); - break; - case STATE_RELEASE: - this.release(); - break; + case STATE_SEARCHING: + this.search(); + this.touchTest(); + break; + case STATE_DISTANCE_HOLDING: + this.distanceHolding(); + break; + case STATE_CONTINUE_DISTANCE_HOLDING: + this.continueDistanceHolding(); + break; + case STATE_NEAR_GRABBING: + this.nearGrabbing(); + break; + case STATE_CONTINUE_NEAR_GRABBING: + this.continueNearGrabbing(); + break; + case STATE_NEAR_GRABBING_NON_COLLIDING: + this.nearGrabbingNonColliding(); + break; + case STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING: + this.continueNearGrabbingNonColliding(); + break; + case STATE_RELEASE: + this.release(); + break; } }; - _this.pointerIDs = []; - this.lineOn = function (closePoint, farPoint, color) { + + this.lineOn = function(closePoint, farPoint, color) { // draw a line if (this.pointer === null) { this.pointer = Entities.addEntity({ @@ -153,7 +139,6 @@ function controller(hand, triggerAction) { color: color, lifetime: LIFETIME }); - _this.pointerIDs.push(this.pointer); } else { Entities.editEntity(this.pointer, { position: closePoint, @@ -165,20 +150,14 @@ function controller(hand, triggerAction) { }; - - this.lineOff = function () { + this.lineOff = function() { if (this.pointer !== null) { Entities.deleteEntity(this.pointer); } - var index = _this.pointerIDs.indexOf(this.pointer); - if (index > -1) { - _this.pointerIDs.splice(index, 1); - } this.pointer = null; }; - - this.triggerSmoothedSqueezed = function () { + this.triggerSmoothedSqueezed = function() { var triggerValue = Controller.getActionValue(this.triggerAction); // smooth out trigger value this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) + @@ -186,16 +165,12 @@ function controller(hand, triggerAction) { return this.triggerValue > TRIGGER_ON_VALUE; }; - - this.triggerSqueezed = function () { + this.triggerSqueezed = function() { var triggerValue = Controller.getActionValue(this.triggerAction); return triggerValue > TRIGGER_ON_VALUE; }; - - this.search = function () { - - + this.search = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -248,8 +223,7 @@ function controller(hand, triggerAction) { }; - - this.distanceHolding = function () { + this.distanceHolding = function() { var handControllerPosition = Controller.getSpatialControlPosition(this.palm); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm)); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation"]); @@ -282,12 +256,9 @@ function controller(hand, triggerAction) { Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); } - - }; - - this.continueDistanceHolding = function () { + this.continueDistanceHolding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -319,9 +290,7 @@ function controller(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); @@ -335,8 +304,7 @@ function controller(hand, triggerAction) { }); }; - - this.nearGrabbing = function () { + this.nearGrabbing = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -381,7 +349,7 @@ function controller(hand, triggerAction) { this.currentObjectTime = Date.now(); }; - this.continueNearGrabbing = function () { + this.continueNearGrabbing = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -400,7 +368,7 @@ function controller(hand, triggerAction) { Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); }; - this.nearGrabbingNonColliding = function () { + this.nearGrabbingNonColliding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -409,7 +377,7 @@ function controller(hand, triggerAction) { this.state = STATE_CONTINUE_NEAR_GRABBING_NON_COLLIDING; }; - this.continueNearGrabbingNonColliding = function () { + this.continueNearGrabbingNonColliding = function() { if (!this.triggerSmoothedSqueezed()) { this.state = STATE_RELEASE; return; @@ -417,28 +385,28 @@ function controller(hand, triggerAction) { Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding"); }; - _this.allTouchedIDs = {}; - this.touchTest = function () { - //print('touch test'); + this.touchTest = function() { var maxDistance = 0.05; var leftHandPosition = MyAvatar.getLeftPalmPosition(); var rightHandPosition = MyAvatar.getRightPalmPosition(); var leftEntities = Entities.findEntities(leftHandPosition, maxDistance); var rightEntities = Entities.findEntities(rightHandPosition, maxDistance); var ids = []; + if (leftEntities.length !== 0) { - leftEntities.forEach(function (entity) { + leftEntities.forEach(function(entity) { ids.push(entity); }); } + if (rightEntities.length !== 0) { - rightEntities.forEach(function (entity) { + rightEntities.forEach(function(entity) { ids.push(entity); }); } - ids.forEach(function (id) { + ids.forEach(function(id) { var props = Entities.getEntityProperties(id, ["boundingBox", "name"]); if (props.name === 'pointer') { @@ -471,23 +439,22 @@ function controller(hand, triggerAction) { }; - this.startTouch = function (entityID) { + this.startTouch = function(entityID) { // print('START TOUCH' + entityID); Entities.callEntityMethod(entityID, "startTouch"); }; - this.continueTouch = function (entityID) { + this.continueTouch = function(entityID) { // print('CONTINUE TOUCH' + entityID); Entities.callEntityMethod(entityID, "continueTouch"); }; - this.stopTouch = function (entityID) { + this.stopTouch = function(entityID) { // print('STOP TOUCH' + entityID); Entities.callEntityMethod(entityID, "stopTouch"); - }; - this.computeReleaseVelocity = function (deltaPosition, deltaTime, useMultiplier) { + this.computeReleaseVelocity = function(deltaPosition, deltaTime, useMultiplier) { if (deltaTime > 0.0 && !vec3equal(deltaPosition, ZERO_VEC)) { var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger @@ -504,8 +471,7 @@ function controller(hand, triggerAction) { } }; - - this.release = function () { + this.release = function() { this.lineOff(); if (this.grabbedEntity !== null && this.actionID !== null) { @@ -526,12 +492,11 @@ function controller(hand, triggerAction) { this.state = STATE_SEARCHING; }; - - this.cleanup = function () { + this.cleanup = function() { this.release(); }; - this.activateEntity = function () { + this.activateEntity = function() { var data = { activated: true, avatarId: MyAvatar.sessionUUID @@ -539,7 +504,7 @@ function controller(hand, triggerAction) { setEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, data); }; - this.deactivateEntity = function () { + this.deactivateEntity = function() { var data = { activated: false, avatarId: null @@ -548,22 +513,18 @@ function controller(hand, triggerAction) { }; } - -var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); -var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); - +var rightController = new MyController(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK")); +var leftController = new MyController(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK")); function update() { rightController.update(); leftController.update(); } - function cleanup() { rightController.cleanup(); leftController.cleanup(); } - Script.scriptEnding.connect(cleanup); Script.update.connect(update); \ No newline at end of file diff --git a/examples/entityScripts/changeColorOnTouch.js b/examples/entityScripts/changeColorOnTouch.js index b3082fa9d5..3a8ebae956 100644 --- a/examples/entityScripts/changeColorOnTouch.js +++ b/examples/entityScripts/changeColorOnTouch.js @@ -13,54 +13,54 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */ -(function () { - ChangeColorOnTouch = function () { + +(function() { + + function ChangeColorOnTouch () { this.oldColor = {}; this.oldColorKnown = false; - }; + } ChangeColorOnTouch.prototype = { - storeOldColor: function (entityID) { + storeOldColor: function(entityID) { var oldProperties = Entities.getEntityProperties(entityID); this.oldColor = oldProperties.color; this.oldColorKnown = true; + print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); }, - preload: function (entityID) { + preload: function(entityID) { print("preload"); + this.entityID = entityID; this.storeOldColor(entityID); }, - startTouch: function () { + startTouch: function() { print("startTouch"); + if (!this.oldColorKnown) { this.storeOldColor(this.entityID); } - Entities.editEntity(this.entityID, { - color: { - red: 0, - green: 255, - blue: 255 - } - }); + + Entities.editEntity(this.entityID, {color: { red: 0, green: 255, blue: 255 }}); }, - continueTouch: function () { + continueTouch: function() { //unused here return; }, - stopTouch: function () { + stopTouch: function() { print("stopTouch"); + if (this.oldColorKnown) { print("leave restoring old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); - Entities.editEntity(this.entityID, { - color: this.oldColor - }); + Entities.editEntity(this.entityID, {color: this.oldColor}); } } @@ -68,4 +68,4 @@ }; return new ChangeColorOnTouch(); -}) \ No newline at end of file +}); \ No newline at end of file From 629ee7b0c153faeb3a1f1101e956eeca9b1c3558 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 24 Sep 2015 15:12:10 -0700 Subject: [PATCH 17/25] Completely remove SOXR from cmake --- BUILD.md | 1 - cmake/externals/soxr/CMakeLists.txt | 34 --------------------- cmake/modules/FindSoxr.cmake | 43 --------------------------- libraries/audio-client/CMakeLists.txt | 7 +---- libraries/audio/CMakeLists.txt | 6 ---- 5 files changed, 1 insertion(+), 90 deletions(-) delete mode 100644 cmake/externals/soxr/CMakeLists.txt delete mode 100644 cmake/modules/FindSoxr.cmake diff --git a/BUILD.md b/BUILD.md index ae4a67c2ee..e2f310bb1f 100644 --- a/BUILD.md +++ b/BUILD.md @@ -13,7 +13,6 @@ * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 * [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4 * [gverb](https://github.com/highfidelity/gverb) -* [Soxr](http://sourceforge.net/projects/soxr/) ~> 0.1.1 The following external projects are optional dependencies. You can indicate to CMake that you would like to include them by passing -DGET_$NAME=1 when running a clean CMake build. For example, to get CMake to download and compile SDL2 you would pass -DGET_SDL2=1. diff --git a/cmake/externals/soxr/CMakeLists.txt b/cmake/externals/soxr/CMakeLists.txt deleted file mode 100644 index 69d2276ab9..0000000000 --- a/cmake/externals/soxr/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -set(EXTERNAL_NAME soxr) - -if (ANDROID) - set(PLATFORM_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19" "-DHAVE_WORDS_BIGENDIAN_EXITCODE=1") -endif () - -include(ExternalProject) -ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/soxr-0.1.1.zip - URL_MD5 349b5b2f323a7380bc12186d98c77d1d - CMAKE_ARGS ${PLATFORM_CMAKE_ARGS} -DBUILD_SHARED_LIBS=1 -DBUILD_TESTS=0 -DCMAKE_INSTALL_PREFIX:PATH= - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 - BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build -) - -# Hide this external target (for ide users) -set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - -ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE PATH "List of soxr include directories") - -if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/soxr.lib CACHE FILEPATH "List of soxr libraries") - set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${INSTALL_DIR}/bin CACHE PATH "Path to soxr dll") -elseif (APPLE) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libsoxr.dylib CACHE FILEPATH "List of soxr libraries") -else () - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libsoxr.so CACHE FILEPATH "List of soxr libraries") -endif () \ No newline at end of file diff --git a/cmake/modules/FindSoxr.cmake b/cmake/modules/FindSoxr.cmake deleted file mode 100644 index df6ad8050e..0000000000 --- a/cmake/modules/FindSoxr.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# -# FindSoxr.cmake -# -# Try to find the libsoxr resampling library -# -# You can provide a LIBSOXR_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# SOXR_FOUND - system found libsoxr -# SOXR_INCLUDE_DIRS - the libsoxr include directory -# SOXR_LIBRARIES - link to this to use libsoxr -# -# Created on 1/22/2015 by Stephen Birarda -# Copyright 2015 High Fidelity, Inc. -# -# Distributed under the Apache License, Version 2.0. -# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -# - -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("soxr") - -find_path(SOXR_INCLUDE_DIRS soxr.h PATH_SUFFIXES include HINTS ${SOXR_SEARCH_DIRS}) -find_library(SOXR_LIBRARIES NAMES soxr PATH_SUFFIXES lib HINTS ${SOXR_SEARCH_DIRS}) - -if (WIN32) - find_path(SOXR_DLL_PATH soxr.dll PATH_SUFFIXES bin HINTS ${SOXR_SEARCH_DIRS}) -endif() - -set(SOXR_REQUIREMENTS SOXR_INCLUDE_DIRS SOXR_LIBRARIES) -if (WIN32) - list(APPEND SOXR_REQUIREMENTS SOXR_DLL_PATH) -endif () - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Soxr DEFAULT_MSG ${SOXR_REQUIREMENTS}) - -if (WIN32) - add_paths_to_fixup_libs(${SOXR_DLL_PATH}) -endif () - -mark_as_advanced(SOXR_INCLUDE_DIRS SOXR_LIBRARIES SOXR_SEARCH_DIRS) \ No newline at end of file diff --git a/libraries/audio-client/CMakeLists.txt b/libraries/audio-client/CMakeLists.txt index 76f4cb4a0f..f631ec6387 100644 --- a/libraries/audio-client/CMakeLists.txt +++ b/libraries/audio-client/CMakeLists.txt @@ -9,18 +9,13 @@ link_hifi_libraries(audio) target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src") # have CMake grab externals for us -add_dependency_external_projects(gverb soxr) +add_dependency_external_projects(gverb) find_package(Gverb REQUIRED) target_link_libraries(${TARGET_NAME} ${GVERB_LIBRARIES}) target_include_directories(${TARGET_NAME} PRIVATE ${GVERB_INCLUDE_DIRS}) -# we use libsoxr for resampling -find_package(Soxr REQUIRED) -target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES}) -target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS}) - if (APPLE) find_library(CoreAudio CoreAudio) find_library(CoreFoundation CoreFoundation) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt index c03f588d94..5134ccda36 100644 --- a/libraries/audio/CMakeLists.txt +++ b/libraries/audio/CMakeLists.txt @@ -7,10 +7,4 @@ add_dependency_external_projects(glm) find_package(GLM REQUIRED) target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS}) -# we use libsoxr for resampling -add_dependency_external_projects(soxr) -find_package(Soxr REQUIRED) -target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES}) -target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS}) - link_hifi_libraries(networking shared) From 49d3b7e93bdd3dce9682560bb8825ba587ace3aa Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 15:26:19 -0700 Subject: [PATCH 18/25] fix indentation --- examples/toys/doll/doll.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/toys/doll/doll.js b/examples/toys/doll/doll.js index d47dd483ec..f97b6de378 100644 --- a/examples/toys/doll/doll.js +++ b/examples/toys/doll/doll.js @@ -56,7 +56,6 @@ this.isGrabbed = true; this.initialHand = this.hand; - } }, @@ -69,16 +68,16 @@ }, releaseGrab: function() { - if (this.isGrabbed === true && this.hand === this.initialHand) { + if (this.isGrabbed === true && this.hand === this.initialHand) { - this.audioInjector.stop(); + this.audioInjector.stop(); Entities.editEntity(this.entityID, { animationSettings: this.stopAnimationSetting, animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx", }); - this.isGrabbed = false; - } + this.isGrabbed = false; + } }, preload: function(entityID) { From 8dacd736df9793e9352f7008844f4144e520eef6 Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 15:27:26 -0700 Subject: [PATCH 19/25] fix weird multi line thing --- examples/controllers/handControllerGrab.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index df7f67169c..ce2f1b5249 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -272,9 +272,7 @@ 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); var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition); this.handPreviousPosition = handControllerPosition; From 266c69fc70712c304ed712f6eb932959e45940a6 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 24 Sep 2015 15:33:52 -0700 Subject: [PATCH 20/25] Disable the old-school Rig::inverseKinematics during reset. --- interface/src/avatar/MyAvatar.cpp | 2 ++ libraries/animation/src/Rig.cpp | 2 +- libraries/animation/src/Rig.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1c3744c362..c704327d16 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -156,6 +156,7 @@ void MyAvatar::reset() { bool isRig = _rig->getEnableRig(); bool isGraph = _rig->getEnableAnimGraph(); qApp->setRawAvatarUpdateThreading(false); + _rig->disableHands = true; setEnableRigAnimations(true); _skeletonModel.simulate(0.1f); // non-zero setEnableRigAnimations(false); @@ -167,6 +168,7 @@ void MyAvatar::reset() { setEnableAnimGraph(true); Menu::getInstance()->setIsOptionChecked(MenuOption::EnableAnimGraph, true); } + _rig->disableHands = false; qApp->setRawAvatarUpdateThreading(); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 770e857c4a..1874939b3d 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -738,7 +738,7 @@ void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::q return; } - if (_enableAnimGraph && _animSkeleton) { + if (disableHands || (_enableAnimGraph && _animSkeleton)) { // the hand data goes through a different path: Rig::updateFromHandParameters() --> early-exit return; } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 37e1d51a0a..90082ca38b 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -193,6 +193,7 @@ public: AnimNode::ConstPointer getAnimNode() const { return _animNode; } AnimSkeleton::ConstPointer getAnimSkeleton() const { return _animSkeleton; } + bool disableHands {false}; // should go away with rig animation (and Rig::inverseKinematics) protected: From fd4395650226d85b78dac8ada86b4e0c52f37b6b Mon Sep 17 00:00:00 2001 From: James Pollack Date: Thu, 24 Sep 2015 16:35:59 -0700 Subject: [PATCH 21/25] re add allTouchedIDs object --- examples/controllers/handControllerGrab.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ce2f1b5249..a13f1de86d 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -383,6 +383,7 @@ function MyController(hand, triggerAction) { Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding"); }; + _this.allTouchedIDs={}; this.touchTest = function() { var maxDistance = 0.05; var leftHandPosition = MyAvatar.getLeftPalmPosition(); From 85b2322accd73c40c1df7494dbd67b4e60de8f28 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 24 Sep 2015 17:11:14 -0700 Subject: [PATCH 22/25] more work on batch optimzation --- interface/src/Application.cpp | 163 ++++++++++-------- interface/src/ui/ApplicationCompositor.cpp | 4 +- interface/src/ui/ApplicationOverlay.cpp | 37 ++-- libraries/gpu/src/gpu/Context.h | 5 +- .../input-plugins/ViveControllerManager.cpp | 2 +- .../src/AmbientOcclusionEffect.cpp | 2 +- .../render-utils/src/AntialiasingEffect.cpp | 2 +- .../src/DeferredLightingEffect.cpp | 6 +- libraries/render-utils/src/HitEffect.cpp | 2 +- libraries/render-utils/src/Model.cpp | 15 +- .../render-utils/src/RenderDeferredTask.cpp | 8 +- libraries/render/src/render/DrawStatus.cpp | 2 +- libraries/render/src/render/DrawTask.cpp | 2 +- 13 files changed, 138 insertions(+), 112 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c68cf1cd4d..13dcfe332e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1037,6 +1037,8 @@ void Application::initializeUi() { void Application::paintGL() { PROFILE_RANGE(__FUNCTION__); + PerformanceTimer perfTimer("paintGL"); + if (nullptr == _displayPlugin) { return; } @@ -1063,18 +1065,19 @@ void Application::paintGL() { lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); - PerformanceTimer perfTimer("paintGL"); - - PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::paintGL()"); resizeGL(); // Before anything else, let's sync up the gpuContext with the true glcontext used in case anything happened - renderArgs._context->syncCache(); + { + PerformanceTimer perfTimer("syncCache"); + renderArgs._context->syncCache(); + } if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + PerformanceTimer perfTimer("Mirror"); auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; @@ -1088,7 +1091,7 @@ void Application::paintGL() { auto mirrorRectDest = glm::ivec4(mirrorRect.z, mirrorRect.y, mirrorRect.x, mirrorRect.w); auto selfieFbo = DependencyManager::get()->getSelfieFramebuffer(); - doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { batch.setFramebuffer(selfieFbo); batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); batch.blit(primaryFbo, mirrorRect, selfieFbo, mirrorRectDest); @@ -1106,81 +1109,86 @@ void Application::paintGL() { _applicationOverlay.renderOverlay(&renderArgs); } - _myAvatar->startCapture(); - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); - Application::getInstance()->cameraMenuChanged(); - } + { + PerformanceTimer perfTimer("CameraUpdates"); - // The render mode is default or mirror if the camera is in mirror mode, assigned further below - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - - // Always use the default eye position, not the actual head eye position. - // Using the latter will cause the camera to wobble with idle animations, - // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - if (isHMDMode()) { - mat4 camMat = _myAvatar->getSensorToWorldMatrix() * _myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } else { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(_myAvatar->getHead()->getCameraOrientation()); + _myAvatar->startCapture(); + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); + Application::getInstance()->cameraMenuChanged(); } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(_myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * hmdRotation); - // Ignore MenuOption::CenterPlayerInView in HMD view - glm::vec3 hmdOffset = extractTranslation(_myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() - + _myAvatar->getOrientation() - * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f) + hmdOffset)); - } else { - _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() - * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + + // The render mode is default or mirror if the camera is in mirror mode, assigned further below + renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; + + // Always use the default eye position, not the actual head eye position. + // Using the latter will cause the camera to wobble with idle animations, + // or with changes from the face tracker + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + if (isHMDMode()) { + mat4 camMat = _myAvatar->getSensorToWorldMatrix() * _myAvatar->getHMDSensorMatrix(); + _myCamera.setPosition(extractTranslation(camMat)); + _myCamera.setRotation(glm::quat_cast(camMat)); } else { + _myCamera.setPosition(_myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(_myAvatar->getHead()->getCameraOrientation()); + } + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(_myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() * hmdRotation); + // Ignore MenuOption::CenterPlayerInView in HMD view + glm::vec3 hmdOffset = extractTranslation(_myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + _myAvatar->getOrientation() - * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f) + hmdOffset)); + } else { + _myCamera.setRotation(_myAvatar->getHead()->getOrientation()); + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() + * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } else { + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + _myAvatar->getOrientation() + * (_myAvatar->getScale() * _myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } } + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(_myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + glm::vec3 hmdOffset = extractTranslation(_myAvatar->getHMDSensorMatrix()); + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) + + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + } else { + _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setPosition(_myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) + + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + } + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(_myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); - glm::vec3 hmdOffset = extractTranslation(_myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) - + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); - } else { - _myCamera.setRotation(_myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setPosition(_myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0) - + (_myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + // Update camera position + if (!isHMDMode()) { + _myCamera.update(1.0f / _fps); } - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + _myAvatar->endCapture(); } - // Update camera position - if (!isHMDMode()) { - _myCamera.update(1.0f / _fps); - } - _myAvatar->endCapture(); // Primary rendering pass auto framebufferCache = DependencyManager::get(); const QSize size = framebufferCache->getFrameBufferSize(); { PROFILE_RANGE(__FUNCTION__ "/mainRender"); + PerformanceTimer perfTimer("mainRender"); // Viewport is assigned to the size of the framebuffer renderArgs._viewport = ivec4(0, 0, size.width(), size.height()); if (displayPlugin->isStereo()) { @@ -1217,7 +1225,7 @@ void Application::paintGL() { } displaySide(&renderArgs, _myCamera); renderArgs._context->enableStereo(false); - doInBatch(renderArgs._context, [](gpu::Batch& batch) { + gpu::doInBatch(renderArgs._context, [](gpu::Batch& batch) { batch.setFramebuffer(nullptr); }); } @@ -1225,6 +1233,7 @@ void Application::paintGL() { // Overlay Composition, needs to occur after screen space effects have completed { PROFILE_RANGE(__FUNCTION__ "/compositor"); + PerformanceTimer perfTimer("compositor"); auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo)); if (displayPlugin->isStereo()) { @@ -1249,6 +1258,7 @@ void Application::paintGL() { // deliver final composited scene to the display plugin { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); + PerformanceTimer perfTimer("pluginOutput"); auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); // Ensure the rendering context commands are completed when rendering @@ -1266,24 +1276,29 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginDisplay"); + PerformanceTimer perfTimer("pluginDisplay"); displayPlugin->display(finalTexture, toGlm(size)); } { PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); + PerformanceTimer perfTimer("bufferSwap"); displayPlugin->finishFrame(); } } - _offscreenContext->makeCurrent(); - _frameCount++; - Stats::getInstance()->setRenderDetails(renderArgs._details); + { + PerformanceTimer perfTimer("makeCurrent"); + _offscreenContext->makeCurrent(); + _frameCount++; + Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages - // Back to the default framebuffer; - doInBatch(renderArgs._context, [=](gpu::Batch& batch) { - batch.resetStages(); - }); + // Reset the gpu::Context Stages + // Back to the default framebuffer; + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + batch.resetStages(); + }); + } } void Application::runTests() { diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index ec93137d3a..497a94bb86 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -207,7 +207,7 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { updateTooltips(); //Handle fading and deactivation/activation of UI - doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { auto geometryCache = DependencyManager::get(); @@ -278,7 +278,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int auto geometryCache = DependencyManager::get(); - doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { geometryCache->useSimpleDrawPipeline(batch); batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 7254295c2f..03d6432104 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -70,29 +70,28 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { } // Execute the batch into our framebuffer - gpu::Batch batch; - renderArgs->_batch = &batch; + doInBatch(renderArgs->_context, [=](gpu::Batch& batch) { + renderArgs->_batch = &batch; - int width = _overlayFramebuffer->getWidth(); - int height = _overlayFramebuffer->getHeight(); + int width = _overlayFramebuffer->getWidth(); + int height = _overlayFramebuffer->getHeight(); - batch.setViewportTransform(glm::ivec4(0, 0, width, height)); - batch.setFramebuffer(_overlayFramebuffer); + batch.setViewportTransform(glm::ivec4(0, 0, width, height)); + batch.setFramebuffer(_overlayFramebuffer); - glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; - float depth = 1.0f; - int stencil = 0; - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); + glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; + float depth = 1.0f; + int stencil = 0; + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); - // Now render the overlay components together into a single texture - renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line - renderAudioScope(renderArgs); // audio scope in the very back - renderRearView(renderArgs); // renders the mirror view selfie - renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts - renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope - renderStatsAndLogs(renderArgs); // currently renders nothing - - renderArgs->_context->render(batch); + // Now render the overlay components together into a single texture + renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line + renderAudioScope(renderArgs); // audio scope in the very back + renderRearView(renderArgs); // renders the mirror view selfie + renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture, and the text overlays from scripts + renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope + renderStatsAndLogs(renderArgs); // currently renders nothing + }); renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 286decfad4..ad21d71427 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -215,8 +215,6 @@ protected: }; typedef std::shared_ptr ContextPointer; -}; - template void doInBatch(std::shared_ptr context, F f) { static gpu::Batch::CacheState cacheState; @@ -226,4 +224,7 @@ void doInBatch(std::shared_ptr context, F f) { cacheState = batch.getCacheState(); } +}; + + #endif diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 3d6f2e1656..bb8267b616 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -173,7 +173,7 @@ void ViveControllerManager::updateRendering(RenderArgs* args, render::ScenePoint UserInputMapper::PoseValue leftHand = _poseStateMap[makeInput(JointChannel::LEFT_HAND).getChannel()]; UserInputMapper::PoseValue rightHand = _poseStateMap[makeInput(JointChannel::RIGHT_HAND).getChannel()]; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); DependencyManager::get()->bindSimpleProgram(batch, true); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 73c316648b..456a6430a7 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -179,7 +179,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto framebufferCache = DependencyManager::get(); QSize framebufferSize = framebufferCache->getFrameBufferSize(); float fbWidth = framebufferSize.width(); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 9af3f90a4e..aaef67542f 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -101,7 +101,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re } RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); auto framebufferCache = DependencyManager::get(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5ace0d4e13..a9d83aa9d6 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -340,7 +340,7 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu } void DeferredLightingEffect::prepare(RenderArgs* args) { - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); batch.setStateScissorRect(args->_viewport); @@ -357,7 +357,7 @@ void DeferredLightingEffect::prepare(RenderArgs* args) { gpu::FramebufferPointer _copyFBO; void DeferredLightingEffect::render(RenderArgs* args) { - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { // Allocate the parameters buffer used by all the deferred shaders if (!_deferredTransformBuffer[0]._buffer) { @@ -685,7 +685,7 @@ void DeferredLightingEffect::render(RenderArgs* args) { void DeferredLightingEffect::copyBack(RenderArgs* args) { auto framebufferCache = DependencyManager::get(); - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); QSize framebufferSize = framebufferCache->getFrameBufferSize(); diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index b3915aa072..06bd07b456 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -63,7 +63,7 @@ void HitEffect::run(const render::SceneContextPointer& sceneContext, const rende assert(renderContext->args); assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { glm::mat4 projMat; Transform viewMat; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ff27c3ab62..7aee46b108 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1272,6 +1272,8 @@ void Model::simulateInternal(float deltaTime) { updateRig(deltaTime, parentTransform); } void Model::updateClusterMatrices() { + PerformanceTimer perfTimer("Model::updateClusterMatrices"); + if (!_needsUpdateClusterMatrices) { return; } @@ -1528,6 +1530,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape { if (!_showTrueJointTransforms) { + PerformanceTimer perfTimer("_rig->updateVisibleJointStates()"); _rig->updateVisibleJointStates(); } // else no need to update visible transforms } @@ -1692,6 +1695,8 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape // TODO: We should be able to do that just in the renderTransparentJob if (translucentMesh && locations->lightBufferUnit >= 0) { + PerformanceTimer perfTimer("DLE->setupTransparent()"); + DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); } @@ -1702,8 +1707,11 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape } } - batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); - batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); + { + PerformanceTimer perfTimer("batch.drawIndexed()"); + batch.setIndexBuffer(gpu::UINT32, part.getMergedTriangles(), 0); + batch.drawIndexed(gpu::TRIANGLES, part.mergedTrianglesIndicesCount, 0); + } if (args) { const int INDICES_PER_TRIANGLE = 3; @@ -1743,6 +1751,9 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { + PerformanceTimer perfTimer("Model::pickPrograms"); + + RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); if (mode == RenderArgs::MIRROR_RENDER_MODE) { key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 35ac2e4af2..65f77689c3 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -32,7 +32,7 @@ using namespace render; void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { auto primaryFbo = DependencyManager::get()->getPrimaryFramebufferDepthColor(); @@ -166,7 +166,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -195,7 +195,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const assert(renderContext->args->_viewFrustum); RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); batch.setStateScissorRect(args->_viewport); args->_batch = &batch; @@ -267,7 +267,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon } // Render the items - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; args->_whiteTexture = DependencyManager::get()->getWhiteTexture(); diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 66067f3ff2..32cd21d0bc 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -126,7 +126,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex } // Allright, something to render let's do it - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { glm::mat4 projMat; Transform viewMat; args->_viewFrustum->evalProjectionMatrix(projMat); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 644b9b0adf..e2c4c5f747 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -236,7 +236,7 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext cullItems(sceneContext, renderContext, inItems, culledItems); RenderArgs* args = renderContext->args; - doInBatch(args->_context, [=](gpu::Batch& batch) { + gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { args->_batch = &batch; renderItems(sceneContext, renderContext, culledItems); }); From d063f3488d6aacc84e21edfc0668df0c0146edf6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Sep 2015 19:14:26 -0700 Subject: [PATCH 23/25] Back out fromSpherical code addition --- libraries/script-engine/src/Vec3.cpp | 24 ++++++++++++++++++++++++ libraries/script-engine/src/Vec3.h | 4 ++-- libraries/shared/src/GLMHelpers.cpp | 24 ------------------------ libraries/shared/src/GLMHelpers.h | 4 ---- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 04e3a4fe05..88d6373b6d 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -58,3 +58,27 @@ glm::vec3 Vec3::toPolar(const glm::vec3& v) { return glm::vec3(elevation, azimuth, radius); } + +glm::vec3 Vec3::fromPolar(const glm::vec3& polar) { + float x = glm::cos(polar.x) * glm::sin(polar.y); + float y = glm::sin(-polar.x); + float z = glm::cos(polar.x) * glm::cos(polar.y); + + // Round small values to 0 + if (glm::abs(x) < EPSILON) { + x = 0.0f; + } + if (glm::abs(y) < EPSILON) { + y = 0.0f; + } + if (glm::abs(z) < EPSILON) { + z = 0.0f; + } + + return polar.z * glm::vec3(x, y, z); +} + +glm::vec3 Vec3::fromPolar(float elevation, float azimuth) { + glm::vec3 v = glm::vec3(elevation, azimuth, 1.0f); + return fromPolar(v); +} diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 2d703ac87e..b05e729a49 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -43,8 +43,8 @@ public slots: bool withinEpsilon(const glm::vec3& v1, const glm::vec3& v2, float epsilon); // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation glm::vec3 toPolar(const glm::vec3& v); - glm::vec3 fromPolar(const glm::vec3& polar) { return fromSpherical(polar); } - glm::vec3 fromPolar(float elevation, float azimuth) { return fromSpherical(elevation, azimuth); } + glm::vec3 fromPolar(const glm::vec3& polar); + glm::vec3 fromPolar(float elevation, float azimuth); const glm::vec3& UNIT_X() { return Vectors::UNIT_X; } const glm::vec3& UNIT_Y() { return Vectors::UNIT_Y; } const glm::vec3& UNIT_Z() { return Vectors::UNIT_Z; } diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 3d705cf99e..7d56157e53 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -225,30 +225,6 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { return glm::angleAxis(angle, axis); } -glm::vec3 fromSpherical(const glm::vec3& spherical) { - float x = glm::cos(spherical.x) * glm::sin(spherical.y); - float y = glm::sin(-spherical.x); - float z = glm::cos(spherical.x) * glm::cos(spherical.y); - - // Round small values to 0 - if (glm::abs(x) < EPSILON) { - x = 0.0f; - } - if (glm::abs(y) < EPSILON) { - y = 0.0f; - } - if (glm::abs(z) < EPSILON) { - z = 0.0f; - } - - return spherical.z * glm::vec3(x, y, z); -} - -glm::vec3 fromSpherical(float elevation, float azimuth) { - glm::vec3 v = glm::vec3(elevation, azimuth, 1.0f); - return fromSpherical(v); -} - bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) { glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 0245ca926f..6683088306 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -117,10 +117,6 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2); glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); -glm::vec3 fromSpherical(const glm::vec3& spherical); - -glm::vec3 fromSpherical(float elevation, float azimuth); - bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2); glm::vec3 extractTranslation(const glm::mat4& matrix); From 629128c17f3d191c1e98352a49b7eb85fb27eb97 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Sep 2015 19:16:28 -0700 Subject: [PATCH 24/25] Fix particle emit directions for point emitter --- libraries/entities/src/ParticleEffectEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 8c45c860fa..3f3bde7077 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -711,10 +711,10 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { if (_emitDimensions == glm::vec3()) { // Point - emitDirection = _emitOrientation * fromSpherical(elevation, azimuth); + emitDirection = glm::angleAxis(PI_OVER_TWO - elevation, X_AXIS) * Z_AXIS; + emitDirection = glm::angleAxis(azimuth, Z_AXIS) * emitDirection; _particlePositions[i] = getPosition(); - } else { // Ellipsoid float radiusScale = 1.0f; From d233d3f81bdae9873cc93be0c5024398eb76e094 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Sep 2015 19:17:02 -0700 Subject: [PATCH 25/25] Fix particle emitter corner cases --- libraries/entities/src/ParticleEffectEntityItem.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 3f3bde7077..9d11dff55a 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -682,9 +682,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } updateRadius(i, 0.0f); - // Velocity and acceleration - if (_polarStart == 0.0f && _polarFinish == 0.0f) { - // Emit along z-axis + // Position, velocity, and acceleration + if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { + // Emit along z-axis from position _particlePositions[i] = getPosition(); _particleVelocities[i] = (_emitSpeed + (2.0f * randFloat() - 1.0f) * _speedSpread) * (_emitOrientation * Z_AXIS); @@ -730,9 +730,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { float z = radiuses.z * glm::sin(elevation); glm::vec3 emitPosition = glm::vec3(x, y, z); emitDirection = glm::normalize(glm::vec3( - x / (radiuses.x * radiuses.x), - y / (radiuses.y * radiuses.y), - z / (radiuses.z * radiuses.z) + radiuses.x > 0.0f ? x / (radiuses.x * radiuses.x) : 0.0f, + radiuses.y > 0.0f ? y / (radiuses.y * radiuses.y) : 0.0f, + radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f )); _particlePositions[i] = getPosition() + _emitOrientation * emitPosition;