From e5959a555faa2ab053df140af0160bc67af4c7a0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 14 Sep 2015 15:44:43 -0700 Subject: [PATCH 001/171] Move assertion in AssetRequest below error checking If the request had an error then there is no reason the assertion should be true. --- libraries/networking/src/AssetRequest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index c0e5f0b6f2..45e925389d 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -76,8 +76,6 @@ void AssetRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) { - Q_ASSERT(data.size() == (end - start)); - if (!responseReceived) { _error = NetworkError; } else if (serverError != AssetServerError::NoError) { @@ -93,6 +91,7 @@ void AssetRequest::start() { break; } } else { + Q_ASSERT(data.size() == (end - start)); // we need to check the hash of the received data to make sure it matches what we expect if (hashData(data).toHex() == _hash) { From 8d4d4a555c15f130b43c693dc0af451c36fce72d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 20 Oct 2015 15:56:24 -0700 Subject: [PATCH 002/171] Add kinematicGrab option in handControllerGrab.js --- 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 d2ad2aa4be..a586188f8b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -497,7 +497,8 @@ function MyController(hand, triggerAction) { timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: this.offsetPosition, relativeRotation: this.offsetRotation, - lifetime: ACTION_LIFETIME + lifetime: ACTION_LIFETIME, + kinematic: (grabbableData.kinematicGrab && (grabbableData.kinematicGrab === true)) }); if (this.actionID === NULL_ACTION_ID) { this.actionID = null; From c67eafffba8c0398dc3098a1e75cce8907d64a04 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Oct 2015 16:59:03 -0700 Subject: [PATCH 003/171] Add pitching.js --- examples/pitching.js | 365 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 examples/pitching.js diff --git a/examples/pitching.js b/examples/pitching.js new file mode 100644 index 0000000000..046113cbc3 --- /dev/null +++ b/examples/pitching.js @@ -0,0 +1,365 @@ +//var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/323725__reitanna__thunk.wav"; +var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/thunk.wav"; +var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; +var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); + +function info(message) { + print("[INFO] " + message); +} + +function error(message) { + print("[ERROR] " + message); +} + +var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; +var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { + x: 0.0, + y: 0.25, + z: -1.05, +}; +var PITCHING_MACHINE_PROPERTIES = { + name: "Pitching Machine", + type: "Model", + position: { + x: 0, + y: 0.8, + z: -22.3, + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + gravity: { + x: 0.0, + y: -9.8, + z: 0.0 + }, + registrationPoint: { + x: 0.5, + y: 0.5, + z: 0.5, + }, + rotation: Quat.fromPitchYawRollDegrees(0, 180, 0), + modelURL: PITCHING_MACHINE_URL, + dimensions: { + x: 0.4, + y: 0.61, + z: 0.39 + }, + collisionsWillMove: false, + shapeType: "Box", +}; +PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); + + +var PITCH_RATE = 5000; + +var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; +var BASEBALL_SPEED = 2.7; +var BASEBALL_RADIUS = 0.07468; +var BASEBALL_PROPERTIES = { + name: "Baseball", + type: "Model", + modelURL: BASEBALL_MODEL_URL, + shapeType: "Sphere", + position: { + x: 0, + y: 0, + z: 0 + }, + dimensions: { + x: BASEBALL_RADIUS, + y: BASEBALL_RADIUS, + z: BASEBALL_RADIUS + }, + collisionsWillMove: true, + angularVelocity: { + x: 17.0, + y: 0, + z: -8.0, + }, + angularDamping: 0.0, + damping: 0.0, + restitution: 0.5, + friction: 0.0, + lifetime: 20, + collisionSoundURL: PITCH_THUNK_SOUND_URL, + gravity: { + x: 0, + y: 0,//-9.8, + z: 0 + } +}; + + +var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); + +var pitchFromPosition = { x: 0, y: 1.0, z: 0 }; +var pitchDirection = { x: 0, y: 0, z: 1 }; + +function shallowCopy(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +function randomInt(low, high) { + return low + (Math.random() * (high - low)); +} + +var ACCELERATION_SPREAD = 10.15; + +function createBaseball(position, velocity, ballScale) { + var properties = shallowCopy(BASEBALL_PROPERTIES); + properties.position = position; + properties.velocity = velocity; + properties.acceleration = { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + }; + properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); + var entityID = Entities.addEntity(properties); + Script.addEventHandler(entityID, "collisionWithEntity", buildBaseballHitCallback(entityID)); + if (false && Math.random() < 0.5) { + for (var i = 0; i < 50; i++) { + Script.setTimeout(function() { + Entities.editEntity(entityID, { + gravity: { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + } + }) + }, i * 100); + } + } + return entityID; +} + +var buildBaseballHitCallback = function(entityID) { + var f = function(entityA, entityB, collision) { + var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); + var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); + var lastPosition = properties.position; + Vec3.print("Velocity", properties.velocity); + Vec3.print("VelocityChange", collision.velocityChange); + Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + line.enqueuePoint(properties.position); + lastPosition = properties.position; + } + }, 50); + Entities.editEntity(entityID, { + velocity: Vec3.multiply(3, properties.velocity), + gravity: { + x: 0, + y: -2.8, + z: 0 + } + }); + print("Baseball hit!"); + Script.removeEventHandler(entityID, "collisionWithEntity", f); + }; + return f; +} + + +function vec3Mult(a, b) { + return { + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, + }; +} + +var injector = null; +function pitchBall() { + var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); + var pitchFromPositionBase = machineProperties.position; + var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); + pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); + var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); + var pitchDirection = Quat.getFront(machineProperties.rotation); + var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; + print("Creating baseball"); + var ballEntityID = createBaseball(pitchFromPosition, Vec3.multiply(BASEBALL_SPEED, pitchDirection), ballScale); + if (!injector) { + injector = Audio.playSound(pitchSound, { + position: pitchFromPosition, + volume: 1.0 + }); + } else { + injector.restart(); + } +} + +Script.scriptEnding.connect(function() { + Entities.deleteEntity(pitchingMachineID); +}) + +Script.setInterval(pitchBall, PITCH_RATE); + + + + +/****************************************************************************** + * PolyLine + *****************************************************************************/ +var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; +var MAX_LINE_LENGTH = 40; // This must be 2 or greater; +var PolyLine = function(position, color, defaultStrokeWidth) { + //info("Creating polyline"); + //Vec3.print("New line at", position); + this.position = position; + this.color = color; + this.defaultStrokeWidth = 0.10; + this.points = [ + { x: 0, y: 0, z: 0 }, + ]; + this.strokeWidths = [ + this.defaultStrokeWidth, + ] + this.normals = [ + { x: 1, y: 0, z: 0 }, + ] + this.entityID = Entities.addEntity({ + type: "PolyLine", + position: position, + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + dimensions: LINE_DIMENSIONS, + color: color, + lifetime: 20, + }); +}; + +PolyLine.prototype.enqueuePoint = function(position) { + if (this.isFull()) { + error("Hit max PolyLine size"); + return; + } + + //Vec3.print("pos", position); + //info("Number of points: " + this.points.length); + + position = Vec3.subtract(position, this.position); + this.points.push(position); + this.normals.push({ x: 1, y: 0, z: 0 }); + this.strokeWidths.push(this.defaultStrokeWidth); + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.dequeuePoint = function() { + if (this.points.length == 0) { + error("Hit min PolyLine size"); + return; + } + + this.points = this.points.slice(1); + this.normals = this.normals.slice(1); + this.strokeWidths = this.strokeWidths.slice(1); + + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.getFirstPoint = function() { + return Vec3.sum(this.position, this.points[0]); +}; + +PolyLine.prototype.getLastPoint = function() { + return Vec3.sum(this.position, this.points[this.points.length - 1]); +}; + +PolyLine.prototype.getSize = function() { + return this.points.length; +} + +PolyLine.prototype.isFull = function() { + return this.points.length >= MAX_LINE_LENGTH; +}; + +PolyLine.prototype.destroy = function() { + Entities.deleteEntity(this.entityID); + this.points = []; +}; + + +/****************************************************************************** + * InfiniteLine + *****************************************************************************/ +InfiniteLine = function(position, color) { + this.position = position; + this.color = color; + this.lines = [new PolyLine(position, color)]; + this.size = 0; +}; + +InfiniteLine.prototype.enqueuePoint = function(position) { + var currentLine; + + if (this.lines.length == 0) { + currentLine = new PolyLine(position, this.color); + this.lines.push(currentLine); + } else { + currentLine = this.lines[this.lines.length - 1]; + } + + if (currentLine.isFull()) { + //info("Current line is full, creating new line"); + //Vec3.print("Last line is", currentLine.getLastPoint()); + //Vec3.print("New line is", position); + var newLine = new PolyLine(currentLine.getLastPoint(), this.color); + this.lines.push(newLine); + currentLine = newLine; + } + + currentLine.enqueuePoint(position); + + ++this.size; +}; + +InfiniteLine.prototype.dequeuePoint = function() { + if (this.lines.length == 0) { + error("Trying to dequeue from InfiniteLine when no points are left"); + return; + } + + var lastLine = this.lines[0]; + lastLine.dequeuePoint(); + + if (lastLine.getSize() <= 1) { + this.lines = this.lines.slice(1); + } + + --this.size; +}; + +InfiniteLine.prototype.getFirstPoint = function() { + return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; +}; + +InfiniteLine.prototype.getLastPoint = function() { + return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; +}; + +InfiniteLine.prototype.destroy = function() { + for (var i = 0; i < this.lines.length; ++i) { + this.lines[i].destroy(); + } + + this.size = 0; +}; From 014e62e25a2766cdc8261a9ba0f778c4f8758f51 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Oct 2015 17:11:37 -0700 Subject: [PATCH 004/171] allow assignment client to use AssetClient for ATP downloads --- assignment-client/src/Agent.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9109703cb..fb9b2a94a0 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,8 @@ Agent::Agent(NLPacket& packet) : DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)) { DependencyManager::get()->setPacketSender(&_entityEditSender); - + + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -110,11 +112,12 @@ void Agent::run() { ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent); auto nodeList = DependencyManager::get(); - nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() - << NodeType::AudioMixer - << NodeType::AvatarMixer - << NodeType::EntityServer - ); + nodeList->addSetOfNodeTypesToNodeInterestSet({ + NodeType::AudioMixer, + NodeType::AvatarMixer, + NodeType::EntityServer, + NodeType::AssetServer + }); _pingTimer = new QTimer(this); connect(_pingTimer, SIGNAL(timeout()), SLOT(sendPingRequests())); From 21903b746cb3e9f02214bbc9028b341cd8063884 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 10:06:51 -0700 Subject: [PATCH 005/171] CP --- examples/baseballEntityScript.js | 0 examples/libraries/walkApi.js | 1884 ++++++++++++------------ examples/map.js~ | 323 ++++ examples/pitching.js | 6 +- examples/toys/flashlight/flashlight.js | 536 +++---- examples/walk.js | 906 ++++++------ 6 files changed, 1990 insertions(+), 1665 deletions(-) create mode 100644 examples/baseballEntityScript.js create mode 100644 examples/map.js~ diff --git a/examples/baseballEntityScript.js b/examples/baseballEntityScript.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js index d1192deee7..7f5070f5d0 100644 --- a/examples/libraries/walkApi.js +++ b/examples/libraries/walkApi.js @@ -1,943 +1,943 @@ -// -// walkApi.js -// version 1.3 -// -// Created by David Wooldridge, June 2015 -// Copyright © 2014 - 2015 High Fidelity, Inc. -// -// Exposes API for use by walk.js version 1.2+. -// -// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// included here to ensure walkApi.js can be used as an API, separate from walk.js -Script.include("./libraries/walkConstants.js"); - -Avatar = function() { - // if Hydras are connected, the only way to enable use is to never set any arm joint rotation - this.hydraCheck = function() { - // function courtesy of Thijs Wenker (frisbee.js) - var numberOfButtons = Controller.getNumberOfButtons(); - var numberOfTriggers = Controller.getNumberOfTriggers(); - var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); - const HYDRA_BUTTONS = 12; - const HYDRA_TRIGGERS = 2; - const HYDRA_CONTROLLERS_PER_TRIGGER = 2; - var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; - if (numberOfButtons == HYDRA_BUTTONS && - numberOfTriggers == HYDRA_TRIGGERS && - controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) { - print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)'); - return true; - } else { - print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.'); - return false; - } - } - // settings - this.headFree = true; - this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix - this.makesFootStepSounds = false; - this.blenderPreRotations = false; // temporary fix - this.animationSet = undefined; // currently just one animation set - this.setAnimationSet = function(animationSet) { - this.animationSet = animationSet; - switch (animationSet) { - case 'standardMale': - this.selectedIdle = walkAssets.getAnimationDataFile("MaleIdle"); - this.selectedWalk = walkAssets.getAnimationDataFile("MaleWalk"); - this.selectedWalkBackwards = walkAssets.getAnimationDataFile("MaleWalkBackwards"); - this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft"); - this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight"); - this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend"); - this.selectedHover = walkAssets.getAnimationDataFile("MaleHover"); - this.selectedFly = walkAssets.getAnimationDataFile("MaleFly"); - this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards"); - this.selectedFlyDown = walkAssets.getAnimationDataFile("MaleFlyDown"); - this.selectedFlyUp = walkAssets.getAnimationDataFile("MaleFlyUp"); - this.selectedFlyBlend = walkAssets.getAnimationDataFile("FlyBlend"); - this.currentAnimation = this.selectedIdle; - return; - } - } - this.setAnimationSet('standardMale'); - - // calibration - this.calibration = { - hipsToFeet: 1, - strideLength: this.selectedWalk.calibration.strideLength - } - this.distanceFromSurface = 0; - this.calibrate = function() { - // Triple check: measurements are taken three times to ensure accuracy - the first result is often too large - const MAX_ATTEMPTS = 3; - var attempts = MAX_ATTEMPTS; - var extraAttempts = 0; - do { - for (joint in walkAssets.animationReference.joints) { - var IKChain = walkAssets.animationReference.joints[joint].IKChain; - - // only need to zero right leg IK chain and hips - if (IKChain === "RightLeg" || joint === "Hips" ) { - MyAvatar.setJointRotation(joint, Quat.fromPitchYawRollDegrees(0, 0, 0)); - } - } - this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y; - - // maybe measuring before Blender pre-rotations have been applied? - if (this.calibration.hipsToFeet < 0 && this.blenderPreRotations) { - this.calibration.hipsToFeet *= -1; - } - - if (this.calibration.hipsToFeet === 0 && extraAttempts < 100) { - attempts++; - extraAttempts++;// Interface can sometimes report zero for hips to feet. if so, we try again. - } - } while (attempts-- > 1) - - // just in case - if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) { - this.calibration.hipsToFeet = 1; - print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+ - this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.'); - } else { - print('walk.js info: Hips to feet calibrated to '+this.calibration.hipsToFeet.toFixed(3)+'m'); - } - } - - // pose the fingers - this.poseFingers = function() { - for (knuckle in walkAssets.animationReference.leftHand) { - if (walkAssets.animationReference.leftHand[knuckle].IKChain === "LeftHandThumb") { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, -4)); - } else { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, 5)); - } - } - for (knuckle in walkAssets.animationReference.rightHand) { - if (walkAssets.animationReference.rightHand[knuckle].IKChain === "RightHandThumb") { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, 4)); - } else { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, -5)); - } - } - }; - this.calibrate(); - this.poseFingers(); - - // footsteps - this.nextStep = RIGHT; // the first step is right, because the waveforms say so - this.leftAudioInjector = null; - this.rightAudioInjector = null; - this.makeFootStepSound = function() { - // correlate footstep volume with avatar speed. place the audio source at the feet, not the hips - const SPEED_THRESHOLD = 0.4; - const VOLUME_ATTENUATION = 0.8; - const MIN_VOLUME = 0.5; - var volume = Vec3.length(motion.velocity) > SPEED_THRESHOLD ? - VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME; - volume = volume > 1 ? 1 : volume; // occurs when landing at speed - can walk faster than max walking speed - var options = { - position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}), - volume: volume - }; - if (this.nextStep === RIGHT) { - if (this.rightAudioInjector === null) { - this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options); - } else { - this.rightAudioInjector.setOptions(options); - this.rightAudioInjector.restart(); - } - this.nextStep = LEFT; - } else if (this.nextStep === LEFT) { - if (this.leftAudioInjector === null) { - this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options); - } else { - this.leftAudioInjector.setOptions(options); - this.leftAudioInjector.restart(); - } - this.nextStep = RIGHT; - } - } -}; - -// constructor for the Motion object -Motion = function() { - this.isLive = true; - // locomotion status - this.state = STATIC; - this.nextState = STATIC; - this.isMoving = false; - this.isWalkingSpeed = false; - this.isFlyingSpeed = false; - this.isAccelerating = false; - this.isDecelerating = false; - this.isDeceleratingFast = false; - this.isComingToHalt = false; - this.directedAcceleration = 0; - - // used to make sure at least one step has been taken when transitioning from a walk cycle - this.elapsedFTDegrees = 0; - - // the current transition (any layered transitions are nested within this transition) - this.currentTransition = null; - - // orientation, locomotion and timing - this.velocity = {x:0, y:0, z:0}; - this.acceleration = {x:0, y:0, z:0}; - this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - this.yawDelta = 0; - this.yawDeltaAcceleration = 0; - this.direction = FORWARDS; - this.deltaTime = 0; - - // historical orientation, locomotion and timing - this.lastDirection = FORWARDS; - this.lastVelocity = {x:0, y:0, z:0}; - this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - this.lastYawDelta = 0; - this.lastYawDeltaAcceleration = 0; - - // Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered - var YAW_SMOOTHING = 22; - this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); - this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); - this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); - - // assess locomotion state - this.assess = function(deltaTime) { - // calculate avatar frame speed, velocity and acceleration - this.deltaTime = deltaTime; - this.velocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), MyAvatar.getVelocity()); - var lateralVelocity = Math.sqrt(Math.pow(this.velocity.x, 2) + Math.pow(this.velocity.z, 2)); - - // MyAvatar.getAcceleration() currently not working. bug report submitted: https://worklist.net/20527 - var acceleration = {x:0, y:0, z:0}; - this.acceleration.x = (this.velocity.x - this.lastVelocity.x) / deltaTime; - this.acceleration.y = (this.velocity.y - this.lastVelocity.y) / deltaTime; - this.acceleration.z = (this.velocity.z - this.lastVelocity.z) / deltaTime; - - // MyAvatar.getAngularVelocity and MyAvatar.getAngularAcceleration currently not working. bug report submitted - this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - if (this.lastYaw < 0 && this.yaw > 0 || this.lastYaw > 0 && this.yaw < 0) { - this.lastYaw *= -1; - } - var timeDelta = this.deltaTimeFilter.process(deltaTime); - this.yawDelta = filter.degToRad(this.yawFilter.process(this.lastYaw - this.yaw)) / timeDelta; - this.yawDeltaAcceleration = this.yawDeltaAccelerationFilter.process(this.lastYawDelta - this.yawDelta) / timeDelta; - - // how far above the surface is the avatar? (for testing / validation purposes) - var pickRay = {origin: MyAvatar.position, direction: {x:0, y:-1, z:0}}; - var distanceFromSurface = Entities.findRayIntersectionBlocking(pickRay).distance; - avatar.distanceFromSurface = distanceFromSurface - avatar.calibration.hipsToFeet; - - // determine principle direction of locomotion - var FWD_BACK_BIAS = 100; // helps prevent false sidestep condition detection when banking hard - if (Math.abs(this.velocity.x) > Math.abs(this.velocity.y) && - Math.abs(this.velocity.x) > FWD_BACK_BIAS * Math.abs(this.velocity.z)) { - if (this.velocity.x < 0) { - this.directedAcceleration = -this.acceleration.x; - this.direction = LEFT; - } else if (this.velocity.x > 0){ - this.directedAcceleration = this.acceleration.x; - this.direction = RIGHT; - } - } else if (Math.abs(this.velocity.y) > Math.abs(this.velocity.x) && - Math.abs(this.velocity.y) > Math.abs(this.velocity.z)) { - if (this.velocity.y > 0) { - this.directedAcceleration = this.acceleration.y; - this.direction = UP; - } else if (this.velocity.y < 0) { - this.directedAcceleration = -this.acceleration.y; - this.direction = DOWN; - } - } else if (FWD_BACK_BIAS * Math.abs(this.velocity.z) > Math.abs(this.velocity.x) && - Math.abs(this.velocity.z) > Math.abs(this.velocity.y)) { - if (this.velocity.z < 0) { - this.direction = FORWARDS; - this.directedAcceleration = -this.acceleration.z; - } else if (this.velocity.z > 0) { - this.directedAcceleration = this.acceleration.z; - this.direction = BACKWARDS; - } - } else { - this.direction = NONE; - this.directedAcceleration = 0; - } - - // set speed flags - if (Vec3.length(this.velocity) < MOVE_THRESHOLD) { - this.isMoving = false; - this.isWalkingSpeed = false; - this.isFlyingSpeed = false; - this.isComingToHalt = false; - } else if (Vec3.length(this.velocity) < MAX_WALK_SPEED) { - this.isMoving = true; - this.isWalkingSpeed = true; - this.isFlyingSpeed = false; - } else { - this.isMoving = true; - this.isWalkingSpeed = false; - this.isFlyingSpeed = true; - } - - // set acceleration flags - if (this.directedAcceleration > ACCELERATION_THRESHOLD) { - this.isAccelerating = true; - this.isDecelerating = false; - this.isDeceleratingFast = false; - this.isComingToHalt = false; - } else if (this.directedAcceleration < DECELERATION_THRESHOLD) { - this.isAccelerating = false; - this.isDecelerating = true; - this.isDeceleratingFast = (this.directedAcceleration < FAST_DECELERATION_THRESHOLD); - } else { - this.isAccelerating = false; - this.isDecelerating = false; - this.isDeceleratingFast = false; - } - - // use the gathered information to build up some spatial awareness - var isOnSurface = (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD); - var isUnderGravity = (avatar.distanceFromSurface < GRAVITY_THRESHOLD); - var isTakingOff = (isUnderGravity && this.velocity.y > OVERCOME_GRAVITY_SPEED); - var isComingInToLand = (isUnderGravity && this.velocity.y < -OVERCOME_GRAVITY_SPEED); - var aboutToLand = isComingInToLand && avatar.distanceFromSurface < LANDING_THRESHOLD; - var surfaceMotion = isOnSurface && this.isMoving; - var acceleratingAndAirborne = this.isAccelerating && !isOnSurface; - var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed; - var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) - var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false; - - // we now have enough information to set the appropriate locomotion mode - switch (this.state) { - case STATIC: - var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk || - (movingDirectlyUpOrDown && !isOnSurface)); - var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown && - !this.isDecelerating && lateralVelocity > MOVE_THRESHOLD; - - if (staticToAirMotion) { - this.nextState = AIR_MOTION; - } else if (staticToSurfaceMotion) { - this.nextState = SURFACE_MOTION; - } else { - this.nextState = STATIC; - } - break; - - case SURFACE_MOTION: - var surfaceMotionToStatic = !this.isMoving || - (this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion && - !maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED); - var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) && - (!surfaceMotion && isTakingOff) || - (!surfaceMotion && this.isMoving && !isComingInToLand); - - if (surfaceMotionToStatic) { - // working on the assumption that stopping is now inevitable - if (!motion.isComingToHalt && isOnSurface) { - motion.isComingToHalt = true; - } - this.nextState = STATIC; - } else if (surfaceMotionToAirMotion) { - this.nextState = AIR_MOTION; - } else { - this.nextState = SURFACE_MOTION; - } - break; - - case AIR_MOTION: - var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown; - var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection; - - if (airMotionToSurfaceMotion){ - this.nextState = SURFACE_MOTION; - } else if (airMotionToStatic) { - this.nextState = STATIC; - } else { - this.nextState = AIR_MOTION; - } - break; - } - } - - // frequency time wheel (foot / ground speed matching) - const DEFAULT_HIPS_TO_FEET = 1; - this.frequencyTimeWheelPos = 0; - this.frequencyTimeWheelRadius = DEFAULT_HIPS_TO_FEET / 2; - this.recentFrequencyTimeIncrements = []; - const FT_WHEEL_HISTORY_LENGTH = 8; - for (var i = 0; i < FT_WHEEL_HISTORY_LENGTH; i++) { - this.recentFrequencyTimeIncrements.push(0); - } - this.averageFrequencyTimeIncrement = 0; - - this.advanceFrequencyTimeWheel = function(angle){ - this.elapsedFTDegrees += angle; - // keep a running average of increments for use in transitions (used during transitioning) - this.recentFrequencyTimeIncrements.push(angle); - this.recentFrequencyTimeIncrements.shift(); - for (increment in this.recentFrequencyTimeIncrements) { - this.averageFrequencyTimeIncrement += this.recentFrequencyTimeIncrements[increment]; - } - this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length; - this.frequencyTimeWheelPos += angle; - const FULL_CIRCLE = 360; - if (this.frequencyTimeWheelPos >= FULL_CIRCLE) { - this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % FULL_CIRCLE; - } - } - - this.saveHistory = function() { - this.lastDirection = this.direction; - this.lastVelocity = this.velocity; - this.lastYaw = this.yaw; - this.lastYawDelta = this.yawDelta; - this.lastYawDeltaAcceleration = this.yawDeltaAcceleration; - } -}; // end Motion constructor - -// animation manipulation object -animationOperations = (function() { - - return { - - // helper function for renderMotion(). calculate joint translations based on animation file settings and frequency * time - calculateTranslations: function(animation, ft, direction) { - var jointName = "Hips"; - var joint = animation.joints[jointName]; - var jointTranslations = {x:0, y:0, z:0}; - - // gather modifiers and multipliers - modifiers = new FrequencyMultipliers(joint, direction); - - // calculate translations. Use synthesis filters where specified by the animation data file. - - // sway (oscillation on the x-axis) - if (animation.filters.hasOwnProperty(jointName) && 'swayFilter' in animation.filters[jointName]) { - jointTranslations.x = joint.sway * animation.filters[jointName].swayFilter.calculate - (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; - } else { - jointTranslations.x = joint.sway * Math.sin - (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; - } - // bob (oscillation on the y-axis) - if (animation.filters.hasOwnProperty(jointName) && 'bobFilter' in animation.filters[jointName]) { - jointTranslations.y = joint.bob * animation.filters[jointName].bobFilter.calculate - (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; - } else { - jointTranslations.y = joint.bob * Math.sin - (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; - - if (animation.filters.hasOwnProperty(jointName) && 'bobLPFilter' in animation.filters[jointName]) { - jointTranslations.y = filter.clipTrough(jointTranslations.y, joint, 2); - jointTranslations.y = animation.filters[jointName].bobLPFilter.process(jointTranslations.y); - } - } - // thrust (oscillation on the z-axis) - if (animation.filters.hasOwnProperty(jointName) && 'thrustFilter' in animation.filters[jointName]) { - jointTranslations.z = joint.thrust * animation.filters[jointName].thrustFilter.calculate - (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; - } else { - jointTranslations.z = joint.thrust * Math.sin - (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; - } - return jointTranslations; - }, - - // helper function for renderMotion(). calculate joint rotations based on animation file settings and frequency * time - calculateRotations: function(jointName, animation, ft, direction) { - var joint = animation.joints[jointName]; - var jointRotations = {x:0, y:0, z:0}; - - if (avatar.blenderPreRotations) { - jointRotations = Vec3.sum(jointRotations, walkAssets.blenderPreRotations.joints[jointName]); - } - - // gather frequency multipliers for this joint - modifiers = new FrequencyMultipliers(joint, direction); - - // calculate rotations. Use synthesis filters where specified by the animation data file. - - // calculate pitch - if (animation.filters.hasOwnProperty(jointName) && - 'pitchFilter' in animation.filters[jointName]) { - jointRotations.x += joint.pitch * animation.filters[jointName].pitchFilter.calculate - (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; - } else { - jointRotations.x += joint.pitch * Math.sin - (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; - } - // calculate yaw - if (animation.filters.hasOwnProperty(jointName) && - 'yawFilter' in animation.filters[jointName]) { - jointRotations.y += joint.yaw * animation.filters[jointName].yawFilter.calculate - (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; - } else { - jointRotations.y += joint.yaw * Math.sin - (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; - } - // calculate roll - if (animation.filters.hasOwnProperty(jointName) && - 'rollFilter' in animation.filters[jointName]) { - jointRotations.z += joint.roll * animation.filters[jointName].rollFilter.calculate - (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; - } else { - jointRotations.z += joint.roll * Math.sin - (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; - } - return jointRotations; - }, - - zeroAnimation: function(animation) { - for (i in animation.joints) { - for (j in animation.joints[i]) { - animation.joints[i][j] = 0; - } - } - }, - - blendAnimation: function(sourceAnimation, targetAnimation, percent) { - for (i in targetAnimation.joints) { - targetAnimation.joints[i].pitch += percent * sourceAnimation.joints[i].pitch; - targetAnimation.joints[i].yaw += percent * sourceAnimation.joints[i].yaw; - targetAnimation.joints[i].roll += percent * sourceAnimation.joints[i].roll; - targetAnimation.joints[i].pitchPhase += percent * sourceAnimation.joints[i].pitchPhase; - targetAnimation.joints[i].yawPhase += percent * sourceAnimation.joints[i].yawPhase; - targetAnimation.joints[i].rollPhase += percent * sourceAnimation.joints[i].rollPhase; - targetAnimation.joints[i].pitchOffset += percent * sourceAnimation.joints[i].pitchOffset; - targetAnimation.joints[i].yawOffset += percent * sourceAnimation.joints[i].yawOffset; - targetAnimation.joints[i].rollOffset += percent * sourceAnimation.joints[i].rollOffset; - if (i === "Hips") { - // Hips only - targetAnimation.joints[i].thrust += percent * sourceAnimation.joints[i].thrust; - targetAnimation.joints[i].sway += percent * sourceAnimation.joints[i].sway; - targetAnimation.joints[i].bob += percent * sourceAnimation.joints[i].bob; - targetAnimation.joints[i].thrustPhase += percent * sourceAnimation.joints[i].thrustPhase; - targetAnimation.joints[i].swayPhase += percent * sourceAnimation.joints[i].swayPhase; - targetAnimation.joints[i].bobPhase += percent * sourceAnimation.joints[i].bobPhase; - targetAnimation.joints[i].thrustOffset += percent * sourceAnimation.joints[i].thrustOffset; - targetAnimation.joints[i].swayOffset += percent * sourceAnimation.joints[i].swayOffset; - targetAnimation.joints[i].bobOffset += percent * sourceAnimation.joints[i].bobOffset; - } - } - }, - - deepCopy: function(sourceAnimation, targetAnimation) { - // calibration - targetAnimation.calibration = JSON.parse(JSON.stringify(sourceAnimation.calibration)); - - // harmonics - targetAnimation.harmonics = {}; - if (sourceAnimation.harmonics) { - targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics)); - } - - // filters - targetAnimation.filters = {}; - for (i in sourceAnimation.filters) { - // are any filters specified for this joint? - if (sourceAnimation.filters[i]) { - targetAnimation.filters[i] = sourceAnimation.filters[i]; - // wave shapers - if (sourceAnimation.filters[i].pitchFilter) { - targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter; - } - if (sourceAnimation.filters[i].yawFilter) { - targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter; - } - if (sourceAnimation.filters[i].rollFilter) { - targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter; - } - // LP filters - if (sourceAnimation.filters[i].swayLPFilter) { - targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter; - } - if (sourceAnimation.filters[i].bobLPFilter) { - targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter; - } - if (sourceAnimation.filters[i].thrustLPFilter) { - targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter; - } - } - } - // joints - targetAnimation.joints = JSON.parse(JSON.stringify(sourceAnimation.joints)); - } - } - -})(); // end animation object literal - -// ReachPose datafile wrapper object -ReachPose = function(reachPoseName) { - this.name = reachPoseName; - this.reachPoseParameters = walkAssets.getReachPoseParameters(reachPoseName); - this.reachPoseDataFile = walkAssets.getReachPoseDataFile(reachPoseName); - this.progress = 0; - this.smoothingFilter = filter.createAveragingFilter(this.reachPoseParameters.smoothing); - this.currentStrength = function() { - // apply optionally smoothed (D)ASDR envelope to reach pose's strength / influence whilst active - var segmentProgress = undefined; // progress through chosen segment - var segmentTimeDelta = undefined; // total change in time over chosen segment - var segmentStrengthDelta = undefined; // total change in strength over chosen segment - var lastStrength = undefined; // the last value the previous segment held - var currentStrength = undefined; // return value - - // select parameters based on segment (a segment being one of (D),A,S,D or R) - if (this.progress >= this.reachPoseParameters.sustain.timing) { - // release segment - segmentProgress = this.progress - this.reachPoseParameters.sustain.timing; - segmentTimeDelta = this.reachPoseParameters.release.timing - this.reachPoseParameters.sustain.timing; - segmentStrengthDelta = this.reachPoseParameters.release.strength - this.reachPoseParameters.sustain.strength; - lastStrength = this.reachPoseParameters.sustain.strength; - } else if (this.progress >= this.reachPoseParameters.decay.timing) { - // sustain phase - segmentProgress = this.progress - this.reachPoseParameters.decay.timing; - segmentTimeDelta = this.reachPoseParameters.sustain.timing - this.reachPoseParameters.decay.timing; - segmentStrengthDelta = this.reachPoseParameters.sustain.strength - this.reachPoseParameters.decay.strength; - lastStrength = this.reachPoseParameters.decay.strength; - } else if (this.progress >= this.reachPoseParameters.attack.timing) { - // decay phase - segmentProgress = this.progress - this.reachPoseParameters.attack.timing; - segmentTimeDelta = this.reachPoseParameters.decay.timing - this.reachPoseParameters.attack.timing; - segmentStrengthDelta = this.reachPoseParameters.decay.strength - this.reachPoseParameters.attack.strength; - lastStrength = this.reachPoseParameters.attack.strength; - } else if (this.progress >= this.reachPoseParameters.delay.timing) { - // attack phase - segmentProgress = this.progress - this.reachPoseParameters.delay.timing; - segmentTimeDelta = this.reachPoseParameters.attack.timing - this.reachPoseParameters.delay.timing; - segmentStrengthDelta = this.reachPoseParameters.attack.strength - this.reachPoseParameters.delay.strength; - lastStrength = 0; //this.delay.strength; - } else { - // delay phase - segmentProgress = this.progress; - segmentTimeDelta = this.reachPoseParameters.delay.timing; - segmentStrengthDelta = this.reachPoseParameters.delay.strength; - lastStrength = 0; - } - currentStrength = segmentTimeDelta > 0 ? lastStrength + segmentStrengthDelta * segmentProgress / segmentTimeDelta - : lastStrength; - // smooth off the response curve - currentStrength = this.smoothingFilter.process(currentStrength); - return currentStrength; - } -}; - -// constructor with default parameters -TransitionParameters = function() { - this.duration = 0.5; - this.easingLower = {x:0.25, y:0.75}; - this.easingUpper = {x:0.75, y:0.25}; - this.reachPoses = []; -} - -const QUARTER_CYCLE = 90; -const HALF_CYCLE = 180; -const THREE_QUARTER_CYCLE = 270; -const FULL_CYCLE = 360; - -// constructor for animation Transition -Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) { - - if (playTransitionReachPoses === undefined) { - playTransitionReachPoses = true; - } - - // record the current state of animation - this.nextAnimation = nextAnimation; - this.lastAnimation = lastAnimation; - this.lastTransition = lastTransition; - - // collect information about the currently playing animation - this.direction = motion.direction; - this.lastDirection = motion.lastDirection; - this.lastFrequencyTimeWheelPos = motion.frequencyTimeWheelPos; - this.lastFrequencyTimeIncrement = motion.averageFrequencyTimeIncrement; - this.lastFrequencyTimeWheelRadius = motion.frequencyTimeWheelRadius; - this.degreesToTurn = 0; // total degrees to turn the ft wheel before the avatar stops (walk only) - this.degreesRemaining = 0; // remaining degrees to turn the ft wheel before the avatar stops (walk only) - this.lastElapsedFTDegrees = motion.elapsedFTDegrees; // degrees elapsed since last transition start - motion.elapsedFTDegrees = 0; // reset ready for the next transition - motion.frequencyTimeWheelPos = 0; // start the next animation's frequency time wheel from zero - - // set parameters for the transition - this.parameters = new TransitionParameters(); - this.liveReachPoses = []; - if (walkAssets && lastAnimation && nextAnimation) { - // overwrite this.parameters with any transition parameters specified for this particular transition - walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters); - // fire up any reach poses for this transition - if (playTransitionReachPoses) { - for (poseName in this.parameters.reachPoses) { - this.liveReachPoses.push(new ReachPose(this.parameters.reachPoses[poseName])); - } - } - } - this.startTime = new Date().getTime(); // Starting timestamp (seconds) - this.progress = 0; // how far are we through the transition? - this.filteredProgress = 0; - - // coming to a halt whilst walking? if so, will need a clean stopping point defined - if (motion.isComingToHalt) { - - const FULL_CYCLE_THRESHOLD = 320; - const HALF_CYCLE_THRESHOLD = 140; - const CYCLE_COMMIT_THRESHOLD = 5; - - // how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground? - if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) { - // just stop the walk cycle right here and blend to idle - this.degreesToTurn = 0; - } else if (this.lastElapsedFTDegrees < HALF_CYCLE) { - // we have not taken a complete step yet, so we advance to the second stop angle - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; - } else if (this.lastFrequencyTimeWheelPos > 0 && this.lastFrequencyTimeWheelPos <= HALF_CYCLE_THRESHOLD) { - // complete the step and stop at 180 - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; - } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE_THRESHOLD && this.lastFrequencyTimeWheelPos <= HALF_CYCLE) { - // complete the step and next then stop at 0 - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; - } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE && this.lastFrequencyTimeWheelPos <= FULL_CYCLE_THRESHOLD) { - // complete the step and stop at 0 - this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos; - } else { - // complete the step and the next then stop at 180 - this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; - } - - // transition length in this case should be directly proportional to the remaining degrees to turn - var MIN_FT_INCREMENT = 5.0; // degrees per frame - var MIN_TRANSITION_DURATION = 0.4; - const TWO_THIRDS = 0.6667; - this.lastFrequencyTimeIncrement *= TWO_THIRDS; // help ease the transition - var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ? - this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT; - var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement, - MIN_TRANSITION_DURATION); - this.parameters.duration = timeToFinish; - this.degreesRemaining = this.degreesToTurn; - } - - // deal with transition recursion (overlapping transitions) - this.recursionDepth = 0; - this.incrementRecursion = function() { - this.recursionDepth += 1; - - // cancel any continued motion - this.degreesToTurn = 0; - - // limit the number of layered / nested transitions - if (this.lastTransition !== nullTransition) { - this.lastTransition.incrementRecursion(); - if (this.lastTransition.recursionDepth > MAX_TRANSITION_RECURSION) { - this.lastTransition = nullTransition; - } - } - }; - if (this.lastTransition !== nullTransition) { - this.lastTransition.incrementRecursion(); - } - - // end of transition initialisation. begin Transition public methods - - // keep up the pace for the frequency time wheel for the last animation - this.advancePreviousFrequencyTimeWheel = function(deltaTime) { - var wheelAdvance = undefined; - - if (this.lastAnimation === avatar.selectedWalkBlend && - this.nextAnimation === avatar.selectedIdle) { - if (this.degreesRemaining <= 0) { - // stop continued motion - wheelAdvance = 0; - if (motion.isComingToHalt) { - if (this.lastFrequencyTimeWheelPos < QUARTER_CYCLE) { - this.lastFrequencyTimeWheelPos = 0; - } else { - this.lastFrequencyTimeWheelPos = HALF_CYCLE; - } - } - } else { - wheelAdvance = this.lastFrequencyTimeIncrement; - var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / HALF_CYCLE; - if (this.degreesRemaining <= 0) { - distanceToTravel = 0; - this.degreesRemaining = 0; - } else { - this.degreesRemaining -= wheelAdvance; - } - } - } else { - wheelAdvance = this.lastFrequencyTimeIncrement; - } - - // advance the ft wheel - this.lastFrequencyTimeWheelPos += wheelAdvance; - if (this.lastFrequencyTimeWheelPos >= FULL_CYCLE) { - this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % FULL_CYCLE; - } - - // advance ft wheel for the nested (previous) Transition - if (this.lastTransition !== nullTransition) { - this.lastTransition.advancePreviousFrequencyTimeWheel(deltaTime); - } - // update the lastElapsedFTDegrees for short stepping - this.lastElapsedFTDegrees += wheelAdvance; - this.degreesTurned += wheelAdvance; - }; - - this.updateProgress = function() { - const MILLISECONDS_CONVERT = 1000; - const ACCURACY_INCREASER = 1000; - var elapasedTime = (new Date().getTime() - this.startTime) / MILLISECONDS_CONVERT; - this.progress = elapasedTime / this.parameters.duration; - this.progress = Math.round(this.progress * ACCURACY_INCREASER) / ACCURACY_INCREASER; - - // updated nested transition/s - if (this.lastTransition !== nullTransition) { - if (this.lastTransition.updateProgress() === TRANSITION_COMPLETE) { - // the previous transition is now complete - this.lastTransition = nullTransition; - } - } - - // update any reachPoses - for (pose in this.liveReachPoses) { - // use independent timing for reachPoses - this.liveReachPoses[pose].progress += (motion.deltaTime / this.liveReachPoses[pose].reachPoseParameters.duration); - if (this.liveReachPoses[pose].progress >= 1) { - // time to kill off this reach pose - this.liveReachPoses.splice(pose, 1); - } - } - - // update transition progress - this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper); - return this.progress >= 1 ? TRANSITION_COMPLETE : false; - }; - - this.blendTranslations = function(frequencyTimeWheelPos, direction) { - var lastTranslations = {x:0, y:0, z:0}; - var nextTranslations = animationOperations.calculateTranslations(this.nextAnimation, - frequencyTimeWheelPos, - direction); - // are we blending with a previous, still live transition? - if (this.lastTransition !== nullTransition) { - lastTranslations = this.lastTransition.blendTranslations(this.lastFrequencyTimeWheelPos, - this.lastDirection); - } else { - lastTranslations = animationOperations.calculateTranslations(this.lastAnimation, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } - - // blend last / next translations - nextTranslations = Vec3.multiply(this.filteredProgress, nextTranslations); - lastTranslations = Vec3.multiply((1 - this.filteredProgress), lastTranslations); - nextTranslations = Vec3.sum(nextTranslations, lastTranslations); - - if (this.liveReachPoses.length > 0) { - for (pose in this.liveReachPoses) { - var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); - var poseTranslations = animationOperations.calculateTranslations( - this.liveReachPoses[pose].reachPoseDataFile, - frequencyTimeWheelPos, - direction); - - // can't use Vec3 operations here, as if x,y or z is zero, the reachPose should have no influence at all - if (Math.abs(poseTranslations.x) > 0) { - nextTranslations.x = reachPoseStrength * poseTranslations.x + (1 - reachPoseStrength) * nextTranslations.x; - } - if (Math.abs(poseTranslations.y) > 0) { - nextTranslations.y = reachPoseStrength * poseTranslations.y + (1 - reachPoseStrength) * nextTranslations.y; - } - if (Math.abs(poseTranslations.z) > 0) { - nextTranslations.z = reachPoseStrength * poseTranslations.z + (1 - reachPoseStrength) * nextTranslations.z; - } - } - } - return nextTranslations; - }; - - this.blendRotations = function(jointName, frequencyTimeWheelPos, direction) { - var lastRotations = {x:0, y:0, z:0}; - var nextRotations = animationOperations.calculateRotations(jointName, - this.nextAnimation, - frequencyTimeWheelPos, - direction); - - // are we blending with a previous, still live transition? - if (this.lastTransition !== nullTransition) { - lastRotations = this.lastTransition.blendRotations(jointName, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } else { - lastRotations = animationOperations.calculateRotations(jointName, - this.lastAnimation, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } - // blend last / next translations - nextRotations = Vec3.multiply(this.filteredProgress, nextRotations); - lastRotations = Vec3.multiply((1 - this.filteredProgress), lastRotations); - nextRotations = Vec3.sum(nextRotations, lastRotations); - - // are there reachPoses defined for this transition? - if (this.liveReachPoses.length > 0) { - for (pose in this.liveReachPoses) { - var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); - var poseRotations = animationOperations.calculateRotations(jointName, - this.liveReachPoses[pose].reachPoseDataFile, - frequencyTimeWheelPos, - direction); - - // don't use Vec3 operations here, as if x,y or z is zero, the reach pose should have no influence at all - if (Math.abs(poseRotations.x) > 0) { - nextRotations.x = reachPoseStrength * poseRotations.x + (1 - reachPoseStrength) * nextRotations.x; - } - if (Math.abs(poseRotations.y) > 0) { - nextRotations.y = reachPoseStrength * poseRotations.y + (1 - reachPoseStrength) * nextRotations.y; - } - if (Math.abs(poseRotations.z) > 0) { - nextRotations.z = reachPoseStrength * poseRotations.z + (1 - reachPoseStrength) * nextRotations.z; - } - } - } - return nextRotations; - }; -}; // end Transition constructor - -// individual joint modifiers -FrequencyMultipliers = function(joint, direction) { - // gather multipliers - this.pitchFrequencyMultiplier = 1; - this.yawFrequencyMultiplier = 1; - this.rollFrequencyMultiplier = 1; - this.swayFrequencyMultiplier = 1; - this.bobFrequencyMultiplier = 1; - this.thrustFrequencyMultiplier = 1; - - if (joint) { - if (joint.pitchFrequencyMultiplier) { - this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier; - } - if (joint.yawFrequencyMultiplier) { - this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier; - } - if (joint.rollFrequencyMultiplier) { - this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier; - } - if (joint.swayFrequencyMultiplier) { - this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier; - } - if (joint.bobFrequencyMultiplier) { - this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier; - } - if (joint.thrustFrequencyMultiplier) { - this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier; - } - } +// +// walkApi.js +// version 1.3 +// +// Created by David Wooldridge, June 2015 +// Copyright © 2014 - 2015 High Fidelity, Inc. +// +// Exposes API for use by walk.js version 1.2+. +// +// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// included here to ensure walkApi.js can be used as an API, separate from walk.js +Script.include("./libraries/walkConstants.js"); + +Avatar = function() { + // if Hydras are connected, the only way to enable use is to never set any arm joint rotation + this.hydraCheck = function() { + // function courtesy of Thijs Wenker (frisbee.js) + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + const HYDRA_BUTTONS = 12; + const HYDRA_TRIGGERS = 2; + const HYDRA_CONTROLLERS_PER_TRIGGER = 2; + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + if (numberOfButtons == HYDRA_BUTTONS && + numberOfTriggers == HYDRA_TRIGGERS && + controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) { + print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)'); + return true; + } else { + print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.'); + return false; + } + } + // settings + this.headFree = true; + this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix + this.makesFootStepSounds = false; + this.blenderPreRotations = false; // temporary fix + this.animationSet = undefined; // currently just one animation set + this.setAnimationSet = function(animationSet) { + this.animationSet = animationSet; + switch (animationSet) { + case 'standardMale': + this.selectedIdle = walkAssets.getAnimationDataFile("MaleIdle"); + this.selectedWalk = walkAssets.getAnimationDataFile("MaleWalk"); + this.selectedWalkBackwards = walkAssets.getAnimationDataFile("MaleWalkBackwards"); + this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft"); + this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight"); + this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend"); + this.selectedHover = walkAssets.getAnimationDataFile("MaleHover"); + this.selectedFly = walkAssets.getAnimationDataFile("MaleFly"); + this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards"); + this.selectedFlyDown = walkAssets.getAnimationDataFile("MaleFlyDown"); + this.selectedFlyUp = walkAssets.getAnimationDataFile("MaleFlyUp"); + this.selectedFlyBlend = walkAssets.getAnimationDataFile("FlyBlend"); + this.currentAnimation = this.selectedIdle; + return; + } + } + this.setAnimationSet('standardMale'); + + // calibration + this.calibration = { + hipsToFeet: 1, + strideLength: this.selectedWalk.calibration.strideLength + } + this.distanceFromSurface = 0; + this.calibrate = function() { + // Triple check: measurements are taken three times to ensure accuracy - the first result is often too large + const MAX_ATTEMPTS = 3; + var attempts = MAX_ATTEMPTS; + var extraAttempts = 0; + do { + for (joint in walkAssets.animationReference.joints) { + var IKChain = walkAssets.animationReference.joints[joint].IKChain; + + // only need to zero right leg IK chain and hips + if (IKChain === "RightLeg" || joint === "Hips" ) { + MyAvatar.setJointRotation(joint, Quat.fromPitchYawRollDegrees(0, 0, 0)); + } + } + this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y; + + // maybe measuring before Blender pre-rotations have been applied? + if (this.calibration.hipsToFeet < 0 && this.blenderPreRotations) { + this.calibration.hipsToFeet *= -1; + } + + if (this.calibration.hipsToFeet === 0 && extraAttempts < 100) { + attempts++; + extraAttempts++;// Interface can sometimes report zero for hips to feet. if so, we try again. + } + } while (attempts-- > 1) + + // just in case + if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) { + this.calibration.hipsToFeet = 1; + print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+ + this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.'); + } else { + print('walk.js info: Hips to feet calibrated to '+this.calibration.hipsToFeet.toFixed(3)+'m'); + } + } + + // pose the fingers + this.poseFingers = function() { + for (knuckle in walkAssets.animationReference.leftHand) { + if (walkAssets.animationReference.leftHand[knuckle].IKChain === "LeftHandThumb") { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, -4)); + } else { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, 5)); + } + } + for (knuckle in walkAssets.animationReference.rightHand) { + if (walkAssets.animationReference.rightHand[knuckle].IKChain === "RightHandThumb") { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, 4)); + } else { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, -5)); + } + } + }; + this.calibrate(); + this.poseFingers(); + + // footsteps + this.nextStep = RIGHT; // the first step is right, because the waveforms say so + this.leftAudioInjector = null; + this.rightAudioInjector = null; + this.makeFootStepSound = function() { + // correlate footstep volume with avatar speed. place the audio source at the feet, not the hips + const SPEED_THRESHOLD = 0.4; + const VOLUME_ATTENUATION = 0.8; + const MIN_VOLUME = 0.5; + var volume = Vec3.length(motion.velocity) > SPEED_THRESHOLD ? + VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME; + volume = volume > 1 ? 1 : volume; // occurs when landing at speed - can walk faster than max walking speed + var options = { + position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}), + volume: volume + }; + if (this.nextStep === RIGHT) { + if (this.rightAudioInjector === null) { + this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options); + } else { + this.rightAudioInjector.setOptions(options); + this.rightAudioInjector.restart(); + } + this.nextStep = LEFT; + } else if (this.nextStep === LEFT) { + if (this.leftAudioInjector === null) { + this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options); + } else { + this.leftAudioInjector.setOptions(options); + this.leftAudioInjector.restart(); + } + this.nextStep = RIGHT; + } + } +}; + +// constructor for the Motion object +Motion = function() { + this.isLive = true; + // locomotion status + this.state = STATIC; + this.nextState = STATIC; + this.isMoving = false; + this.isWalkingSpeed = false; + this.isFlyingSpeed = false; + this.isAccelerating = false; + this.isDecelerating = false; + this.isDeceleratingFast = false; + this.isComingToHalt = false; + this.directedAcceleration = 0; + + // used to make sure at least one step has been taken when transitioning from a walk cycle + this.elapsedFTDegrees = 0; + + // the current transition (any layered transitions are nested within this transition) + this.currentTransition = null; + + // orientation, locomotion and timing + this.velocity = {x:0, y:0, z:0}; + this.acceleration = {x:0, y:0, z:0}; + this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + this.yawDelta = 0; + this.yawDeltaAcceleration = 0; + this.direction = FORWARDS; + this.deltaTime = 0; + + // historical orientation, locomotion and timing + this.lastDirection = FORWARDS; + this.lastVelocity = {x:0, y:0, z:0}; + this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + this.lastYawDelta = 0; + this.lastYawDeltaAcceleration = 0; + + // Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered + var YAW_SMOOTHING = 22; + this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); + this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); + this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); + + // assess locomotion state + this.assess = function(deltaTime) { + // calculate avatar frame speed, velocity and acceleration + this.deltaTime = deltaTime; + this.velocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), MyAvatar.getVelocity()); + var lateralVelocity = Math.sqrt(Math.pow(this.velocity.x, 2) + Math.pow(this.velocity.z, 2)); + + // MyAvatar.getAcceleration() currently not working. bug report submitted: https://worklist.net/20527 + var acceleration = {x:0, y:0, z:0}; + this.acceleration.x = (this.velocity.x - this.lastVelocity.x) / deltaTime; + this.acceleration.y = (this.velocity.y - this.lastVelocity.y) / deltaTime; + this.acceleration.z = (this.velocity.z - this.lastVelocity.z) / deltaTime; + + // MyAvatar.getAngularVelocity and MyAvatar.getAngularAcceleration currently not working. bug report submitted + this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + if (this.lastYaw < 0 && this.yaw > 0 || this.lastYaw > 0 && this.yaw < 0) { + this.lastYaw *= -1; + } + var timeDelta = this.deltaTimeFilter.process(deltaTime); + this.yawDelta = filter.degToRad(this.yawFilter.process(this.lastYaw - this.yaw)) / timeDelta; + this.yawDeltaAcceleration = this.yawDeltaAccelerationFilter.process(this.lastYawDelta - this.yawDelta) / timeDelta; + + // how far above the surface is the avatar? (for testing / validation purposes) + var pickRay = {origin: MyAvatar.position, direction: {x:0, y:-1, z:0}}; + var distanceFromSurface = Entities.findRayIntersectionBlocking(pickRay).distance; + avatar.distanceFromSurface = distanceFromSurface - avatar.calibration.hipsToFeet; + + // determine principle direction of locomotion + var FWD_BACK_BIAS = 100; // helps prevent false sidestep condition detection when banking hard + if (Math.abs(this.velocity.x) > Math.abs(this.velocity.y) && + Math.abs(this.velocity.x) > FWD_BACK_BIAS * Math.abs(this.velocity.z)) { + if (this.velocity.x < 0) { + this.directedAcceleration = -this.acceleration.x; + this.direction = LEFT; + } else if (this.velocity.x > 0){ + this.directedAcceleration = this.acceleration.x; + this.direction = RIGHT; + } + } else if (Math.abs(this.velocity.y) > Math.abs(this.velocity.x) && + Math.abs(this.velocity.y) > Math.abs(this.velocity.z)) { + if (this.velocity.y > 0) { + this.directedAcceleration = this.acceleration.y; + this.direction = UP; + } else if (this.velocity.y < 0) { + this.directedAcceleration = -this.acceleration.y; + this.direction = DOWN; + } + } else if (FWD_BACK_BIAS * Math.abs(this.velocity.z) > Math.abs(this.velocity.x) && + Math.abs(this.velocity.z) > Math.abs(this.velocity.y)) { + if (this.velocity.z < 0) { + this.direction = FORWARDS; + this.directedAcceleration = -this.acceleration.z; + } else if (this.velocity.z > 0) { + this.directedAcceleration = this.acceleration.z; + this.direction = BACKWARDS; + } + } else { + this.direction = NONE; + this.directedAcceleration = 0; + } + + // set speed flags + if (Vec3.length(this.velocity) < MOVE_THRESHOLD) { + this.isMoving = false; + this.isWalkingSpeed = false; + this.isFlyingSpeed = false; + this.isComingToHalt = false; + } else if (Vec3.length(this.velocity) < MAX_WALK_SPEED) { + this.isMoving = true; + this.isWalkingSpeed = true; + this.isFlyingSpeed = false; + } else { + this.isMoving = true; + this.isWalkingSpeed = false; + this.isFlyingSpeed = true; + } + + // set acceleration flags + if (this.directedAcceleration > ACCELERATION_THRESHOLD) { + this.isAccelerating = true; + this.isDecelerating = false; + this.isDeceleratingFast = false; + this.isComingToHalt = false; + } else if (this.directedAcceleration < DECELERATION_THRESHOLD) { + this.isAccelerating = false; + this.isDecelerating = true; + this.isDeceleratingFast = (this.directedAcceleration < FAST_DECELERATION_THRESHOLD); + } else { + this.isAccelerating = false; + this.isDecelerating = false; + this.isDeceleratingFast = false; + } + + // use the gathered information to build up some spatial awareness + var isOnSurface = (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD); + var isUnderGravity = (avatar.distanceFromSurface < GRAVITY_THRESHOLD); + var isTakingOff = (isUnderGravity && this.velocity.y > OVERCOME_GRAVITY_SPEED); + var isComingInToLand = (isUnderGravity && this.velocity.y < -OVERCOME_GRAVITY_SPEED); + var aboutToLand = isComingInToLand && avatar.distanceFromSurface < LANDING_THRESHOLD; + var surfaceMotion = isOnSurface && this.isMoving; + var acceleratingAndAirborne = this.isAccelerating && !isOnSurface; + var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed; + var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) + var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false; + + // we now have enough information to set the appropriate locomotion mode + switch (this.state) { + case STATIC: + var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk || + (movingDirectlyUpOrDown && !isOnSurface)); + var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown && + !this.isDecelerating && lateralVelocity > MOVE_THRESHOLD; + + if (staticToAirMotion) { + this.nextState = AIR_MOTION; + } else if (staticToSurfaceMotion) { + this.nextState = SURFACE_MOTION; + } else { + this.nextState = STATIC; + } + break; + + case SURFACE_MOTION: + var surfaceMotionToStatic = !this.isMoving || + (this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion && + !maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED); + var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) && + (!surfaceMotion && isTakingOff) || + (!surfaceMotion && this.isMoving && !isComingInToLand); + + if (surfaceMotionToStatic) { + // working on the assumption that stopping is now inevitable + if (!motion.isComingToHalt && isOnSurface) { + motion.isComingToHalt = true; + } + this.nextState = STATIC; + } else if (surfaceMotionToAirMotion) { + this.nextState = AIR_MOTION; + } else { + this.nextState = SURFACE_MOTION; + } + break; + + case AIR_MOTION: + var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown; + var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection; + + if (airMotionToSurfaceMotion){ + this.nextState = SURFACE_MOTION; + } else if (airMotionToStatic) { + this.nextState = STATIC; + } else { + this.nextState = AIR_MOTION; + } + break; + } + } + + // frequency time wheel (foot / ground speed matching) + const DEFAULT_HIPS_TO_FEET = 1; + this.frequencyTimeWheelPos = 0; + this.frequencyTimeWheelRadius = DEFAULT_HIPS_TO_FEET / 2; + this.recentFrequencyTimeIncrements = []; + const FT_WHEEL_HISTORY_LENGTH = 8; + for (var i = 0; i < FT_WHEEL_HISTORY_LENGTH; i++) { + this.recentFrequencyTimeIncrements.push(0); + } + this.averageFrequencyTimeIncrement = 0; + + this.advanceFrequencyTimeWheel = function(angle){ + this.elapsedFTDegrees += angle; + // keep a running average of increments for use in transitions (used during transitioning) + this.recentFrequencyTimeIncrements.push(angle); + this.recentFrequencyTimeIncrements.shift(); + for (increment in this.recentFrequencyTimeIncrements) { + this.averageFrequencyTimeIncrement += this.recentFrequencyTimeIncrements[increment]; + } + this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length; + this.frequencyTimeWheelPos += angle; + const FULL_CIRCLE = 360; + if (this.frequencyTimeWheelPos >= FULL_CIRCLE) { + this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % FULL_CIRCLE; + } + } + + this.saveHistory = function() { + this.lastDirection = this.direction; + this.lastVelocity = this.velocity; + this.lastYaw = this.yaw; + this.lastYawDelta = this.yawDelta; + this.lastYawDeltaAcceleration = this.yawDeltaAcceleration; + } +}; // end Motion constructor + +// animation manipulation object +animationOperations = (function() { + + return { + + // helper function for renderMotion(). calculate joint translations based on animation file settings and frequency * time + calculateTranslations: function(animation, ft, direction) { + var jointName = "Hips"; + var joint = animation.joints[jointName]; + var jointTranslations = {x:0, y:0, z:0}; + + // gather modifiers and multipliers + modifiers = new FrequencyMultipliers(joint, direction); + + // calculate translations. Use synthesis filters where specified by the animation data file. + + // sway (oscillation on the x-axis) + if (animation.filters.hasOwnProperty(jointName) && 'swayFilter' in animation.filters[jointName]) { + jointTranslations.x = joint.sway * animation.filters[jointName].swayFilter.calculate + (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; + } else { + jointTranslations.x = joint.sway * Math.sin + (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; + } + // bob (oscillation on the y-axis) + if (animation.filters.hasOwnProperty(jointName) && 'bobFilter' in animation.filters[jointName]) { + jointTranslations.y = joint.bob * animation.filters[jointName].bobFilter.calculate + (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; + } else { + jointTranslations.y = joint.bob * Math.sin + (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; + + if (animation.filters.hasOwnProperty(jointName) && 'bobLPFilter' in animation.filters[jointName]) { + jointTranslations.y = filter.clipTrough(jointTranslations.y, joint, 2); + jointTranslations.y = animation.filters[jointName].bobLPFilter.process(jointTranslations.y); + } + } + // thrust (oscillation on the z-axis) + if (animation.filters.hasOwnProperty(jointName) && 'thrustFilter' in animation.filters[jointName]) { + jointTranslations.z = joint.thrust * animation.filters[jointName].thrustFilter.calculate + (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; + } else { + jointTranslations.z = joint.thrust * Math.sin + (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; + } + return jointTranslations; + }, + + // helper function for renderMotion(). calculate joint rotations based on animation file settings and frequency * time + calculateRotations: function(jointName, animation, ft, direction) { + var joint = animation.joints[jointName]; + var jointRotations = {x:0, y:0, z:0}; + + if (avatar.blenderPreRotations) { + jointRotations = Vec3.sum(jointRotations, walkAssets.blenderPreRotations.joints[jointName]); + } + + // gather frequency multipliers for this joint + modifiers = new FrequencyMultipliers(joint, direction); + + // calculate rotations. Use synthesis filters where specified by the animation data file. + + // calculate pitch + if (animation.filters.hasOwnProperty(jointName) && + 'pitchFilter' in animation.filters[jointName]) { + jointRotations.x += joint.pitch * animation.filters[jointName].pitchFilter.calculate + (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; + } else { + jointRotations.x += joint.pitch * Math.sin + (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; + } + // calculate yaw + if (animation.filters.hasOwnProperty(jointName) && + 'yawFilter' in animation.filters[jointName]) { + jointRotations.y += joint.yaw * animation.filters[jointName].yawFilter.calculate + (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; + } else { + jointRotations.y += joint.yaw * Math.sin + (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; + } + // calculate roll + if (animation.filters.hasOwnProperty(jointName) && + 'rollFilter' in animation.filters[jointName]) { + jointRotations.z += joint.roll * animation.filters[jointName].rollFilter.calculate + (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; + } else { + jointRotations.z += joint.roll * Math.sin + (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; + } + return jointRotations; + }, + + zeroAnimation: function(animation) { + for (i in animation.joints) { + for (j in animation.joints[i]) { + animation.joints[i][j] = 0; + } + } + }, + + blendAnimation: function(sourceAnimation, targetAnimation, percent) { + for (i in targetAnimation.joints) { + targetAnimation.joints[i].pitch += percent * sourceAnimation.joints[i].pitch; + targetAnimation.joints[i].yaw += percent * sourceAnimation.joints[i].yaw; + targetAnimation.joints[i].roll += percent * sourceAnimation.joints[i].roll; + targetAnimation.joints[i].pitchPhase += percent * sourceAnimation.joints[i].pitchPhase; + targetAnimation.joints[i].yawPhase += percent * sourceAnimation.joints[i].yawPhase; + targetAnimation.joints[i].rollPhase += percent * sourceAnimation.joints[i].rollPhase; + targetAnimation.joints[i].pitchOffset += percent * sourceAnimation.joints[i].pitchOffset; + targetAnimation.joints[i].yawOffset += percent * sourceAnimation.joints[i].yawOffset; + targetAnimation.joints[i].rollOffset += percent * sourceAnimation.joints[i].rollOffset; + if (i === "Hips") { + // Hips only + targetAnimation.joints[i].thrust += percent * sourceAnimation.joints[i].thrust; + targetAnimation.joints[i].sway += percent * sourceAnimation.joints[i].sway; + targetAnimation.joints[i].bob += percent * sourceAnimation.joints[i].bob; + targetAnimation.joints[i].thrustPhase += percent * sourceAnimation.joints[i].thrustPhase; + targetAnimation.joints[i].swayPhase += percent * sourceAnimation.joints[i].swayPhase; + targetAnimation.joints[i].bobPhase += percent * sourceAnimation.joints[i].bobPhase; + targetAnimation.joints[i].thrustOffset += percent * sourceAnimation.joints[i].thrustOffset; + targetAnimation.joints[i].swayOffset += percent * sourceAnimation.joints[i].swayOffset; + targetAnimation.joints[i].bobOffset += percent * sourceAnimation.joints[i].bobOffset; + } + } + }, + + deepCopy: function(sourceAnimation, targetAnimation) { + // calibration + targetAnimation.calibration = JSON.parse(JSON.stringify(sourceAnimation.calibration)); + + // harmonics + targetAnimation.harmonics = {}; + if (sourceAnimation.harmonics) { + targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics)); + } + + // filters + targetAnimation.filters = {}; + for (i in sourceAnimation.filters) { + // are any filters specified for this joint? + if (sourceAnimation.filters[i]) { + targetAnimation.filters[i] = sourceAnimation.filters[i]; + // wave shapers + if (sourceAnimation.filters[i].pitchFilter) { + targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter; + } + if (sourceAnimation.filters[i].yawFilter) { + targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter; + } + if (sourceAnimation.filters[i].rollFilter) { + targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter; + } + // LP filters + if (sourceAnimation.filters[i].swayLPFilter) { + targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter; + } + if (sourceAnimation.filters[i].bobLPFilter) { + targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter; + } + if (sourceAnimation.filters[i].thrustLPFilter) { + targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter; + } + } + } + // joints + targetAnimation.joints = JSON.parse(JSON.stringify(sourceAnimation.joints)); + } + } + +})(); // end animation object literal + +// ReachPose datafile wrapper object +ReachPose = function(reachPoseName) { + this.name = reachPoseName; + this.reachPoseParameters = walkAssets.getReachPoseParameters(reachPoseName); + this.reachPoseDataFile = walkAssets.getReachPoseDataFile(reachPoseName); + this.progress = 0; + this.smoothingFilter = filter.createAveragingFilter(this.reachPoseParameters.smoothing); + this.currentStrength = function() { + // apply optionally smoothed (D)ASDR envelope to reach pose's strength / influence whilst active + var segmentProgress = undefined; // progress through chosen segment + var segmentTimeDelta = undefined; // total change in time over chosen segment + var segmentStrengthDelta = undefined; // total change in strength over chosen segment + var lastStrength = undefined; // the last value the previous segment held + var currentStrength = undefined; // return value + + // select parameters based on segment (a segment being one of (D),A,S,D or R) + if (this.progress >= this.reachPoseParameters.sustain.timing) { + // release segment + segmentProgress = this.progress - this.reachPoseParameters.sustain.timing; + segmentTimeDelta = this.reachPoseParameters.release.timing - this.reachPoseParameters.sustain.timing; + segmentStrengthDelta = this.reachPoseParameters.release.strength - this.reachPoseParameters.sustain.strength; + lastStrength = this.reachPoseParameters.sustain.strength; + } else if (this.progress >= this.reachPoseParameters.decay.timing) { + // sustain phase + segmentProgress = this.progress - this.reachPoseParameters.decay.timing; + segmentTimeDelta = this.reachPoseParameters.sustain.timing - this.reachPoseParameters.decay.timing; + segmentStrengthDelta = this.reachPoseParameters.sustain.strength - this.reachPoseParameters.decay.strength; + lastStrength = this.reachPoseParameters.decay.strength; + } else if (this.progress >= this.reachPoseParameters.attack.timing) { + // decay phase + segmentProgress = this.progress - this.reachPoseParameters.attack.timing; + segmentTimeDelta = this.reachPoseParameters.decay.timing - this.reachPoseParameters.attack.timing; + segmentStrengthDelta = this.reachPoseParameters.decay.strength - this.reachPoseParameters.attack.strength; + lastStrength = this.reachPoseParameters.attack.strength; + } else if (this.progress >= this.reachPoseParameters.delay.timing) { + // attack phase + segmentProgress = this.progress - this.reachPoseParameters.delay.timing; + segmentTimeDelta = this.reachPoseParameters.attack.timing - this.reachPoseParameters.delay.timing; + segmentStrengthDelta = this.reachPoseParameters.attack.strength - this.reachPoseParameters.delay.strength; + lastStrength = 0; //this.delay.strength; + } else { + // delay phase + segmentProgress = this.progress; + segmentTimeDelta = this.reachPoseParameters.delay.timing; + segmentStrengthDelta = this.reachPoseParameters.delay.strength; + lastStrength = 0; + } + currentStrength = segmentTimeDelta > 0 ? lastStrength + segmentStrengthDelta * segmentProgress / segmentTimeDelta + : lastStrength; + // smooth off the response curve + currentStrength = this.smoothingFilter.process(currentStrength); + return currentStrength; + } +}; + +// constructor with default parameters +TransitionParameters = function() { + this.duration = 0.5; + this.easingLower = {x:0.25, y:0.75}; + this.easingUpper = {x:0.75, y:0.25}; + this.reachPoses = []; +} + +const QUARTER_CYCLE = 90; +const HALF_CYCLE = 180; +const THREE_QUARTER_CYCLE = 270; +const FULL_CYCLE = 360; + +// constructor for animation Transition +Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) { + + if (playTransitionReachPoses === undefined) { + playTransitionReachPoses = true; + } + + // record the current state of animation + this.nextAnimation = nextAnimation; + this.lastAnimation = lastAnimation; + this.lastTransition = lastTransition; + + // collect information about the currently playing animation + this.direction = motion.direction; + this.lastDirection = motion.lastDirection; + this.lastFrequencyTimeWheelPos = motion.frequencyTimeWheelPos; + this.lastFrequencyTimeIncrement = motion.averageFrequencyTimeIncrement; + this.lastFrequencyTimeWheelRadius = motion.frequencyTimeWheelRadius; + this.degreesToTurn = 0; // total degrees to turn the ft wheel before the avatar stops (walk only) + this.degreesRemaining = 0; // remaining degrees to turn the ft wheel before the avatar stops (walk only) + this.lastElapsedFTDegrees = motion.elapsedFTDegrees; // degrees elapsed since last transition start + motion.elapsedFTDegrees = 0; // reset ready for the next transition + motion.frequencyTimeWheelPos = 0; // start the next animation's frequency time wheel from zero + + // set parameters for the transition + this.parameters = new TransitionParameters(); + this.liveReachPoses = []; + if (walkAssets && lastAnimation && nextAnimation) { + // overwrite this.parameters with any transition parameters specified for this particular transition + walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters); + // fire up any reach poses for this transition + if (playTransitionReachPoses) { + for (poseName in this.parameters.reachPoses) { + this.liveReachPoses.push(new ReachPose(this.parameters.reachPoses[poseName])); + } + } + } + this.startTime = new Date().getTime(); // Starting timestamp (seconds) + this.progress = 0; // how far are we through the transition? + this.filteredProgress = 0; + + // coming to a halt whilst walking? if so, will need a clean stopping point defined + if (motion.isComingToHalt) { + + const FULL_CYCLE_THRESHOLD = 320; + const HALF_CYCLE_THRESHOLD = 140; + const CYCLE_COMMIT_THRESHOLD = 5; + + // how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground? + if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) { + // just stop the walk cycle right here and blend to idle + this.degreesToTurn = 0; + } else if (this.lastElapsedFTDegrees < HALF_CYCLE) { + // we have not taken a complete step yet, so we advance to the second stop angle + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; + } else if (this.lastFrequencyTimeWheelPos > 0 && this.lastFrequencyTimeWheelPos <= HALF_CYCLE_THRESHOLD) { + // complete the step and stop at 180 + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; + } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE_THRESHOLD && this.lastFrequencyTimeWheelPos <= HALF_CYCLE) { + // complete the step and next then stop at 0 + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; + } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE && this.lastFrequencyTimeWheelPos <= FULL_CYCLE_THRESHOLD) { + // complete the step and stop at 0 + this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos; + } else { + // complete the step and the next then stop at 180 + this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; + } + + // transition length in this case should be directly proportional to the remaining degrees to turn + var MIN_FT_INCREMENT = 5.0; // degrees per frame + var MIN_TRANSITION_DURATION = 0.4; + const TWO_THIRDS = 0.6667; + this.lastFrequencyTimeIncrement *= TWO_THIRDS; // help ease the transition + var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ? + this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT; + var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement, + MIN_TRANSITION_DURATION); + this.parameters.duration = timeToFinish; + this.degreesRemaining = this.degreesToTurn; + } + + // deal with transition recursion (overlapping transitions) + this.recursionDepth = 0; + this.incrementRecursion = function() { + this.recursionDepth += 1; + + // cancel any continued motion + this.degreesToTurn = 0; + + // limit the number of layered / nested transitions + if (this.lastTransition !== nullTransition) { + this.lastTransition.incrementRecursion(); + if (this.lastTransition.recursionDepth > MAX_TRANSITION_RECURSION) { + this.lastTransition = nullTransition; + } + } + }; + if (this.lastTransition !== nullTransition) { + this.lastTransition.incrementRecursion(); + } + + // end of transition initialisation. begin Transition public methods + + // keep up the pace for the frequency time wheel for the last animation + this.advancePreviousFrequencyTimeWheel = function(deltaTime) { + var wheelAdvance = undefined; + + if (this.lastAnimation === avatar.selectedWalkBlend && + this.nextAnimation === avatar.selectedIdle) { + if (this.degreesRemaining <= 0) { + // stop continued motion + wheelAdvance = 0; + if (motion.isComingToHalt) { + if (this.lastFrequencyTimeWheelPos < QUARTER_CYCLE) { + this.lastFrequencyTimeWheelPos = 0; + } else { + this.lastFrequencyTimeWheelPos = HALF_CYCLE; + } + } + } else { + wheelAdvance = this.lastFrequencyTimeIncrement; + var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / HALF_CYCLE; + if (this.degreesRemaining <= 0) { + distanceToTravel = 0; + this.degreesRemaining = 0; + } else { + this.degreesRemaining -= wheelAdvance; + } + } + } else { + wheelAdvance = this.lastFrequencyTimeIncrement; + } + + // advance the ft wheel + this.lastFrequencyTimeWheelPos += wheelAdvance; + if (this.lastFrequencyTimeWheelPos >= FULL_CYCLE) { + this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % FULL_CYCLE; + } + + // advance ft wheel for the nested (previous) Transition + if (this.lastTransition !== nullTransition) { + this.lastTransition.advancePreviousFrequencyTimeWheel(deltaTime); + } + // update the lastElapsedFTDegrees for short stepping + this.lastElapsedFTDegrees += wheelAdvance; + this.degreesTurned += wheelAdvance; + }; + + this.updateProgress = function() { + const MILLISECONDS_CONVERT = 1000; + const ACCURACY_INCREASER = 1000; + var elapasedTime = (new Date().getTime() - this.startTime) / MILLISECONDS_CONVERT; + this.progress = elapasedTime / this.parameters.duration; + this.progress = Math.round(this.progress * ACCURACY_INCREASER) / ACCURACY_INCREASER; + + // updated nested transition/s + if (this.lastTransition !== nullTransition) { + if (this.lastTransition.updateProgress() === TRANSITION_COMPLETE) { + // the previous transition is now complete + this.lastTransition = nullTransition; + } + } + + // update any reachPoses + for (pose in this.liveReachPoses) { + // use independent timing for reachPoses + this.liveReachPoses[pose].progress += (motion.deltaTime / this.liveReachPoses[pose].reachPoseParameters.duration); + if (this.liveReachPoses[pose].progress >= 1) { + // time to kill off this reach pose + this.liveReachPoses.splice(pose, 1); + } + } + + // update transition progress + this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper); + return this.progress >= 1 ? TRANSITION_COMPLETE : false; + }; + + this.blendTranslations = function(frequencyTimeWheelPos, direction) { + var lastTranslations = {x:0, y:0, z:0}; + var nextTranslations = animationOperations.calculateTranslations(this.nextAnimation, + frequencyTimeWheelPos, + direction); + // are we blending with a previous, still live transition? + if (this.lastTransition !== nullTransition) { + lastTranslations = this.lastTransition.blendTranslations(this.lastFrequencyTimeWheelPos, + this.lastDirection); + } else { + lastTranslations = animationOperations.calculateTranslations(this.lastAnimation, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } + + // blend last / next translations + nextTranslations = Vec3.multiply(this.filteredProgress, nextTranslations); + lastTranslations = Vec3.multiply((1 - this.filteredProgress), lastTranslations); + nextTranslations = Vec3.sum(nextTranslations, lastTranslations); + + if (this.liveReachPoses.length > 0) { + for (pose in this.liveReachPoses) { + var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); + var poseTranslations = animationOperations.calculateTranslations( + this.liveReachPoses[pose].reachPoseDataFile, + frequencyTimeWheelPos, + direction); + + // can't use Vec3 operations here, as if x,y or z is zero, the reachPose should have no influence at all + if (Math.abs(poseTranslations.x) > 0) { + nextTranslations.x = reachPoseStrength * poseTranslations.x + (1 - reachPoseStrength) * nextTranslations.x; + } + if (Math.abs(poseTranslations.y) > 0) { + nextTranslations.y = reachPoseStrength * poseTranslations.y + (1 - reachPoseStrength) * nextTranslations.y; + } + if (Math.abs(poseTranslations.z) > 0) { + nextTranslations.z = reachPoseStrength * poseTranslations.z + (1 - reachPoseStrength) * nextTranslations.z; + } + } + } + return nextTranslations; + }; + + this.blendRotations = function(jointName, frequencyTimeWheelPos, direction) { + var lastRotations = {x:0, y:0, z:0}; + var nextRotations = animationOperations.calculateRotations(jointName, + this.nextAnimation, + frequencyTimeWheelPos, + direction); + + // are we blending with a previous, still live transition? + if (this.lastTransition !== nullTransition) { + lastRotations = this.lastTransition.blendRotations(jointName, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } else { + lastRotations = animationOperations.calculateRotations(jointName, + this.lastAnimation, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } + // blend last / next translations + nextRotations = Vec3.multiply(this.filteredProgress, nextRotations); + lastRotations = Vec3.multiply((1 - this.filteredProgress), lastRotations); + nextRotations = Vec3.sum(nextRotations, lastRotations); + + // are there reachPoses defined for this transition? + if (this.liveReachPoses.length > 0) { + for (pose in this.liveReachPoses) { + var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); + var poseRotations = animationOperations.calculateRotations(jointName, + this.liveReachPoses[pose].reachPoseDataFile, + frequencyTimeWheelPos, + direction); + + // don't use Vec3 operations here, as if x,y or z is zero, the reach pose should have no influence at all + if (Math.abs(poseRotations.x) > 0) { + nextRotations.x = reachPoseStrength * poseRotations.x + (1 - reachPoseStrength) * nextRotations.x; + } + if (Math.abs(poseRotations.y) > 0) { + nextRotations.y = reachPoseStrength * poseRotations.y + (1 - reachPoseStrength) * nextRotations.y; + } + if (Math.abs(poseRotations.z) > 0) { + nextRotations.z = reachPoseStrength * poseRotations.z + (1 - reachPoseStrength) * nextRotations.z; + } + } + } + return nextRotations; + }; +}; // end Transition constructor + +// individual joint modifiers +FrequencyMultipliers = function(joint, direction) { + // gather multipliers + this.pitchFrequencyMultiplier = 1; + this.yawFrequencyMultiplier = 1; + this.rollFrequencyMultiplier = 1; + this.swayFrequencyMultiplier = 1; + this.bobFrequencyMultiplier = 1; + this.thrustFrequencyMultiplier = 1; + + if (joint) { + if (joint.pitchFrequencyMultiplier) { + this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier; + } + if (joint.yawFrequencyMultiplier) { + this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier; + } + if (joint.rollFrequencyMultiplier) { + this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier; + } + if (joint.swayFrequencyMultiplier) { + this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier; + } + if (joint.bobFrequencyMultiplier) { + this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier; + } + if (joint.thrustFrequencyMultiplier) { + this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier; + } + } }; \ No newline at end of file diff --git a/examples/map.js~ b/examples/map.js~ new file mode 100644 index 0000000000..5a4e0f0f8c --- /dev/null +++ b/examples/map.js~ @@ -0,0 +1,323 @@ +Script.include("entityManager.js"); +Script.include("overlayManager.js"); + + +// Poll for nearby map data + +var entityManager = new EntityManager(); + +// From http://evanw.github.io/lightgl.js/docs/raytracer.html +function raySphereIntersection(origin, ray, center, radius) { + var offset = Vec3.subtract(origin, center); + var a = Vec3.dot(ray, ray); + // var a = ray.dot(ray); + var b = 2 * Vec3.dot(ray, offset); + // var b = 2 * ray.dot(offset); + var c = Vec3.dot(offset, offset) - radius * radius; + // var c = offset.dot(offset) - radius * radius; + var discriminant = b * b - 4 * a * c; + + if (discriminant > 0) { + return true; + } + + return null; +}; + + +Map = function(data) { + var visible = false; + + var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); + var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); + + var ROOT_SCALE = 0.0005; + + // Create object in objectManager + var rootObject = entityManager.addBare(); + var position = ROOT_POSITION; + rootObject.position = ROOT_POSITION; + rootObject.scale = ROOT_SCALE + Vec3.print("Position:", position); + + // Search for all nearby objects that have the userData "mapped" + // TODO Update to use the zone's bounds + var entities = Entities.findEntities(MyAvatar.position, 32000); + var mappedEntities = []; + var minCorner = { + x: 4294967295, + y: 4294967295, + z: 4294967295, + }; + var maxCorner = { + x: -4294967295, + y: -4294967295, + z: -4294967295, + }; + + for (var i = 0; i < entities.length; ++i) { + var entityID = entities[i]; + var properties = Entities.getEntityProperties(entityID); + if (properties.userData == "mapped" || properties.userData == "tracked") { + + print("Found: ", properties.name); + + minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); + minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); + minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); + + maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); + maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); + maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); + + } + // if (properties.userData == "mapped") { + // properties.visible = false; + // var entity = entityManager.add(properties.type, properties); + // mappedEntities.push(entity); + // } else if (properties.userData == "tracked") { + // // TODO implement tracking of objects + // } + } + + var dimensions = { + x: maxCorner.x - minCorner.x, + y: maxCorner.y - minCorner.y, + z: maxCorner.z - minCorner.z, + }; + Vec3.print("dims", dimensions); + + var center = { + x: minCorner.x + (dimensions.x / 2), + y: minCorner.y + (dimensions.y / 2), + z: minCorner.z + (dimensions.z / 2), + }; + Vec3.print("center", center); + + var trackedEntities = []; + var waypointEntities = []; + for (var i = 0; i < entities.length; ++i) { + var entityID = entities[i]; + var properties = Entities.getEntityProperties(entityID); + var mapData = null; + try { + var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); + mapData = data.mapData; + } catch (e) { + print("Caught: ", properties.name); + } + + if (mapData) { + print("Creating copy of", properties.name); + properties.name += " (COPY)"; + properties.userData = ""; + properties.visible = true; + var position = properties.position; + properties.position = Vec3.subtract(properties.position, center); + properties.position = Vec3.multiply(properties.position, ROOT_SCALE); + var extra = { }; + + if (mapData.track) { + extra.trackingEntityID= entityID; + trackedEntities.push(entity); + rootObject.addChild(entity); + } + if (mapData.waypoint) { + print("Waypoint: ", mapData.waypoint.name); + // properties.type = "Model"; + // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; + extra.waypoint = mapData.waypoint; + extra.waypoint.position = position; + } + + var entity = entityManager.add(properties.type, properties); + entity.__extra__ = extra; + if (mapData.waypoint) { + waypointEntities.push(entity); + } + mappedEntities.push(entity); + + rootObject.addChild(entity); + + } else { + // print("Not creating copy of", properties.name); + } + } + + var avatarArrowEntity = entityManager.add("Model", { + name: "You Are Here", + modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", + position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), + dimensions: { x: 30, y: 100, z: 100 }, + }); + rootObject.addChild(avatarArrowEntity); + + this.isVisible = function() { + return visible; + } + + Controller.mousePressEvent.connect(mousePressEvent); + function mousePressEvent(event) { + // Entities.setZonesArePickable(false); + + var pickRay = Camera.computePickRay(event.x, event.y); + for (var i = 0; i < waypointEntities.length; ++i) { + var entity = waypointEntities[i]; + print("Checkit for hit", entity.__extra__.waypoint.name); + var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); + if (result) { + print("Pressed entity: ", entity.id); + print("Pressed waypoint: ", entity.__extra__.waypoint.name); + print("Teleporting..."); + MyAvatar.position = entity.__extra__.waypoint.position; + break; + } + } + // var result = Entities.findRayIntersection(pickRay, false); + // if (result.intersects) { + // var entity = entityManager.get(result.entityID); + // if (entity) { + // print("Pressed entity: ", entity.id); + // } + // if (entity && entity.__extra__.waypoint) { + // print("Pressed waypoint: ", entity.__extra__.waypoint.name); + // print("Teleporting..."); + // MyAvatar.position = entity.__extra__.waypoint.position; + // } + // } + + // Entities.setZonesArePickable(true); + }; + + var time = 0; + Script.update.connect(function(dt) { + time += dt; + // Update tracked entities + for (var i = 0; i < trackedEntities.length; ++i) { + entity = trackedEntities[i]; + var entityID = entity.__extra__.trackingEntityID; + var properties = Entities.getEntityProperties(entityID); + properties.position = Vec3.subtract(properties.position, center); + properties.position = Vec3.multiply(properties.position, ROOT_SCALE); + entity.position = properties.position; + } + + + var position = Vec3.subtract(MyAvatar.position, center) + position.y += 60 + (Math.sin(time) * 10); + position = Vec3.multiply(position, ROOT_SCALE); + avatarArrowEntity.position = position; + // Vec3.print("Position:", avatarArrowEntity.position); + + // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); + //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); + //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); + // position = ROOT_POSITION; + rootObject.position = ROOT_POSITION; + entityManager.update(); + + // Update waypoint highlights + var pickRay = Camera.computePickRay(event.x, event.y); + for (var i = 0; i < waypointEntities.length; ++i) { + var entity = waypointEntities[i]; + print("Checkit for hit", entity.__extra__.waypoint.name); + var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); + if (result) { + print("Pressed entity: ", entity.id); + print("Pressed waypoint: ", entity.__extra__.waypoint.name); + print("Teleporting..."); + MyAvatar.position = entity.__extra__.waypoint.position; + break; + } + } + }); + + function setVisible(newValue) { + if (visible != newValue) { + visible = newValue; + + if (visible) { + } else { + } + } + } + + this.show = function() { + setVisible(true); + } + + this.hide = function() { + setVisible(false); + } +}; + +var map = null; +map = Map(mapData); + +// On press key +Controller.keyPressEvent.connect(function(event) { + if (event.text == "m") { + if (!map) { + map = Map(mapData); + } + + map.show(); + print("MAP!"); + } +}); + + + + + +var mapData = { + config: { + // World dimensions that the minimap maps to + worldDimensions: { + x: 10.0, + y: 10.0, + z: 10.0, + }, + // The center of the map should map to this location in the center of the area + worldCenter: { + x: 5.0, + y: 5.0, + z: 5.0, + }, + // Map dimensions + mapDimensions: { + x: 10.0, + y: 10.0, + z: 10.0, + }, + + // Can this be automated? Tag entities that should be included? Store in UserData? + objects: [ + { + type: "Model", + modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", + }, + ], + }, + waypoints: [ + { + name: "Forest's Edge", + position: { + }, + }, + ], +}; + + +// entityManager = new OverlayManager(); +// entityManager = new EntityManager(); +// +// var rootEntity = entityManager.addBare(); +// +// var time = 0; +// +// +// rootEntity.scale = 0.1; +// Script.include("sfData.js"); +// rootEntity.addChild(entity); +entityManager.update(); diff --git a/examples/pitching.js b/examples/pitching.js index 046113cbc3..b419e8935c 100644 --- a/examples/pitching.js +++ b/examples/pitching.js @@ -142,6 +142,7 @@ function createBaseball(position, velocity, ballScale) { var buildBaseballHitCallback = function(entityID) { var f = function(entityA, entityB, collision) { + print("Got baseball hit callback"); var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); var lastPosition = properties.position; @@ -154,11 +155,12 @@ var buildBaseballHitCallback = function(entityID) { lastPosition = properties.position; } }, 50); + var speed = Vec3.length(properties.velocity); Entities.editEntity(entityID, { - velocity: Vec3.multiply(3, properties.velocity), + velocity: Vec3.multiply(2, properties.velocity), gravity: { x: 0, - y: -2.8, + y: -9.8, z: 0 } }); diff --git a/examples/toys/flashlight/flashlight.js b/examples/toys/flashlight/flashlight.js index a775f185e3..912d542d6c 100644 --- a/examples/toys/flashlight/flashlight.js +++ b/examples/toys/flashlight/flashlight.js @@ -1,269 +1,269 @@ -// -// flashlight.js -// -// Script Type: Entity -// -// Created by Sam Gateau on 9/9/15. -// Additions by James B. Pollack @imgntn on 9/21/2015 -// Copyright 2015 High Fidelity, Inc. -// -// This is a toy script that can be added to the Flashlight model entity: -// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" -// that creates a spotlight attached with the flashlight model while the entity is grabbed -// -// 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("../../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'; - - //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them - var startTime = Date.now(); - //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. - var LIFETIME = 25; - var MSEC_PER_SEC = 1000.0; - - // 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) - 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; - - // 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 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) { - - return { - 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 = { - lightOn: false, - hand: null, - whichHand: null, - hasSpotlight: false, - spotlight: null, - setRightHand: function() { - this.hand = 'RIGHT'; - }, - - setLeftHand: function() { - this.hand = 'LEFT'; - }, - - startNearGrab: function() { - if (!this.hasSpotlight) { - - //this light casts the beam - this.spotlight = Entities.addEntity({ - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME - }); - - //this light creates the effect of a bulb at the end of the flashlight - this.glowLight = Entities.addEntity({ - type: "Light", - dimensions: { - x: 0.25, - y: 0.25, - z: 0.25 - }, - isSpotlight: false, - color: { - red: 255, - green: 255, - blue: 255 - }, - exponent: 0, - cutoff: 90, // in degrees - lifetime: LIFETIME - }); - - this.hasSpotlight = true; - - } - - }, - - setWhichHand: function() { - this.whichHand = this.hand; - }, - - 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(); - } else { - this.updateLightPositions(); - this.changeLightWithTriggerPressure(this.whichHand); - } - }, - - releaseGrab: function() { - //delete the lights and reset state - if (this.hasSpotlight) { - Entities.deleteEntity(this.spotlight); - Entities.deleteEntity(this.glowLight); - this.hasSpotlight = false; - this.glowLight = null; - this.spotlight = null; - this.whichHand = null; - this.lightOn = false; - } - }, - - 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, - lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME - }); - - Entities.editEntity(this.glowLight, { - position: glowLightTransform.p, - rotation: glowLightTransform.q, - lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME - }); - - }, - - changeLightWithTriggerPressure: function(flashLightHand) { - var handClickString = flashLightHand + "_HAND_CLICK"; - - var handClick = Controller.findAction(handClickString); - - this.triggerValue = Controller.getActionValue(handClick); - - if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { - this.turnLightOff(); - } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { - this.turnLightOn(); - } - return; - }, - - turnLightOff: function() { - this.playSoundAtCurrentPosition(false); - Entities.editEntity(this.spotlight, { - intensity: 0 - }); - Entities.editEntity(this.glowLight, { - intensity: 0 - }); - this.lightOn = false; - }, - - turnLightOn: function() { - this.playSoundAtCurrentPosition(true); - - Entities.editEntity(this.glowLight, { - intensity: 2 - }); - Entities.editEntity(this.spotlight, { - intensity: 2 - }); - this.lightOn = true; - }, - - playSoundAtCurrentPosition: function(playOnSound) { - var position = Entities.getEntityProperties(this.entityID, "position").position; - - var audioProperties = { - volume: 0.25, - position: position - }; - - if (playOnSound) { - Audio.playSound(this.ON_SOUND, audioProperties); - } else { - Audio.playSound(this.OFF_SOUND, audioProperties); - } - }, - - 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); - this.hasSpotlight = false; - this.glowLight = null; - this.spotlight = null; - this.whichHand = null; - this.lightOn = false; - } - - }, - - }; - - // entity scripts always need to return a newly constructed object of our type - return new Flashlight(); +// +// flashlight.js +// +// Script Type: Entity +// +// Created by Sam Gateau on 9/9/15. +// Additions by James B. Pollack @imgntn on 9/21/2015 +// Copyright 2015 High Fidelity, Inc. +// +// This is a toy script that can be added to the Flashlight model entity: +// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" +// that creates a spotlight attached with the flashlight model while the entity is grabbed +// +// 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("../../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'; + + //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them + var startTime = Date.now(); + //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. + var LIFETIME = 25; + var MSEC_PER_SEC = 1000.0; + + // 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) + 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; + + // 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 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) { + + return { + 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 = { + lightOn: false, + hand: null, + whichHand: null, + hasSpotlight: false, + spotlight: null, + setRightHand: function() { + this.hand = 'RIGHT'; + }, + + setLeftHand: function() { + this.hand = 'LEFT'; + }, + + startNearGrab: function() { + if (!this.hasSpotlight) { + + //this light casts the beam + this.spotlight = Entities.addEntity({ + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME + }); + + //this light creates the effect of a bulb at the end of the flashlight + this.glowLight = Entities.addEntity({ + type: "Light", + dimensions: { + x: 0.25, + y: 0.25, + z: 0.25 + }, + isSpotlight: false, + color: { + red: 255, + green: 255, + blue: 255 + }, + exponent: 0, + cutoff: 90, // in degrees + lifetime: LIFETIME + }); + + this.hasSpotlight = true; + + } + + }, + + setWhichHand: function() { + this.whichHand = this.hand; + }, + + 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(); + } else { + this.updateLightPositions(); + this.changeLightWithTriggerPressure(this.whichHand); + } + }, + + releaseGrab: function() { + //delete the lights and reset state + if (this.hasSpotlight) { + Entities.deleteEntity(this.spotlight); + Entities.deleteEntity(this.glowLight); + this.hasSpotlight = false; + this.glowLight = null; + this.spotlight = null; + this.whichHand = null; + this.lightOn = false; + } + }, + + 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, + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME + }); + + Entities.editEntity(this.glowLight, { + position: glowLightTransform.p, + rotation: glowLightTransform.q, + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME + }); + + }, + + changeLightWithTriggerPressure: function(flashLightHand) { + var handClickString = flashLightHand + "_HAND_CLICK"; + + var handClick = Controller.findAction(handClickString); + + this.triggerValue = Controller.getActionValue(handClick); + + if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { + this.turnLightOff(); + } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { + this.turnLightOn(); + } + return; + }, + + turnLightOff: function() { + this.playSoundAtCurrentPosition(false); + Entities.editEntity(this.spotlight, { + intensity: 0 + }); + Entities.editEntity(this.glowLight, { + intensity: 0 + }); + this.lightOn = false; + }, + + turnLightOn: function() { + this.playSoundAtCurrentPosition(true); + + Entities.editEntity(this.glowLight, { + intensity: 2 + }); + Entities.editEntity(this.spotlight, { + intensity: 2 + }); + this.lightOn = true; + }, + + playSoundAtCurrentPosition: function(playOnSound) { + var position = Entities.getEntityProperties(this.entityID, "position").position; + + var audioProperties = { + volume: 0.25, + position: position + }; + + if (playOnSound) { + Audio.playSound(this.ON_SOUND, audioProperties); + } else { + Audio.playSound(this.OFF_SOUND, audioProperties); + } + }, + + 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); + this.hasSpotlight = false; + this.glowLight = null; + this.spotlight = null; + this.whichHand = null; + this.lightOn = false; + } + + }, + + }; + + // entity scripts always need to return a newly constructed object of our type + return new Flashlight(); }); \ No newline at end of file diff --git a/examples/walk.js b/examples/walk.js index 0b5bcab65a..63b5599cc2 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,454 +1,454 @@ -// -// walk.js -// version 1.25 -// -// Created by David Wooldridge, June 2015 -// Copyright © 2014 - 2015 High Fidelity, Inc. -// -// Animates an avatar using procedural animation techniques. -// -// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files -const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/"; -var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/"; - -Script.include([ - "./libraries/walkConstants.js", - "./libraries/walkFilters.js", - "./libraries/walkApi.js", - pathToAssets + "walkAssets.js" -]); - -// construct Avatar, Motion and (null) Transition -var avatar = new Avatar(); -var motion = new Motion(); -var nullTransition = new Transition(); -motion.currentTransition = nullTransition; - -// create settings (gets initial values from avatar) -Script.include("./libraries/walkSettings.js"); - -// Main loop -Script.update.connect(function(deltaTime) { - - if (motion.isLive) { - - // assess current locomotion state - motion.assess(deltaTime); - - // decide which animation should be playing - selectAnimation(); - - // advance the animation cycle/s by the correct amount/s - advanceAnimations(); - - // update the progress of any live transitions - updateTransitions(); - - // apply translation and rotations - renderMotion(); - - // save this frame's parameters - motion.saveHistory(); - } -}); - -// helper function for selectAnimation() -function setTransition(nextAnimation, playTransitionReachPoses) { - var lastTransition = motion.currentTransition; - var lastAnimation = avatar.currentAnimation; - - // if already transitioning from a blended walk need to maintain the previous walk's direction - if (lastAnimation.lastDirection) { - switch(lastAnimation.lastDirection) { - - case FORWARDS: - lastAnimation = avatar.selectedWalk; - break; - - case BACKWARDS: - lastAnimation = avatar.selectedWalkBackwards; - break; - - case LEFT: - lastAnimation = avatar.selectedSideStepLeft; - break; - - case RIGHT: - lastAnimation = avatar.selectedSideStepRight; - break; - } - } - - motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); - avatar.currentAnimation = nextAnimation; - - // reset default first footstep - if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) { - avatar.nextStep = RIGHT; - } -} - -// fly animation blending: smoothing / damping filters -const FLY_BLEND_DAMPING = 50; -var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); - -// select / blend the appropriate animation for the current state of motion -function selectAnimation() { - var playTransitionReachPoses = true; - - // select appropriate animation. create transitions where appropriate - switch (motion.nextState) { - case STATIC: { - if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && - avatar.currentAnimation !== avatar.selectedIdle) { - setTransition(avatar.selectedIdle, playTransitionReachPoses); - } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && - avatar.currentAnimation !== avatar.selectedHover) { - setTransition(avatar.selectedHover, playTransitionReachPoses); - } - motion.state = STATIC; - avatar.selectedWalkBlend.lastDirection = NONE; - break; - } - - case SURFACE_MOTION: { - // walk transition reach poses are currently only specified for starting to walk forwards - playTransitionReachPoses = (motion.direction === FORWARDS); - var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); - - switch (motion.direction) { - case FORWARDS: - if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { - animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); - avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; - } - avatar.selectedWalkBlend.lastDirection = FORWARDS; - break; - - case BACKWARDS: - if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { - animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); - avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; - } - avatar.selectedWalkBlend.lastDirection = BACKWARDS; - break; - - case LEFT: - animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = LEFT; - avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength; - break - - case RIGHT: - animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = RIGHT; - avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; - break; - - default: - // condition occurs when the avi goes through the floor due to collision hull errors - animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = FORWARDS; - avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; - break; - } - - if (!isAlreadyWalking && !motion.isComingToHalt) { - setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); - } - motion.state = SURFACE_MOTION; - break; - } - - case AIR_MOTION: { - // blend the up, down, forward and backward flying animations relative to motion speed and direction - animationOperations.zeroAnimation(avatar.selectedFlyBlend); - - // calculate influences based on velocity and direction - var velocityMagnitude = Vec3.length(motion.velocity); - var verticalProportion = motion.velocity.y / velocityMagnitude; - var thrustProportion = motion.velocity.z / velocityMagnitude / 2; - - // directional components - var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; - var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; - var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; - var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; - - // smooth / damp directional components to add visual 'weight' - upComponent = flyUpFilter.process(upComponent); - downComponent = flyDownFilter.process(downComponent); - forwardComponent = flyForwardFilter.process(forwardComponent); - backwardComponent = flyBackwardFilter.process(backwardComponent); - - // normalise directional components - var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; - upComponent = upComponent / normaliser; - downComponent = downComponent / normaliser; - forwardComponent = forwardComponent / normaliser; - backwardComponent = backwardComponent / normaliser; - - // blend animations proportionally - if (upComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyUp, - avatar.selectedFlyBlend, - upComponent); - } - if (downComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyDown, - avatar.selectedFlyBlend, - downComponent); - } - if (forwardComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFly, - avatar.selectedFlyBlend, - Math.abs(forwardComponent)); - } - if (backwardComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyBackwards, - avatar.selectedFlyBlend, - Math.abs(backwardComponent)); - } - - if (avatar.currentAnimation !== avatar.selectedFlyBlend) { - setTransition(avatar.selectedFlyBlend, playTransitionReachPoses); - } - motion.state = AIR_MOTION; - avatar.selectedWalkBlend.lastDirection = NONE; - break; - } - } // end switch next state of motion -} - -// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions -function advanceAnimations() { - var wheelAdvance = 0; - - // turn the frequency time wheel - if (avatar.currentAnimation === avatar.selectedWalkBlend) { - // Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach - // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed - // omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length - var speed = Vec3.length(motion.velocity); - motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI; - var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius; - // calculate the degrees turned (at this angular speed) since last frame - wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); - } else { - // turn the frequency time wheel by the amount specified for this animation - wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); - } - - if (motion.currentTransition !== nullTransition) { - // the last animation is still playing so we turn it's frequency time wheel to maintain the animation - if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) { - // if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition - var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1; - if ((motion.currentTransition.lastFrequencyTimeWheelPos > - (motion.currentTransition.stopAngle - tolerance)) && - (motion.currentTransition.lastFrequencyTimeWheelPos < - (motion.currentTransition.stopAngle + tolerance))) { - motion.currentTransition.lastFrequencyTimeIncrement = 0; - } - } - motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); - } - - // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding - if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { - wheelAdvance = 0; - } - - // advance the walk wheel the appropriate amount - motion.advanceFrequencyTimeWheel(wheelAdvance); - - // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) - const ALMOST_ONE = 0.97; - if (avatar.currentAnimation === avatar.selectedWalkBlend && - (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { - - var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; - const TOLERANCE = 1.0; - - if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) && - motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) && - motion.currentTransition === nullTransition) { - // measure and save stride length - var footRPos = MyAvatar.getJointPosition("RightFoot"); - var footLPos = MyAvatar.getJointPosition("LeftFoot"); - avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos); - avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength; - } else { - // use the previously saved value for stride length - avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength; - } - } // end get walk stride length -} - -// initialise a new transition. update progress of a live transition -function updateTransitions() { - - if (motion.currentTransition !== nullTransition) { - // is this a new transition? - if (motion.currentTransition.progress === 0) { - // do we have overlapping transitions? - if (motion.currentTransition.lastTransition !== nullTransition) { - // is the last animation for the nested transition the same as the new animation? - if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) { - // then sync the nested transition's frequency time wheel for a smooth animation blend - motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos; - } - } - } - if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) { - motion.currentTransition = nullTransition; - } - } -} - -// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity -var leanPitchSmoothingFilter = filter.createButterworthFilter(); -function getLeanPitch() { - var leanProgress = 0; - - if (motion.direction === DOWN || - motion.direction === FORWARDS || - motion.direction === BACKWARDS) { - leanProgress = -motion.velocity.z / TOP_SPEED; - } - // use filters to shape the walking acceleration response - leanProgress = leanPitchSmoothingFilter.process(leanProgress); - return PITCH_MAX * leanProgress; -} - -// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning -var leanRollSmoothingFilter = filter.createButterworthFilter(); -function getLeanRoll() { - var leanRollProgress = 0; - var linearContribution = 0; - const LOG_SCALER = 8; - - if (Vec3.length(motion.velocity) > 0) { - linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; - } - var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX; - leanRollProgress = linearContribution; - leanRollProgress *= angularContribution; - // shape the response curve - leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); - // which way to lean? - var turnSign = (motion.yawDelta >= 0) ? 1 : -1; - - if (motion.direction === BACKWARDS || - motion.direction === LEFT) { - turnSign *= -1; - } - // filter progress - leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress); - return ROLL_MAX * leanRollProgress; -} - -// animate the avatar using sine waves, geometric waveforms and harmonic generators -function renderMotion() { - // leaning in response to speed and acceleration - var leanPitch = motion.state === STATIC ? 0 : getLeanPitch(); - var leanRoll = motion.state === STATIC ? 0 : getLeanRoll(); - var lastDirection = motion.lastDirection; - // hips translations from currently playing animations - var hipsTranslations = {x:0, y:0, z:0}; - - if (motion.currentTransition !== nullTransition) { - // maintain previous direction when transitioning from a walk - if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - motion.lastDirection = motion.currentTransition.lastDirection; - } - hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos, - motion.lastDirection); - } else { - hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation, - motion.frequencyTimeWheelPos, - motion.direction); - } - // factor any leaning into the hips offset - hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); - hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); - - // ensure skeleton offsets are within the 1m limit - hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; - hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; - hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y; - hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y; - hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z; - hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z; - // apply translations - MyAvatar.setSkeletonOffset(hipsTranslations); - - // play footfall sound? - var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; - - if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { - if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || - motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - producingFootstepSounds = true; - } - } - if (producingFootstepSounds) { - const QUARTER_CYCLE = 90; - const THREE_QUARTER_CYCLE = 270; - var ftWheelPosition = motion.frequencyTimeWheelPos; - - if (motion.currentTransition !== nullTransition && - motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; - } - if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) { - avatar.makeFootStepSound(); - } else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) { - avatar.makeFootStepSound(); - } - } - - // apply joint rotations - for (jointName in avatar.currentAnimation.joints) { - var joint = walkAssets.animationReference.joints[jointName]; - var jointRotations = undefined; - - // ignore arms / head rotations if options are selected in the settings - if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { - continue; - } - if (avatar.headFree && joint.IKChain === "Head") { - continue; - } - - // if there's a live transition, blend the rotations with the last animation's rotations - if (motion.currentTransition !== nullTransition) { - jointRotations = motion.currentTransition.blendRotations(jointName, - motion.frequencyTimeWheelPos, - motion.lastDirection); - } else { - jointRotations = animationOperations.calculateRotations(jointName, - avatar.currentAnimation, - motion.frequencyTimeWheelPos, - motion.direction); - } - - // apply angular velocity and speed induced leaning - if (jointName === "Hips") { - jointRotations.x += leanPitch; - jointRotations.z += leanRoll; - } - - // apply rotations - MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations)); - } +// +// walk.js +// version 1.25 +// +// Created by David Wooldridge, June 2015 +// Copyright © 2014 - 2015 High Fidelity, Inc. +// +// Animates an avatar using procedural animation techniques. +// +// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files +const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/"; +var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/"; + +Script.include([ + "./libraries/walkConstants.js", + "./libraries/walkFilters.js", + "./libraries/walkApi.js", + pathToAssets + "walkAssets.js" +]); + +// construct Avatar, Motion and (null) Transition +var avatar = new Avatar(); +var motion = new Motion(); +var nullTransition = new Transition(); +motion.currentTransition = nullTransition; + +// create settings (gets initial values from avatar) +Script.include("./libraries/walkSettings.js"); + +// Main loop +Script.update.connect(function(deltaTime) { + + if (motion.isLive) { + + // assess current locomotion state + motion.assess(deltaTime); + + // decide which animation should be playing + selectAnimation(); + + // advance the animation cycle/s by the correct amount/s + advanceAnimations(); + + // update the progress of any live transitions + updateTransitions(); + + // apply translation and rotations + renderMotion(); + + // save this frame's parameters + motion.saveHistory(); + } +}); + +// helper function for selectAnimation() +function setTransition(nextAnimation, playTransitionReachPoses) { + var lastTransition = motion.currentTransition; + var lastAnimation = avatar.currentAnimation; + + // if already transitioning from a blended walk need to maintain the previous walk's direction + if (lastAnimation.lastDirection) { + switch(lastAnimation.lastDirection) { + + case FORWARDS: + lastAnimation = avatar.selectedWalk; + break; + + case BACKWARDS: + lastAnimation = avatar.selectedWalkBackwards; + break; + + case LEFT: + lastAnimation = avatar.selectedSideStepLeft; + break; + + case RIGHT: + lastAnimation = avatar.selectedSideStepRight; + break; + } + } + + motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); + avatar.currentAnimation = nextAnimation; + + // reset default first footstep + if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) { + avatar.nextStep = RIGHT; + } +} + +// fly animation blending: smoothing / damping filters +const FLY_BLEND_DAMPING = 50; +var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); + +// select / blend the appropriate animation for the current state of motion +function selectAnimation() { + var playTransitionReachPoses = true; + + // select appropriate animation. create transitions where appropriate + switch (motion.nextState) { + case STATIC: { + if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && + avatar.currentAnimation !== avatar.selectedIdle) { + setTransition(avatar.selectedIdle, playTransitionReachPoses); + } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && + avatar.currentAnimation !== avatar.selectedHover) { + setTransition(avatar.selectedHover, playTransitionReachPoses); + } + motion.state = STATIC; + avatar.selectedWalkBlend.lastDirection = NONE; + break; + } + + case SURFACE_MOTION: { + // walk transition reach poses are currently only specified for starting to walk forwards + playTransitionReachPoses = (motion.direction === FORWARDS); + var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); + + switch (motion.direction) { + case FORWARDS: + if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { + animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); + avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; + } + avatar.selectedWalkBlend.lastDirection = FORWARDS; + break; + + case BACKWARDS: + if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { + animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); + avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; + } + avatar.selectedWalkBlend.lastDirection = BACKWARDS; + break; + + case LEFT: + animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = LEFT; + avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength; + break + + case RIGHT: + animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = RIGHT; + avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; + break; + + default: + // condition occurs when the avi goes through the floor due to collision hull errors + animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = FORWARDS; + avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; + break; + } + + if (!isAlreadyWalking && !motion.isComingToHalt) { + setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); + } + motion.state = SURFACE_MOTION; + break; + } + + case AIR_MOTION: { + // blend the up, down, forward and backward flying animations relative to motion speed and direction + animationOperations.zeroAnimation(avatar.selectedFlyBlend); + + // calculate influences based on velocity and direction + var velocityMagnitude = Vec3.length(motion.velocity); + var verticalProportion = motion.velocity.y / velocityMagnitude; + var thrustProportion = motion.velocity.z / velocityMagnitude / 2; + + // directional components + var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; + var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; + var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; + var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; + + // smooth / damp directional components to add visual 'weight' + upComponent = flyUpFilter.process(upComponent); + downComponent = flyDownFilter.process(downComponent); + forwardComponent = flyForwardFilter.process(forwardComponent); + backwardComponent = flyBackwardFilter.process(backwardComponent); + + // normalise directional components + var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; + upComponent = upComponent / normaliser; + downComponent = downComponent / normaliser; + forwardComponent = forwardComponent / normaliser; + backwardComponent = backwardComponent / normaliser; + + // blend animations proportionally + if (upComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyUp, + avatar.selectedFlyBlend, + upComponent); + } + if (downComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyDown, + avatar.selectedFlyBlend, + downComponent); + } + if (forwardComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFly, + avatar.selectedFlyBlend, + Math.abs(forwardComponent)); + } + if (backwardComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyBackwards, + avatar.selectedFlyBlend, + Math.abs(backwardComponent)); + } + + if (avatar.currentAnimation !== avatar.selectedFlyBlend) { + setTransition(avatar.selectedFlyBlend, playTransitionReachPoses); + } + motion.state = AIR_MOTION; + avatar.selectedWalkBlend.lastDirection = NONE; + break; + } + } // end switch next state of motion +} + +// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions +function advanceAnimations() { + var wheelAdvance = 0; + + // turn the frequency time wheel + if (avatar.currentAnimation === avatar.selectedWalkBlend) { + // Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach + // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed + // omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length + var speed = Vec3.length(motion.velocity); + motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI; + var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius; + // calculate the degrees turned (at this angular speed) since last frame + wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); + } else { + // turn the frequency time wheel by the amount specified for this animation + wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); + } + + if (motion.currentTransition !== nullTransition) { + // the last animation is still playing so we turn it's frequency time wheel to maintain the animation + if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) { + // if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition + var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1; + if ((motion.currentTransition.lastFrequencyTimeWheelPos > + (motion.currentTransition.stopAngle - tolerance)) && + (motion.currentTransition.lastFrequencyTimeWheelPos < + (motion.currentTransition.stopAngle + tolerance))) { + motion.currentTransition.lastFrequencyTimeIncrement = 0; + } + } + motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); + } + + // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding + if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { + wheelAdvance = 0; + } + + // advance the walk wheel the appropriate amount + motion.advanceFrequencyTimeWheel(wheelAdvance); + + // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) + const ALMOST_ONE = 0.97; + if (avatar.currentAnimation === avatar.selectedWalkBlend && + (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { + + var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; + const TOLERANCE = 1.0; + + if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) && + motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) && + motion.currentTransition === nullTransition) { + // measure and save stride length + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos); + avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength; + } else { + // use the previously saved value for stride length + avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength; + } + } // end get walk stride length +} + +// initialise a new transition. update progress of a live transition +function updateTransitions() { + + if (motion.currentTransition !== nullTransition) { + // is this a new transition? + if (motion.currentTransition.progress === 0) { + // do we have overlapping transitions? + if (motion.currentTransition.lastTransition !== nullTransition) { + // is the last animation for the nested transition the same as the new animation? + if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) { + // then sync the nested transition's frequency time wheel for a smooth animation blend + motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos; + } + } + } + if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) { + motion.currentTransition = nullTransition; + } + } +} + +// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity +var leanPitchSmoothingFilter = filter.createButterworthFilter(); +function getLeanPitch() { + var leanProgress = 0; + + if (motion.direction === DOWN || + motion.direction === FORWARDS || + motion.direction === BACKWARDS) { + leanProgress = -motion.velocity.z / TOP_SPEED; + } + // use filters to shape the walking acceleration response + leanProgress = leanPitchSmoothingFilter.process(leanProgress); + return PITCH_MAX * leanProgress; +} + +// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning +var leanRollSmoothingFilter = filter.createButterworthFilter(); +function getLeanRoll() { + var leanRollProgress = 0; + var linearContribution = 0; + const LOG_SCALER = 8; + + if (Vec3.length(motion.velocity) > 0) { + linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; + } + var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX; + leanRollProgress = linearContribution; + leanRollProgress *= angularContribution; + // shape the response curve + leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); + // which way to lean? + var turnSign = (motion.yawDelta >= 0) ? 1 : -1; + + if (motion.direction === BACKWARDS || + motion.direction === LEFT) { + turnSign *= -1; + } + // filter progress + leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress); + return ROLL_MAX * leanRollProgress; +} + +// animate the avatar using sine waves, geometric waveforms and harmonic generators +function renderMotion() { + // leaning in response to speed and acceleration + var leanPitch = motion.state === STATIC ? 0 : getLeanPitch(); + var leanRoll = motion.state === STATIC ? 0 : getLeanRoll(); + var lastDirection = motion.lastDirection; + // hips translations from currently playing animations + var hipsTranslations = {x:0, y:0, z:0}; + + if (motion.currentTransition !== nullTransition) { + // maintain previous direction when transitioning from a walk + if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + motion.lastDirection = motion.currentTransition.lastDirection; + } + hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos, + motion.lastDirection); + } else { + hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation, + motion.frequencyTimeWheelPos, + motion.direction); + } + // factor any leaning into the hips offset + hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); + hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); + + // ensure skeleton offsets are within the 1m limit + hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; + hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; + hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y; + hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y; + hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z; + hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z; + // apply translations + MyAvatar.setSkeletonOffset(hipsTranslations); + + // play footfall sound? + var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; + + if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { + if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || + motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + producingFootstepSounds = true; + } + } + if (producingFootstepSounds) { + const QUARTER_CYCLE = 90; + const THREE_QUARTER_CYCLE = 270; + var ftWheelPosition = motion.frequencyTimeWheelPos; + + if (motion.currentTransition !== nullTransition && + motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; + } + if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) { + avatar.makeFootStepSound(); + } else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) { + avatar.makeFootStepSound(); + } + } + + // apply joint rotations + for (jointName in avatar.currentAnimation.joints) { + var joint = walkAssets.animationReference.joints[jointName]; + var jointRotations = undefined; + + // ignore arms / head rotations if options are selected in the settings + if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { + continue; + } + if (avatar.headFree && joint.IKChain === "Head") { + continue; + } + + // if there's a live transition, blend the rotations with the last animation's rotations + if (motion.currentTransition !== nullTransition) { + jointRotations = motion.currentTransition.blendRotations(jointName, + motion.frequencyTimeWheelPos, + motion.lastDirection); + } else { + jointRotations = animationOperations.calculateRotations(jointName, + avatar.currentAnimation, + motion.frequencyTimeWheelPos, + motion.direction); + } + + // apply angular velocity and speed induced leaning + if (jointName === "Hips") { + jointRotations.x += leanPitch; + jointRotations.z += leanRoll; + } + + // apply rotations + MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations)); + } } \ No newline at end of file From bfd96194040b880d91c1b22b61274fea44fb717f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Oct 2015 10:10:04 -0700 Subject: [PATCH 006/171] add simple script that spawns a bat when run --- examples/toys/baseball.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 examples/toys/baseball.js diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js new file mode 100644 index 0000000000..79a8a2fd61 --- /dev/null +++ b/examples/toys/baseball.js @@ -0,0 +1,30 @@ +// +// baseball.js +// examples/toys +// +// Created by Stephen Birarda on 10/20/15. +// 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 +// + +var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; +var BAT_COLLISION_SHAPE = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + +function createNewBat() { + // move entity three units in front of the avatar + var batPosition = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: -0.3, z: -2 })); + + var wand = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: batPosition, + collisionsWillMove: true, + compoundShapeURL: BAT_COLLISION_SHAPE + }); +} + +createNewBat(); From 1e39c9359f363cbde506ba5411e1bf3bf8da161f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Oct 2015 11:53:38 -0700 Subject: [PATCH 007/171] don't force parenting of AssetRequest/AssetUpload --- libraries/networking/src/AssetClient.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b7f1205847..6a1b46340c 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -89,7 +89,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) request->moveToThread(thread()); - request->setParent(this); return request; } else { @@ -105,7 +104,6 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { auto upload = new AssetUpload(filename); upload->moveToThread(thread()); - upload->setParent(this); return upload; } else { @@ -118,7 +116,6 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex auto upload = new AssetUpload(data, extension); upload->moveToThread(thread()); - upload->setParent(this); return upload; } else { From 8f83870e527ab2d59eaf8237b5a1d297439016c3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 14:19:21 -0700 Subject: [PATCH 008/171] Update pitching.js to add audio --- examples/baseball/audio/assets.txt | 23 ++++ examples/baseball/audio/attribution.txt | 8 ++ examples/baseball/line.js | 165 ++++++++++++++++++++++++ examples/{ => baseball}/pitching.js | 0 4 files changed, 196 insertions(+) create mode 100644 examples/baseball/audio/assets.txt create mode 100644 examples/baseball/audio/attribution.txt create mode 100644 examples/baseball/line.js rename examples/{ => baseball}/pitching.js (100%) diff --git a/examples/baseball/audio/assets.txt b/examples/baseball/audio/assets.txt new file mode 100644 index 0000000000..225714cbe1 --- /dev/null +++ b/examples/baseball/audio/assets.txt @@ -0,0 +1,23 @@ +crowd-boos.wav +atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav + +crowd-cheers-organ.wav +atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav + +crowd-medium.wav +atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav + +baseball-hitting-bat-1.wav +atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav + +baseball-hitting-bat-set-1.wav +atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav + +baseball-hitting-bat-set-2.wav +atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav + +baseball-hitting-bat-set-3.wav +atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav + +baseball-hitting-bat-set-4.wav +atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav \ No newline at end of file diff --git a/examples/baseball/audio/attribution.txt b/examples/baseball/audio/attribution.txt new file mode 100644 index 0000000000..760951447c --- /dev/null +++ b/examples/baseball/audio/attribution.txt @@ -0,0 +1,8 @@ +Baseball bat hitting sounds +https://www.freesound.org/people/SocializedArtist45/sounds/266595/ +https://www.freesound.org/people/CGEffex/sounds/93136/ + +Crowd Sounds +http://freesound.org/people/AshFox/sounds/191925/ +http://freesound.org/people/AshFox/sounds/191928/ +http://freesound.org/people/AshFox/sounds/191929/ \ No newline at end of file diff --git a/examples/baseball/line.js b/examples/baseball/line.js new file mode 100644 index 0000000000..c4fac784c4 --- /dev/null +++ b/examples/baseball/line.js @@ -0,0 +1,165 @@ +function info(message) { + print("[INFO] " + message); +} + +function error(message) { + print("[ERROR] " + message); +} + + +/****************************************************************************** + * PolyLine + *****************************************************************************/ +var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; +var MAX_LINE_LENGTH = 40; // This must be 2 or greater; +var PolyLine = function(position, color, defaultStrokeWidth) { + //info("Creating polyline"); + //Vec3.print("New line at", position); + this.position = position; + this.color = color; + this.defaultStrokeWidth = 0.10; + this.points = [ + { x: 0, y: 0, z: 0 }, + ]; + this.strokeWidths = [ + this.defaultStrokeWidth, + ] + this.normals = [ + { x: 1, y: 0, z: 0 }, + ] + this.entityID = Entities.addEntity({ + type: "PolyLine", + position: position, + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + dimensions: LINE_DIMENSIONS, + color: color, + lifetime: 20, + }); +}; + +PolyLine.prototype.enqueuePoint = function(position) { + if (this.isFull()) { + error("Hit max PolyLine size"); + return; + } + + //Vec3.print("pos", position); + //info("Number of points: " + this.points.length); + + position = Vec3.subtract(position, this.position); + this.points.push(position); + this.normals.push({ x: 1, y: 0, z: 0 }); + this.strokeWidths.push(this.defaultStrokeWidth); + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.dequeuePoint = function() { + if (this.points.length == 0) { + error("Hit min PolyLine size"); + return; + } + + this.points = this.points.slice(1); + this.normals = this.normals.slice(1); + this.strokeWidths = this.strokeWidths.slice(1); + + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.getFirstPoint = function() { + return Vec3.sum(this.position, this.points[0]); +}; + +PolyLine.prototype.getLastPoint = function() { + return Vec3.sum(this.position, this.points[this.points.length - 1]); +}; + +PolyLine.prototype.getSize = function() { + return this.points.length; +} + +PolyLine.prototype.isFull = function() { + return this.points.length >= MAX_LINE_LENGTH; +}; + +PolyLine.prototype.destroy = function() { + Entities.deleteEntity(this.entityID); + this.points = []; +}; + + +/****************************************************************************** + * InfiniteLine + *****************************************************************************/ +InfiniteLine = function(position, color) { + this.position = position; + this.color = color; + this.lines = [new PolyLine(position, color)]; + this.size = 0; +}; + +InfiniteLine.prototype.enqueuePoint = function(position) { + var currentLine; + + if (this.lines.length == 0) { + currentLine = new PolyLine(position, this.color); + this.lines.push(currentLine); + } else { + currentLine = this.lines[this.lines.length - 1]; + } + + if (currentLine.isFull()) { + //info("Current line is full, creating new line"); + //Vec3.print("Last line is", currentLine.getLastPoint()); + //Vec3.print("New line is", position); + var newLine = new PolyLine(currentLine.getLastPoint(), this.color); + this.lines.push(newLine); + currentLine = newLine; + } + + currentLine.enqueuePoint(position); + + ++this.size; +}; + +InfiniteLine.prototype.dequeuePoint = function() { + if (this.lines.length == 0) { + error("Trying to dequeue from InfiniteLine when no points are left"); + return; + } + + var lastLine = this.lines[0]; + lastLine.dequeuePoint(); + + if (lastLine.getSize() <= 1) { + this.lines = this.lines.slice(1); + } + + --this.size; +}; + +InfiniteLine.prototype.getFirstPoint = function() { + return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; +}; + +InfiniteLine.prototype.getLastPoint = function() { + return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; +}; + +InfiniteLine.prototype.destroy = function() { + for (var i = 0; i < this.lines.length; ++i) { + this.lines[i].destroy(); + } + + this.size = 0; +}; diff --git a/examples/pitching.js b/examples/baseball/pitching.js similarity index 100% rename from examples/pitching.js rename to examples/baseball/pitching.js From 934575a78a1216c89c8636b3d7aa352d82e259d4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 16:46:07 -0700 Subject: [PATCH 009/171] Refactor pitching.js --- examples/baseball/pitching.js | 332 ++++++++++++++-------------------- 1 file changed, 139 insertions(+), 193 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index b419e8935c..5cb29ac5d7 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,16 +1,25 @@ -//var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/323725__reitanna__thunk.wav"; -var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/thunk.wav"; +Script.include("line.js"); + +var AUDIO = { + crowdBoos: [ + SoundCache.getSound("atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", false) + ], + crowdCheers: [ + SoundCache.getSound("atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav", false), + SoundCache.getSound("atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav", false), + ], + batHit: [ + SoundCache.getSound("atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav", false), + SoundCache.getSound("atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav", false), + SoundCache.getSound("atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", false), + SoundCache.getSound("atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", false), + SoundCache.getSound("atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", false), + ] +} + var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); -function info(message) { - print("[INFO] " + message); -} - -function error(message) { - print("[ERROR] " + message); -} - var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { x: 0.0, @@ -23,7 +32,7 @@ var PITCHING_MACHINE_PROPERTIES = { position: { x: 0, y: 0.8, - z: -22.3, + z: -18.3, }, velocity: { x: 0, @@ -51,12 +60,13 @@ var PITCHING_MACHINE_PROPERTIES = { shapeType: "Box", }; PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); - +var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_SPEED = 2.7; +var BASEBALL_MIN_SPEED = 2.7; +var BASEBALL_MAX_SPEED = 5.7; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", @@ -78,13 +88,17 @@ var BASEBALL_PROPERTIES = { x: 17.0, y: 0, z: -8.0, + + x: 0.0, + y: 0, + z: 0.0, }, angularDamping: 0.0, damping: 0.0, restitution: 0.5, friction: 0.0, lifetime: 20, - collisionSoundURL: PITCH_THUNK_SOUND_URL, + //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { x: 0, y: 0,//-9.8, @@ -107,23 +121,44 @@ function shallowCopy(obj) { } function randomInt(low, high) { - return low + (Math.random() * (high - low)); + return Math.floor(randomFloat(low, high)); +} + +function randomFloat(low, high) { + if (high === undefined) { + high = low; + low = 0; + } + return low + Math.random() * (high - low); } var ACCELERATION_SPREAD = 10.15; -function createBaseball(position, velocity, ballScale) { +function Baseball(position, velocity, ballScale) { + var self = this; + + // Setup entity properties var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; - properties.acceleration = { + /* + properties.gravity = { x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, }; + */ properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); - var entityID = Entities.addEntity(properties); - Script.addEventHandler(entityID, "collisionWithEntity", buildBaseballHitCallback(entityID)); + + // Create entity + this.entityID = Entities.addEntity(properties); + this.trail = null; + this.onHit = function() { return true; }; + this.hasBeenHit = false; + + this.boundCollisionCallback = function(a, b, c) { self.collisionCallback.call(self, a, b, c); }; + Script.addEventHandler(this.entityID, "collisionWithEntity", this.boundCollisionCallback); + /* if (false && Math.random() < 0.5) { for (var i = 0; i < 50; i++) { Script.setTimeout(function() { @@ -137,26 +172,39 @@ function createBaseball(position, velocity, ballScale) { }, i * 100); } } - return entityID; + */ } -var buildBaseballHitCallback = function(entityID) { - var f = function(entityA, entityB, collision) { - print("Got baseball hit callback"); - var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); - var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); +Baseball.prototype = { + collisionCallback: function(entityA, entityB, collision) { + var self = this; + + this.hasBeenHit = true; + var properties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + this.trail = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); var lastPosition = properties.position; - Vec3.print("Velocity", properties.velocity); - Vec3.print("VelocityChange", collision.velocityChange); - Script.setInterval(function() { - var properties = Entities.getEntityProperties(entityID, ['position']); + //Vec3.print("Velocity", properties.velocity); + //Vec3.print("VelocityChange", collision.velocityChange); + var speed = Vec3.length(properties.velocity); + playRandomSound(AUDIO.batHit, { + position: properties.position, + volume: 2.0 + }); + var sounds = null; + if (speed < 5.0) { + sounds = AUDIO.crowdBoos; + } else { + sounds = AUDIO.crowdCheers; + } + var self = this; + this.trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(self.entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - line.enqueuePoint(properties.position); + self.trail.enqueuePoint(properties.position); lastPosition = properties.position; } }, 50); - var speed = Vec3.length(properties.velocity); - Entities.editEntity(entityID, { + Entities.editEntity(self.entityID, { velocity: Vec3.multiply(2, properties.velocity), gravity: { x: 0, @@ -164,12 +212,35 @@ var buildBaseballHitCallback = function(entityID) { z: 0 } }); - print("Baseball hit!"); - Script.removeEventHandler(entityID, "collisionWithEntity", f); - }; - return f; + + var removeHandler = this.onHit(entityB, collision); + if (removeHandler) { + Script.removeEventHandler(self.entityID, "collisionWithEntity", self.boundCollisionCallback); + } + }, + cleanupTrail: function() { + if (this.trail) { + Script.clearInterval(this.trailInterval); + this.trailInterval = null; + + this.trail.destroy(); + this.trail = null; + } + } } +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +var lastTrail = null; + function vec3Mult(a, b) { return { @@ -179,8 +250,14 @@ function vec3Mult(a, b) { }; } +var lastBall = null; var injector = null; + function pitchBall() { + if (lastBall) { + lastBall.cleanupTrail(); + } + var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -189,7 +266,32 @@ function pitchBall() { var pitchDirection = Quat.getFront(machineProperties.rotation); var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; print("Creating baseball"); - var ballEntityID = createBaseball(pitchFromPosition, Vec3.multiply(BASEBALL_SPEED, pitchDirection), ballScale); + + var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) + var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; + + var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); + lastBall = baseball; + + baseball.onHit = function(entityB, collision) { + var properties = Entities.getEntityProperties(entityB, ["name"]); + var name = properties.name; + print("Hit: " + name); + if (name == "backstop") { + print("STRIKE"); + } else if (name == "bat") { + print("HIT"); + Script.setTimeout(function() { + playRandomSound(sounds, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0, + }); + }, 500); + } + //Script.clearTimeout(strikeTimeout); + return true; + } + if (!injector) { injector = Audio.playSound(pitchSound, { position: pitchFromPosition, @@ -209,159 +311,3 @@ Script.setInterval(pitchBall, PITCH_RATE); -/****************************************************************************** - * PolyLine - *****************************************************************************/ -var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; -var MAX_LINE_LENGTH = 40; // This must be 2 or greater; -var PolyLine = function(position, color, defaultStrokeWidth) { - //info("Creating polyline"); - //Vec3.print("New line at", position); - this.position = position; - this.color = color; - this.defaultStrokeWidth = 0.10; - this.points = [ - { x: 0, y: 0, z: 0 }, - ]; - this.strokeWidths = [ - this.defaultStrokeWidth, - ] - this.normals = [ - { x: 1, y: 0, z: 0 }, - ] - this.entityID = Entities.addEntity({ - type: "PolyLine", - position: position, - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - dimensions: LINE_DIMENSIONS, - color: color, - lifetime: 20, - }); -}; - -PolyLine.prototype.enqueuePoint = function(position) { - if (this.isFull()) { - error("Hit max PolyLine size"); - return; - } - - //Vec3.print("pos", position); - //info("Number of points: " + this.points.length); - - position = Vec3.subtract(position, this.position); - this.points.push(position); - this.normals.push({ x: 1, y: 0, z: 0 }); - this.strokeWidths.push(this.defaultStrokeWidth); - Entities.editEntity(this.entityID, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - }); -}; - -PolyLine.prototype.dequeuePoint = function() { - if (this.points.length == 0) { - error("Hit min PolyLine size"); - return; - } - - this.points = this.points.slice(1); - this.normals = this.normals.slice(1); - this.strokeWidths = this.strokeWidths.slice(1); - - Entities.editEntity(this.entityID, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - }); -}; - -PolyLine.prototype.getFirstPoint = function() { - return Vec3.sum(this.position, this.points[0]); -}; - -PolyLine.prototype.getLastPoint = function() { - return Vec3.sum(this.position, this.points[this.points.length - 1]); -}; - -PolyLine.prototype.getSize = function() { - return this.points.length; -} - -PolyLine.prototype.isFull = function() { - return this.points.length >= MAX_LINE_LENGTH; -}; - -PolyLine.prototype.destroy = function() { - Entities.deleteEntity(this.entityID); - this.points = []; -}; - - -/****************************************************************************** - * InfiniteLine - *****************************************************************************/ -InfiniteLine = function(position, color) { - this.position = position; - this.color = color; - this.lines = [new PolyLine(position, color)]; - this.size = 0; -}; - -InfiniteLine.prototype.enqueuePoint = function(position) { - var currentLine; - - if (this.lines.length == 0) { - currentLine = new PolyLine(position, this.color); - this.lines.push(currentLine); - } else { - currentLine = this.lines[this.lines.length - 1]; - } - - if (currentLine.isFull()) { - //info("Current line is full, creating new line"); - //Vec3.print("Last line is", currentLine.getLastPoint()); - //Vec3.print("New line is", position); - var newLine = new PolyLine(currentLine.getLastPoint(), this.color); - this.lines.push(newLine); - currentLine = newLine; - } - - currentLine.enqueuePoint(position); - - ++this.size; -}; - -InfiniteLine.prototype.dequeuePoint = function() { - if (this.lines.length == 0) { - error("Trying to dequeue from InfiniteLine when no points are left"); - return; - } - - var lastLine = this.lines[0]; - lastLine.dequeuePoint(); - - if (lastLine.getSize() <= 1) { - this.lines = this.lines.slice(1); - } - - --this.size; -}; - -InfiniteLine.prototype.getFirstPoint = function() { - return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; -}; - -InfiniteLine.prototype.getLastPoint = function() { - return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; -}; - -InfiniteLine.prototype.destroy = function() { - for (var i = 0; i < this.lines.length; ++i) { - this.lines[i].destroy(); - } - - this.size = 0; -}; From a9bad8de664f07501287a648d4005af6f3e77801 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 11:12:02 -0700 Subject: [PATCH 010/171] add a script for ambient crowd noise --- examples/acScripts/baseballCrowd.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 examples/acScripts/baseballCrowd.js diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js new file mode 100644 index 0000000000..5007c64b16 --- /dev/null +++ b/examples/acScripts/baseballCrowd.js @@ -0,0 +1,21 @@ +// +// baseballCrowd.js +// examples/acScripts +// +// Created by Stephen Birarda on 10/20/15. +// 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 +// + +var crowd1 = SoundCache.getSound("atp:0e921b644464d56d5b412ea2ea1d83f8ff3f7506c4b0471ea336a4770daf3b82.wav"); + +function maybePlaySound(deltaTime) { + if (crowd1.downloaded && !crowd1.isPlaying) { + Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true}); + Script.update.disconnect(maybePlaySound); + } +} + +Script.update.connect(maybePlaySound); From cfa47d2fc62d42c81568a2fddb08ef61d980605f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 14:45:08 -0700 Subject: [PATCH 011/171] use triggers to swing with robot --- examples/toys/baseball.js | 59 +++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 15 deletions(-) mode change 100644 => 100755 examples/toys/baseball.js diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js old mode 100644 new mode 100755 index 79a8a2fd61..5863708a86 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -9,22 +9,51 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; -var BAT_COLLISION_SHAPE = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; +var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; +var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } -function createNewBat() { - // move entity three units in front of the avatar - var batPosition = Vec3.sum(MyAvatar.position, - Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: -0.3, z: -2 })); +var lastTriggerValue = 0.0; - var wand = Entities.addEntity({ - name: 'Bat', - type: "Model", - modelURL: BAT_MODEL, - position: batPosition, - collisionsWillMove: true, - compoundShapeURL: BAT_COLLISION_SHAPE - }); +function checkTriggers() { + var rightTrigger = Controller.getTriggerValue(1); + + if (rightTrigger == 0) { + if (lastTriggerValue > 0) { + // the trigger was just released, play out to the last frame of the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 21, + lastFrame: 115 + } + }); + } + } else { + if (lastTriggerValue == 0) { + // the trigger was just depressed, start the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 0, + lastFrame: 21 + } + }); + } + } + + lastTriggerValue = rightTrigger; } -createNewBat(); +// add the fresh bat at home plate +var robot = Entities.addEntity({ + name: 'Robot', + type: "Model", + modelURL: ROBOT_MODEL, + position: ROBOT_POSITION, + animation: { + url: ROBOT_MODEL + } +}); + +// hook the update so we can check controller triggers +Script.update.connect(checkTriggers); From 4f6da68a1fc8ccc08c4efdff48988cc49120c954 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 16:25:28 -0700 Subject: [PATCH 012/171] add getJointPosition and getJointRotation for entities --- examples/toys/baseball.js | 57 ++++++++-- .../src/RenderableModelEntityItem.cpp | 25 ++++ .../src/RenderableModelEntityItem.h | 3 + .../entities/src/EntityScriptingInterface.cpp | 107 ++++++++---------- .../entities/src/EntityScriptingInterface.h | 6 + libraries/entities/src/ModelEntityItem.h | 3 + 6 files changed, 132 insertions(+), 69 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index 5863708a86..f3f26a1f4b 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -12,6 +12,27 @@ var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } +var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" +var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" + +// add the fresh robot at home plate +var robot = Entities.addEntity({ + name: 'Robot', + type: 'Model', + modelURL: ROBOT_MODEL, + position: ROBOT_POSITION, + animation: { + url: ROBOT_MODEL + } +}); + +// add the bat +var bat = Entities.addEntity({ + name: 'Bat', + type: 'Model', + modelURL: BAT_MODEL +}) + var lastTriggerValue = 0.0; function checkTriggers() { @@ -35,7 +56,7 @@ function checkTriggers() { animation: { running: true, currentFrame: 0, - lastFrame: 21 + lastFrame: 21 } }); } @@ -44,16 +65,28 @@ function checkTriggers() { lastTriggerValue = rightTrigger; } -// add the fresh bat at home plate -var robot = Entities.addEntity({ - name: 'Robot', - type: "Model", - modelURL: ROBOT_MODEL, - position: ROBOT_POSITION, - animation: { - url: ROBOT_MODEL - } -}); +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var ACTION_LIFETIME = 15; // seconds + +function moveBat() { + var forearmPosition = Entities.getJointPosition(robot, 40); + var forearmRotation = Entities.getJointRotation(robot, 40); + + Vec3.print("forearmPosition=", forearmPosition); + + Entities.addAction("spring", bat, { + targetPosition: forearmPosition, + targetRotation: forearmRotation, + tag: "bat-to-forearm", + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + lifetime: ACTION_LIFETIME + }); +} + +function update() { + checkTriggers(); +} // hook the update so we can check controller triggers -Script.update.connect(checkTriggers); +Script.update.connect(update); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e604bdb925..a7c2ff09f4 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -575,3 +575,28 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } + +glm::vec3 RenderableModelEntityItem::getJointPosition(int jointIndex) const { + glm::vec3 position; + + if (_model) { + if (!_model->getJointPositionInWorldFrame(jointIndex, position)) { + position = glm::vec3(); + } + } + + return position; +} + +glm::quat RenderableModelEntityItem::getJointRotation(int jointIndex) const { + glm::quat rotation; + + if (_model) { + if (!_model->getJointRotationInWorldFrame(jointIndex, rotation)) { + rotation = glm::quat(); + } + } + + return rotation; +} + diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4dc1cced48..64629ad291 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -67,6 +67,9 @@ public: void computeShapeInfo(ShapeInfo& info); virtual bool contains(const glm::vec3& point) const; + + virtual glm::vec3 getJointPosition(int jointIndex) const override; + virtual glm::quat getJointRotation(int jointIndex) const override; private: void remapTextures(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 01d46e0a91..f18e216bb3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -681,82 +681,75 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, return result; } -glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) { +EntityItemPointer EntityScriptingInterface::checkForTreeEntityAndTypeMatch(const QUuid& entityID, + EntityTypes::EntityType entityType) { if (!_entityTree) { - return glm::vec3(0.0f); + return EntityItemPointer(); } - + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToWorldCoords no entity with ID" << entityID; + qDebug() << "EntityScriptingInterface::checkForTreeEntityAndTypeMatch - no entity with ID" << entityID; + return entity; + } + + if (entityType != EntityTypes::Unknown && entity->getType() != entityType) { + return EntityItemPointer(); + } + + return entity; +} + +glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords); + } else { return glm::vec3(0.0f); } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords); } glm::vec3 EntityScriptingInterface::worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::worldCoordsToVoxelCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); } glm::vec3 EntityScriptingInterface::voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToLocalCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords); } glm::vec3 EntityScriptingInterface::localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->localCoordsToVoxelCoords(localCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::localCoordsToVoxelCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->localCoordsToVoxelCoords(localCoords); +} + +glm::vec3 EntityScriptingInterface::getJointPosition(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getJointPosition(jointIndex); + } else { + return glm::vec3(0.0f); + } +} + +glm::quat EntityScriptingInterface::getJointRotation(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getJointRotation(jointIndex); + } else { + return glm::quat(); + } } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d764cd7bab..4578c2d7ff 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -150,6 +150,9 @@ public slots: Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords); Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords); + + Q_INVOKABLE glm::vec3 getJointPosition(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::quat getJointRotation(const QUuid& entityID, int jointIndex); signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -182,6 +185,9 @@ private: bool setVoxels(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); + + EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID, + EntityTypes::EntityType entityType = EntityTypes::Unknown); /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e8ffcab3e7..66d46bcf4c 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -120,6 +120,9 @@ public: virtual bool shouldBePhysical() const; static void cleanupLoadedAnimations(); + + virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); } + virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); } private: void setAnimationSettings(const QString& value); // only called for old bitstream format From 5f166044ecdec6f2553b28f993efd6830793a622 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 12:03:19 -0700 Subject: [PATCH 013/171] Make handler generators more readable --- libraries/script-engine/src/ScriptEngine.cpp | 47 +++++++++----------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 76590f266b..a317f2a82c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -508,26 +508,29 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& // Connect up ALL the handlers to the global entities object's signals. // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) auto entities = DependencyManager::get(); - connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, - [=](const EntityItemID& entityID) { - _registeredHandlers.remove(entityID); - }); - + connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { + _registeredHandlers.remove(entityID); + }); + // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this); - }); + auto makeSingleEntityHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); - }); + auto makeMouseHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; + + auto makeCollisionHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), + collisionToScriptValue(this, collision) }); + }; + }; + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); @@ -543,12 +546,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); - connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, - [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - generalHandler(idA, "collisionWithEntity", [=]() { - return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); - }); - }); + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); } if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); @@ -899,9 +897,9 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator) { +void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { - qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); return; } @@ -915,9 +913,8 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e } QScriptValueList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { - QScriptValueList args = argGenerator(); for (int i = 0; i < handlersForEvent.count(); ++i) { - handlersForEvent[i].call(QScriptValue(), args); + handlersForEvent[i].call(QScriptValue(), eventHanderArgs); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1d3986143a..c2f9d966f1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -193,7 +193,7 @@ private: ArrayBufferClass* _arrayBufferClass; QHash _registeredHandlers; - void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator); + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); static QSet _allKnownScriptEngines; From 05b794259e6cb8b1f2dd0835ae4bfeba84374f4f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 16:43:37 -0700 Subject: [PATCH 014/171] Script cleanup and particles on ground collisions --- examples/baseball/pitching.js | 245 ++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 103 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 5cb29ac5d7..1f8df39a7b 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -132,8 +132,70 @@ function randomFloat(low, high) { return low + Math.random() * (high - low); } +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +function vec3Mult(a, b) { + return { + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, + }; +} + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} + +function orientationOf(vector) { + var RAD_TO_DEG = 180.0 / Math.PI; + var Y_AXIS = { x: 0, y: 1, z: 0 }; + var X_AXIS = { x: 1, y: 0, z: 0 }; + var direction = Vec3.normalize(vector); + + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); + var pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); + + return Quat.multiply(yaw, pitch); +} + +var injector = null; + var ACCELERATION_SPREAD = 10.15; +var trail = null; +var trailInterval = null; +function cleanupTrail() { + if (trail) { + Script.clearInterval(this.trailInterval); + trailInterval = null; + + trail.destroy(); + trail = null; + } +} + +function setupTrail(entityID, position) { + cleanupTrail(); + + var lastPosition = position; + trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); + trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + trail.enqueuePoint(properties.position); + lastPosition = properties.position; + } + }, 50); +} + function Baseball(position, velocity, ballScale) { var self = this; @@ -141,6 +203,7 @@ function Baseball(position, velocity, ballScale) { var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; + properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); /* properties.gravity = { x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), @@ -148,16 +211,14 @@ function Baseball(position, velocity, ballScale) { z: 0.0, }; */ - properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); - + // Create entity this.entityID = Entities.addEntity(properties); - this.trail = null; - this.onHit = function() { return true; }; - this.hasBeenHit = false; - this.boundCollisionCallback = function(a, b, c) { self.collisionCallback.call(self, a, b, c); }; - Script.addEventHandler(this.entityID, "collisionWithEntity", this.boundCollisionCallback); + // Listen for collision for the lifetime of the entity + Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { + self.collisionCallback(entityA, entityB, collision); + }); /* if (false && Math.random() < 0.5) { for (var i = 0; i < 50; i++) { @@ -178,86 +239,52 @@ function Baseball(position, velocity, ballScale) { Baseball.prototype = { collisionCallback: function(entityA, entityB, collision) { var self = this; - - this.hasBeenHit = true; - var properties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); - this.trail = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); - var lastPosition = properties.position; - //Vec3.print("Velocity", properties.velocity); - //Vec3.print("VelocityChange", collision.velocityChange); - var speed = Vec3.length(properties.velocity); - playRandomSound(AUDIO.batHit, { - position: properties.position, - volume: 2.0 - }); - var sounds = null; - if (speed < 5.0) { - sounds = AUDIO.crowdBoos; - } else { - sounds = AUDIO.crowdCheers; - } - var self = this; - this.trailInterval = Script.setInterval(function() { - var properties = Entities.getEntityProperties(self.entityID, ['position']); - if (Vec3.distance(properties.position, lastPosition)) { - self.trail.enqueuePoint(properties.position); - lastPosition = properties.position; - } - }, 50); + var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + var myPosition = myProperties.position; + var myVelocity = myProperties.velocity; + + // Activate gravity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, properties.velocity), - gravity: { - x: 0, - y: -9.8, - z: 0 - } + gravity: { x: 0, y: -9.8, z: 0 } }); - var removeHandler = this.onHit(entityB, collision); - if (removeHandler) { - Script.removeEventHandler(self.entityID, "collisionWithEntity", self.boundCollisionCallback); - } - }, - cleanupTrail: function() { - if (this.trail) { - Script.clearInterval(this.trailInterval); - this.trailInterval = null; - - this.trail.destroy(); - this.trail = null; + var name = Entities.getEntityProperties(entityB, ["name"]).name; + print("Hit: " + name); + if (name == "Bat") { + print("HIT"); + + // Update ball velocity + Entities.editEntity(self.entityID, { + velocity: Vec3.multiply(2, myVelocity), + }); + + // Setup line update interval + setupTrail(self.entityID, myPosition); + + // Setup bat hit sound + playRandomSound(AUDIO.batHit, { + position: myPosition, + volume: 2.0 + }); + + // Setup crowd reaction sound + var speed = Vec3.length(myVelocity); + Script.setTimeout(function() { + playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0 + }); + }, 500); + } else if (name == "stadium") { + print("PARTICLES"); + entityCollisionWithGround(entityB, this.entityID, collision); + } else if (name == "backstop") { + print("STRIKE"); } } } -function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } - Audio.playSound(sounds[randomInt(sounds.length)], options); -} - -var lastTrail = null; - - -function vec3Mult(a, b) { - return { - x: a.x * b.x, - y: a.y * b.y, - z: a.z * b.z, - }; -} - -var lastBall = null; -var injector = null; - function pitchBall() { - if (lastBall) { - lastBall.cleanupTrail(); - } - var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -271,26 +298,6 @@ function pitchBall() { var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); - lastBall = baseball; - - baseball.onHit = function(entityB, collision) { - var properties = Entities.getEntityProperties(entityB, ["name"]); - var name = properties.name; - print("Hit: " + name); - if (name == "backstop") { - print("STRIKE"); - } else if (name == "bat") { - print("HIT"); - Script.setTimeout(function() { - playRandomSound(sounds, { - position: { x: 0 ,y: 0, z: 0 }, - volume: 1.0, - }); - }, 500); - } - //Script.clearTimeout(strikeTimeout); - return true; - } if (!injector) { injector = Audio.playSound(pitchSound, { @@ -302,12 +309,44 @@ function pitchBall() { } } +function entityCollisionWithGround(ground, entity, collision) { + var ZERO_VEC = { x: 0, y: 0, z: 0 }; + var dVelocityMagnitude = Vec3.length(collision.velocityChange); + var position = Entities.getEntityProperties(entity, "position").position; + var particleRadius = 0.3;//map(dVelocityMagnitude, 0.05, 3, 0.5, 2); + var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); + var displayTime = 400; + var orientationChange = orientationOf(collision.velocityChange); + + var dustEffect = Entities.addEntity({ + type: "ParticleEffect", + name: "Dust-Puff", + position: position, + color: {red: 195, green: 170, blue: 185}, + lifespan: 3, + lifetime: 2,//displayTime/1000 * 2, //So we can fade particle system out gracefully + emitRate: 5, + emitSpeed: speed, + emitAcceleration: ZERO_VEC, + accelerationSpread: ZERO_VEC, + isEmitting: true, + polarStart: Math.PI/2, + polarFinish: Math.PI/2, + emitOrientation: orientationChange, + radiusSpread: 0.1, + radiusStart: particleRadius, + radiusFinish: particleRadius + particleRadius / 2, + particleRadius: particleRadius, + alpha: 0.45, + alphaFinish: 0.001, + textures: "https://hifi-public.s3.amazonaws.com/alan/Playa/Particles/Particle-Sprite-Gen.png" + }); +} + Script.scriptEnding.connect(function() { + cleanupTrail(); Entities.deleteEntity(pitchingMachineID); -}) +}); Script.setInterval(pitchBall, PITCH_RATE); - - - From 70c32e4b13120d550e18eaa1b679722b4863cf24 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 16:45:57 -0700 Subject: [PATCH 015/171] Remove empty script --- examples/baseballEntityScript.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/baseballEntityScript.js diff --git a/examples/baseballEntityScript.js b/examples/baseballEntityScript.js deleted file mode 100644 index e69de29bb2..0000000000 From 9e5e886761bdfc07031409d519f401c153ff8deb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 16:47:43 -0700 Subject: [PATCH 016/171] try to move the bat directly to robot --- examples/toys/baseball.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index f3f26a1f4b..5ad21b162f 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -22,7 +22,8 @@ var robot = Entities.addEntity({ modelURL: ROBOT_MODEL, position: ROBOT_POSITION, animation: { - url: ROBOT_MODEL + url: ROBOT_MODEL, + running: true } }); @@ -74,18 +75,23 @@ function moveBat() { Vec3.print("forearmPosition=", forearmPosition); - Entities.addAction("spring", bat, { - targetPosition: forearmPosition, - targetRotation: forearmRotation, - tag: "bat-to-forearm", - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - lifetime: ACTION_LIFETIME + // Entities.addAction("spring", bat, { + // targetPosition: forearmPosition, + // targetRotation: forearmRotation, + // linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + // angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + // lifetime: ACTION_LIFETIME + // }); + + Entities.editEntity(bat, { + position: forearmPosition, + rotation: forearmRotation }); } function update() { checkTriggers(); + moveBat(); } // hook the update so we can check controller triggers From 001400908d3d27fc33ea9cb5c4004675d67c2588 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 23 Oct 2015 13:37:49 -0700 Subject: [PATCH 017/171] Add automatic CCD activation to the physics engine --- libraries/physics/src/ObjectMotionState.cpp | 18 ++++++++++++++++++ libraries/physics/src/ObjectMotionState.h | 1 + 2 files changed, 19 insertions(+) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 4f3d0396c6..b47c870216 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -115,6 +115,21 @@ void ObjectMotionState::setMotionType(MotionType motionType) { _motionType = motionType; } +void ObjectMotionState::updateCCDConfiguration() { + if (_body) { + if (_shape) { + btVector3 center; + btScalar radius; + _shape->getBoundingSphere(center, radius); + _body->setCcdMotionThreshold(radius * 2.0f); + _body->setCcdSweptSphereRadius(radius); + } else { + // Disable CCD + _body->setCcdMotionThreshold(0); + } + } +} + void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { @@ -125,6 +140,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { if (_body) { _body->setUserPointer(this); } + updateCCDConfiguration(); } } @@ -187,6 +203,8 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* if (_shape != newShape) { _shape = newShape; _body->setCollisionShape(_shape); + + updateCCDConfiguration(); } else { // huh... the shape didn't actually change, so we clear the DIRTY_SHAPE flag flags &= ~Simulation::DIRTY_SHAPE; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 450ac34a90..9945d07c33 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -137,6 +137,7 @@ protected: virtual bool isReadyToComputeShape() = 0; virtual btCollisionShape* computeNewShape() = 0; void setMotionType(MotionType motionType); + void updateCCDConfiguration(); // clearObjectBackPointer() overrrides should call the base method, then actually clear the object back pointer. virtual void clearObjectBackPointer() { _type = MOTIONSTATE_TYPE_INVALID; } From 4e33aa84e873d0dd16d3ad602ba34ea16d851c97 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 12:03:19 -0700 Subject: [PATCH 018/171] Make handler generators more readable --- libraries/script-engine/src/ScriptEngine.cpp | 47 +++++++++----------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 76590f266b..a317f2a82c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -508,26 +508,29 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& // Connect up ALL the handlers to the global entities object's signals. // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) auto entities = DependencyManager::get(); - connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, - [=](const EntityItemID& entityID) { - _registeredHandlers.remove(entityID); - }); - + connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { + _registeredHandlers.remove(entityID); + }); + // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this); - }); + auto makeSingleEntityHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); - }); + auto makeMouseHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; + + auto makeCollisionHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), + collisionToScriptValue(this, collision) }); + }; + }; + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); @@ -543,12 +546,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); - connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, - [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - generalHandler(idA, "collisionWithEntity", [=]() { - return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); - }); - }); + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); } if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); @@ -899,9 +897,9 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator) { +void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { - qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); return; } @@ -915,9 +913,8 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e } QScriptValueList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { - QScriptValueList args = argGenerator(); for (int i = 0; i < handlersForEvent.count(); ++i) { - handlersForEvent[i].call(QScriptValue(), args); + handlersForEvent[i].call(QScriptValue(), eventHanderArgs); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1d3986143a..c2f9d966f1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -193,7 +193,7 @@ private: ArrayBufferClass* _arrayBufferClass; QHash _registeredHandlers; - void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator); + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); static QSet _allKnownScriptEngines; From 421d967e492971bb6414604e77817044ce5528ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 15:40:56 -0700 Subject: [PATCH 019/171] Improve script engine error logging + some cleanup --- libraries/script-engine/src/ScriptEngine.cpp | 74 ++++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 5 +- libraries/shared/src/LogHandler.cpp | 2 +- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a317f2a82c..cbe9449551 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -556,7 +556,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& } -QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { +QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { if (_stoppingAllScripts) { return QScriptValue(); // bail early } @@ -565,27 +565,30 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN QScriptValue result; #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "program:" << program << " fileName:" << fileName << "lineNumber:" << lineNumber; + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; #endif QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QScriptValue, result), - Q_ARG(const QString&, program), + Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName), Q_ARG(int, lineNumber)); return result; } + + // Check synthax + const QScriptProgram program(sourceCode, fileName, lineNumber); + if (!checkSynthax(program)) { + return QScriptValue(); + } - _evaluatesPending++; - QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); - if (hasUncaughtException()) { - int line = uncaughtExceptionLineNumber(); - qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); - } - _evaluatesPending--; + ++_evaluatesPending; + const auto result = QScriptEngine::evaluate(program); + --_evaluatesPending; + + const auto hadUncaughtException = checkExceptions(this, program.fileName()); if (_wantSignals) { - emit evaluationFinished(result, hasUncaughtException()); + emit evaluationFinished(result, hadUncaughtException); } - clearExceptions(); return result; } @@ -603,7 +606,7 @@ void ScriptEngine::run() { emit runningStateChanged(); } - QScriptValue result = evaluate(_scriptContents); + QScriptValue result = evaluate(_scriptContents, _fileNameString); QElapsedTimer startTime; startTime.start(); @@ -644,15 +647,6 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - if (hasUncaughtException()) { - int line = uncaughtExceptionLineNumber(); - qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); - if (_wantSignals) { - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); - } - clearExceptions(); - } - if (!_isFinished) { if (_wantSignals) { emit update(deltaTime); @@ -660,6 +654,7 @@ void ScriptEngine::run() { } lastUpdate = now; + checkExceptions(this, _fileNameString); } stopAllTimers(); // make sure all our timers are stopped if the script is ending @@ -896,6 +891,38 @@ void ScriptEngine::load(const QString& loadFile) { } } + +bool ScriptEngine::checkSynthax(const QScriptProgram& program) { + const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); + if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { + const auto error = syntaxCheck.errorMessage(); + const auto line = QString::number(syntaxCheck.errorLineNumber()); + const auto column = QString::number(syntaxCheck.errorColumnNumber()); + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); + qCWarning(scriptengine) << qPrintable(message); + return false; + } + return true; +} + +bool ScriptEngine::checkExceptions(QScriptEngine* engine, const QString& fileName) { + if (engine->hasUncaughtException()) { + const auto backtrace = engine->uncaughtExceptionBacktrace(); + const auto exception = engine->uncaughtException().toString(); + const auto line = QString::number(engine->uncaughtExceptionLineNumber()); + engine->clearExceptions(); + + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + qCWarning(scriptengine) << qPrintable(message); + return false; + } + return true; +} + // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { @@ -1015,7 +1042,8 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } - QScriptValue entityScriptConstructor = evaluate(contents); + auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); + QScriptValue entityScriptConstructor = evaluate(contents, fileName); QScriptValue entityScriptObject = entityScriptConstructor.construct(); EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; _entityScripts[entityID] = newDetails; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c2f9d966f1..8fda876a31 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -88,7 +88,7 @@ public: Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); /// evaluate some code in the context of the ScriptEngine and return the result - Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1); // this is also used by the script tool widget + Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget /// if the script engine is not already running, this will download the URL and start the process of seting it up /// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed @@ -182,6 +182,9 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); + static bool checkSynthax(const QScriptProgram& program); + static bool checkExceptions(QScriptEngine* engine, const QString& fileName); + AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; Quat _quatLibrary; diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 22ea12c1b3..cc3519e43e 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -135,7 +135,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont prefixString.append(QString(" [%1]").arg(_targetName)); } - QString logMessage = QString("%1 %2").arg(prefixString, message); + QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " ")); fprintf(stdout, "%s\n", qPrintable(logMessage)); return logMessage; } From c1cd7dd50a14723a580039ed1c2f3f0d91855273 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:31:38 -0700 Subject: [PATCH 020/171] Work on robot animation and bat hull --- examples/toys/baseball.js | 132 ++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index f3f26a1f4b..f356e35fdf 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; -var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } +var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d665a5de.fbx"; +var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; +var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" +var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; +var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; // add the fresh robot at home plate var robot = Entities.addEntity({ @@ -21,72 +24,117 @@ var robot = Entities.addEntity({ type: 'Model', modelURL: ROBOT_MODEL, position: ROBOT_POSITION, +// dimensions: ROBOT_DIMENSIONS,a + animationIsPlaying: true, animation: { - url: ROBOT_MODEL + url: ROBOT_MODEL, + fps: 30 } }); // add the bat var bat = Entities.addEntity({ - name: 'Bat', - type: 'Model', - modelURL: BAT_MODEL + name: 'Bat', + /*/ + type: 'Box', + /*/ + type: 'Model', + modelURL: BAT_COLLISION_MODEL, + /**/ + collisionModelURL: BAT_COLLISION_MODEL, +// dimensions: BAT_DIMENSIONS, + registrationPoint: BAT_REGISTRATION_POINT, + visible: false }) var lastTriggerValue = 0.0; function checkTriggers() { - var rightTrigger = Controller.getTriggerValue(1); + var rightTrigger = Controller.getTriggerValue(1); - if (rightTrigger == 0) { - if (lastTriggerValue > 0) { - // the trigger was just released, play out to the last frame of the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 21, - lastFrame: 115 + if (rightTrigger == 0) { + if (lastTriggerValue > 0) { + // the trigger was just released, play out to the last frame of the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 21, + lastFrame: 115 + } + }); } - }); - } - } else { - if (lastTriggerValue == 0) { - // the trigger was just depressed, start the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 0, - lastFrame: 21 + } else { + if (lastTriggerValue == 0) { + // the trigger was just depressed, start the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 0, + lastFrame: 21 + } + }); } - }); } - } - lastTriggerValue = rightTrigger; + lastTriggerValue = rightTrigger; } var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var ACTION_LIFETIME = 15; // seconds +var action = null; +var factor = 0.0; +var STEP = 0.05; function moveBat() { - var forearmPosition = Entities.getJointPosition(robot, 40); - var forearmRotation = Entities.getJointRotation(robot, 40); - - Vec3.print("forearmPosition=", forearmPosition); - - Entities.addAction("spring", bat, { - targetPosition: forearmPosition, - targetRotation: forearmRotation, - tag: "bat-to-forearm", - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - lifetime: ACTION_LIFETIME - }); + var JOINT_INDEX = 19; + + var forearmPosition = Entities.getJointPosition(robot, JOINT_INDEX); + var forearmRotation = Entities.getJointRotation(robot, JOINT_INDEX); + + /*/ + var properties = Entities.getEntityProperties(bat, ["position", "rotation"]); + var offsetPosition = Vec3.subtract(properties.position, forearmPosition); + var offsetRotation = Quat.multiply(Quat.inverse(forearmRotation), properties.rotation); + print("offsetPosition = " + JSON.stringify(offsetPosition)); + print("offsetRotation = " + JSON.stringify(Quat.safeEulerAngles(offsetRotation))); + /*/ + Entities.editEntity(bat, { + position: forearmPosition, + rotation: forearmRotation, + }); + /**/ + +// var actionProperties = { +// relativePosition: forearmPosition, +// relativeRotation: forearmRotation, +//// tag: "bat-to-forearm", +//// linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, +//// angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, +//// lifetime: ACTION_LIFETIME +// hand: "left", +// timeScale: 0.15 +// }; +// +// if (action === null) { +// Entities.addAction("hold", bat, actionProperties); +// } else { +// Entities.editAction(bat, action, actionProperties); +// } } function update() { - checkTriggers(); +// checkTriggers(); + moveBat(); +} + +function scriptEnding() { + Entities.deleteEntity(robot); + Entities.deleteEntity(bat); + if (action) { + Entities.deleteAction(bat, action); + } } // hook the update so we can check controller triggers Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); From 7487c7bd0a8bddbec0b4dad38ebd22e78afc2d8d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:32:27 -0700 Subject: [PATCH 021/171] Move baseball.js --- examples/{toys => baseball}/baseball.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{toys => baseball}/baseball.js (100%) diff --git a/examples/toys/baseball.js b/examples/baseball/baseball.js similarity index 100% rename from examples/toys/baseball.js rename to examples/baseball/baseball.js From 667eec2f46dca9cc3990554dfad55d78aa46fac3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:43:59 -0700 Subject: [PATCH 022/171] change collision hull --- examples/baseball/baseball.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js index f356e35fdf..504d067885 100755 --- a/examples/baseball/baseball.js +++ b/examples/baseball/baseball.js @@ -14,7 +14,7 @@ var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" -var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" +var BAT_COLLISION_MODEL = "atp:atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; From 97713618409d48a4084f7de2a6eb1c0931b2db0c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 10:49:41 -0700 Subject: [PATCH 023/171] Typo --- libraries/script-engine/src/ScriptEngine.cpp | 6 +++--- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cbe9449551..2c725bdf70 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -575,9 +575,9 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi return result; } - // Check synthax + // Check syntax const QScriptProgram program(sourceCode, fileName, lineNumber); - if (!checkSynthax(program)) { + if (!checkSyntax(program)) { return QScriptValue(); } @@ -892,7 +892,7 @@ void ScriptEngine::load(const QString& loadFile) { } -bool ScriptEngine::checkSynthax(const QScriptProgram& program) { +bool ScriptEngine::checkSyntax(const QScriptProgram& program) { const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { const auto error = syntaxCheck.errorMessage(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8fda876a31..db10ecef40 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -182,7 +182,7 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - static bool checkSynthax(const QScriptProgram& program); + static bool checkSyntax(const QScriptProgram& program); static bool checkExceptions(QScriptEngine* engine, const QString& fileName); AbstractControllerScriptingInterface* _controllerScriptingInterface; From 8d72fcada5a712a0518fcf1063686dc3157d3812 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 11:33:13 -0700 Subject: [PATCH 024/171] Some more script checks --- libraries/script-engine/src/ScriptEngine.cpp | 26 +++++++------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2c725bdf70..0411c507ab 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -79,7 +79,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { return engine->newQObject(in); } - void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) { out = qobject_cast(object.toQObject()); } @@ -95,9 +94,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _wantSignals(wantSignals), _controllerScriptingInterface(controllerScriptingInterface), _fileNameString(fileNameString), - _quatLibrary(), - _vec3Library(), - _uuidLibrary(), _isUserLoaded(false), _isReloading(false), _arrayBufferClass(new ArrayBufferClass(this)) @@ -654,7 +650,9 @@ void ScriptEngine::run() { } lastUpdate = now; - checkExceptions(this, _fileNameString); + if (!checkExceptions(this, _fileNameString)) { + stop(); + } } stopAllTimers(); // make sure all our timers are stopped if the script is ending @@ -891,7 +889,6 @@ void ScriptEngine::load(const QString& loadFile) { } } - bool ScriptEngine::checkSyntax(const QScriptProgram& program) { const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { @@ -1005,14 +1002,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co auto scriptCache = DependencyManager::get(); bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); + auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); - // first check the syntax of the script contents - QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents); - if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { - qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID; - qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":" - << syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber(); - qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL; + QScriptProgram program(contents, fileName); + if (!checkSyntax(program)) { if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } @@ -1027,9 +1020,9 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co QScriptValue testConstructor = sandbox.evaluate(contents); if (!testConstructor.isFunction()) { - qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID; - qCDebug(scriptengine) << " NOT CONSTRUCTOR"; - qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL; + qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" + " NOT CONSTRUCTOR\n" + " SCRIPT:" << scriptOrURL; if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } @@ -1042,7 +1035,6 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } - auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); QScriptValue entityScriptConstructor = evaluate(contents, fileName); QScriptValue entityScriptObject = entityScriptConstructor.construct(); EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; From 1e4a414f9df210ffc32b022c132cc49f39ac4127 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 11:33:36 -0700 Subject: [PATCH 025/171] Fix scripts syntax errors --- examples/libraries/entityCameraTool.js | 10 +++++----- examples/libraries/soundArray.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index d304a6382e..88e01b29fe 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -564,12 +564,12 @@ CameraTool = function(cameraManager) { var ORIENTATION_OVERLAY_SIZE = 26; var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2; - var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5, + var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5; - var ORIENTATION_OVERLAY_OFFSET = { - x: 30, - y: 30, - } + var ORIENTATION_OVERLAY_OFFSET = { + x: 30, + y: 30, + } var UI_WIDTH = 70; var UI_HEIGHT = 70; diff --git a/examples/libraries/soundArray.js b/examples/libraries/soundArray.js index 813621fb4b..f59c88a723 100644 --- a/examples/libraries/soundArray.js +++ b/examples/libraries/soundArray.js @@ -6,7 +6,7 @@ SoundArray = function(audioOptions, autoUpdateAudioPosition) { this.audioOptions = audioOptions !== undefined ? audioOptions : {}; this.autoUpdateAudioPosition = autoUpdateAudioPosition !== undefined ? autoUpdateAudioPosition : false; if (this.audioOptions.position === undefined) { - this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0}), + this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0}); } if (this.audioOptions.volume === undefined) { this.audioOptions.volume = 1.0; From e8c6acfeb68ab2e062c3a5de39bc6a4a7af7789e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 11:58:49 -0700 Subject: [PATCH 026/171] update baseball crowd to loop better --- examples/acScripts/baseballCrowd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 5007c64b16..d892fe5c71 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var crowd1 = SoundCache.getSound("atp:0e921b644464d56d5b412ea2ea1d83f8ff3f7506c4b0471ea336a4770daf3b82.wav"); +var crowd1 = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); function maybePlaySound(deltaTime) { if (crowd1.downloaded && !crowd1.isPlaying) { - Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true}); + Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); Script.update.disconnect(maybePlaySound); } } From ca60ce59f1f9194a23f569e82ea4df4c1be66b01 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:06:25 -0700 Subject: [PATCH 027/171] put Agent AssetClient on sep thread, cleanup --- assignment-client/src/Agent.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index fb9b2a94a0..b5162c7478 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -44,7 +44,14 @@ Agent::Agent(NLPacket& packet) : { DependencyManager::get()->setPacketSender(&_entityEditSender); - DependencyManager::set(); + auto assetClient = DependencyManager::set(); + + QThread* assetThread = new QThread; + assetThread->setObjectName("Asset Thread"); + assetClient->moveToThread(assetThread); + connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); + assetThread->start(); + DependencyManager::set(); DependencyManager::set(); @@ -368,6 +375,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending billboards and identity packets + if (_scriptEngine) { _scriptEngine->stop(); } @@ -379,6 +387,12 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(NULL); + + // cleanup the AssetClient thread + QThread* assetThread = DependencyManager::get()->thread(); + DependencyManager::destroy(); + assetThread->quit(); + assetThread->wait(); } void Agent::sendPingRequests() { From 61ad91aba66d5f04f6781804c4d4bf3fb3f87a97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:09:48 -0700 Subject: [PATCH 028/171] hook Sound downloaded to start playback --- examples/acScripts/baseballCrowd.js | 11 +++++------ libraries/audio/src/Sound.cpp | 1 + libraries/audio/src/Sound.h | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index d892fe5c71..c61bbc4a9a 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -9,13 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var crowd1 = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); +var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); -function maybePlaySound(deltaTime) { - if (crowd1.downloaded && !crowd1.isPlaying) { - Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); - Script.update.disconnect(maybePlaySound); +function playChatter() { + if (chatter.downloaded && !chatter.isPlaying) { + Audio.playSound(chatter, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); } } -Script.update.connect(maybePlaySound); +chatter.downloaded.connect(playChatter); diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 2457bda74a..4c8976a6d6 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -95,6 +95,7 @@ void Sound::downloadFinished(const QByteArray& data) { } _isReady = true; + emit downloaded(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 842c395a7d..43c05ed4a5 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -29,6 +29,9 @@ public: bool isReady() const { return _isReady; } const QByteArray& getByteArray() { return _byteArray; } + +signals: + void downloaded(); private: QByteArray _byteArray; From a4ddb7a1e4e05e35fcb9cf90ee3dfd9d6abbfe02 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:14:12 -0700 Subject: [PATCH 029/171] change downloaded to ready to avoid collision --- libraries/audio/src/Sound.cpp | 2 +- libraries/audio/src/Sound.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 4c8976a6d6..d20de2ba48 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -95,7 +95,7 @@ void Sound::downloadFinished(const QByteArray& data) { } _isReady = true; - emit downloaded(); + emit ready(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 43c05ed4a5..bcac999ee8 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -31,7 +31,7 @@ public: const QByteArray& getByteArray() { return _byteArray; } signals: - void downloaded(); + void ready(); private: QByteArray _byteArray; From 47e8a1bdf7a50b7a8d9486d6408f4c6610ac8002 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:15:08 -0700 Subject: [PATCH 030/171] connect to correct signal for sound ready --- examples/acScripts/baseballCrowd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index c61bbc4a9a..1f82b65f54 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,4 +17,4 @@ function playChatter() { } } -chatter.downloaded.connect(playChatter); +chatter.ready.connect(playChatter); From 1c048880ee2d3f33f38c20defc74dedf80f1cba5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 12:27:48 -0700 Subject: [PATCH 031/171] Lambda conversion fix for windows --- libraries/script-engine/src/ScriptEngine.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0411c507ab..bcfeef1acb 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -509,18 +509,22 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& }); // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [&](QString eventName) { + using SingleEntityHandler = std::function; + auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { return [this, eventName](const EntityItemID& entityItemID) { forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [&](QString eventName) { + + using MouseHandler = std::function; + auto makeMouseHandler = [this](QString eventName) -> MouseHandler { return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; - auto makeCollisionHandler = [&](QString eventName) { + using CollisionHandler = std::function; + auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), collisionToScriptValue(this, collision) }); From 380139364c4b2e0f74c6881f5cc809094d504c0a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 12:33:42 -0700 Subject: [PATCH 032/171] checkExceptions after testing entity scripts in the sandbox --- libraries/script-engine/src/ScriptEngine.cpp | 23 +++++++++++--------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index bcfeef1acb..986613c20b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -585,7 +585,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi const auto result = QScriptEngine::evaluate(program); --_evaluatesPending; - const auto hadUncaughtException = checkExceptions(this, program.fileName()); + const auto hadUncaughtException = checkExceptions(*this, program.fileName()); if (_wantSignals) { emit evaluationFinished(result, hadUncaughtException); } @@ -654,7 +654,7 @@ void ScriptEngine::run() { } lastUpdate = now; - if (!checkExceptions(this, _fileNameString)) { + if (!checkExceptions(*this, _fileNameString)) { stop(); } } @@ -906,12 +906,12 @@ bool ScriptEngine::checkSyntax(const QScriptProgram& program) { return true; } -bool ScriptEngine::checkExceptions(QScriptEngine* engine, const QString& fileName) { - if (engine->hasUncaughtException()) { - const auto backtrace = engine->uncaughtExceptionBacktrace(); - const auto exception = engine->uncaughtException().toString(); - const auto line = QString::number(engine->uncaughtExceptionLineNumber()); - engine->clearExceptions(); +bool ScriptEngine::checkExceptions(QScriptEngine& engine, const QString& fileName) { + if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); if (!backtrace.empty()) { @@ -1021,8 +1021,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } QScriptEngine sandbox; - QScriptValue testConstructor = sandbox.evaluate(contents); - + QScriptValue testConstructor = sandbox.evaluate(program); + if (!checkExceptions(sandbox, program.fileName())) { + return; + } + if (!testConstructor.isFunction()) { qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" " NOT CONSTRUCTOR\n" diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index db10ecef40..ddd957e163 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -183,7 +183,7 @@ private: void stopTimer(QTimer* timer); static bool checkSyntax(const QScriptProgram& program); - static bool checkExceptions(QScriptEngine* engine, const QString& fileName); + static bool checkExceptions(QScriptEngine& engine, const QString& fileName); AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; From 6080654d7e93cb9c034eeab14d77e6bb715548a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 15:48:02 -0700 Subject: [PATCH 033/171] zero out the pre-mix samples for each stream --- assignment-client/src/audio/AudioMixer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1d8908845f..ea980075c3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -437,7 +437,6 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); // zero out the client mix for this node - memset(_preMixSamples, 0, sizeof(_preMixSamples)); memset(_mixSamples, 0, sizeof(_mixSamples)); // loop through all other nodes that have sufficient audio to mix @@ -458,6 +457,9 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { if (otherNodeStream->getType() == PositionalAudioStream::Microphone) { streamUUID = otherNode->getUUID(); } + + // clear out the pre-mix samples before filling it up with this source + memset(_preMixSamples, 0, sizeof(_preMixSamples)); if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) { streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID, From f275d2678d9214ca340a0e7490221b728e2816bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 16:06:12 -0700 Subject: [PATCH 034/171] ping the AssetClient from the agent --- assignment-client/src/Agent.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index b5162c7478..88f5aafccd 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -43,20 +43,20 @@ Agent::Agent(NLPacket& packet) : DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)) { DependencyManager::get()->setPacketSender(&_entityEditSender); - + auto assetClient = DependencyManager::set(); - + QThread* assetThread = new QThread; assetThread->setObjectName("Asset Thread"); assetClient->moveToThread(assetThread); connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); assetThread->start(); - + DependencyManager::set(); DependencyManager::set(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - + packetReceiver.registerListenerForTypes( { PacketType::MixedAudio, PacketType::SilentAudioFrame }, this, "handleAudioPacket"); @@ -75,7 +75,7 @@ void Agent::handleOctreePacket(QSharedPointer packet, SharedNodePointe if (packet->getPayloadSize() > statsMessageLength) { // pull out the piggybacked packet and create a new QSharedPointer for it int piggyBackedSizeWithHeader = packet->getPayloadSize() - statsMessageLength; - + auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggyBackedSizeWithHeader); @@ -102,7 +102,7 @@ void Agent::handleJurisdictionPacket(QSharedPointer packet, SharedNode DependencyManager::get()->getJurisdictionListener()-> queueReceivedPacket(packet, senderNode); } -} +} void Agent::handleAudioPacket(QSharedPointer packet) { _receivedAudioStream.parseData(*packet); @@ -176,7 +176,7 @@ void Agent::run() { // give this AvatarData object to the script engine setAvatarData(&scriptedAvatar, "Avatar"); - + auto avatarHashMap = DependencyManager::set(); _scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); @@ -189,7 +189,7 @@ void Agent::run() { // register ourselves to the script engine _scriptEngine->registerGlobalObject("Agent", this); - // FIXME -we shouldn't be calling this directly, it's normally called by run(), not sure why + // FIXME -we shouldn't be calling this directly, it's normally called by run(), not sure why // viewers would need this called. //_scriptEngine->init(); // must be done before we set up the viewers @@ -201,14 +201,14 @@ void Agent::run() { auto entityScriptingInterface = DependencyManager::get(); _scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); - + // we need to make sure that init has been called for our EntityScriptingInterface // so that it actually has a jurisdiction listener when we ask it for it next entityScriptingInterface->init(); _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); - + _entityViewer.init(); - + entityScriptingInterface->setEntityTree(_entityViewer.getTree()); // wire up our additional agent related processing to the update signal @@ -241,7 +241,7 @@ void Agent::setIsAvatar(bool isAvatar) { delete _avatarIdentityTimer; _avatarIdentityTimer = nullptr; } - + if (_avatarBillboardTimer) { _avatarBillboardTimer->stop(); delete _avatarBillboardTimer; @@ -375,7 +375,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending billboards and identity packets - + if (_scriptEngine) { _scriptEngine->stop(); } @@ -387,7 +387,7 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(NULL); - + // cleanup the AssetClient thread QThread* assetThread = DependencyManager::get()->thread(); DependencyManager::destroy(); @@ -403,6 +403,7 @@ void Agent::sendPingRequests() { case NodeType::AvatarMixer: case NodeType::AudioMixer: case NodeType::EntityServer: + case NodeType::AssetClient: return true; default: return false; From 5f8c3a6b4b35bdd363a34cc930bc4caeff8b723a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 27 Oct 2015 10:27:37 -0700 Subject: [PATCH 035/171] Fix AssetResourceRequest crash --- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index eba9e45e5c..dac3329153 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -46,7 +46,7 @@ void AssetResourceRequest::doSend() { } connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress); - connect(_assetRequest, &AssetRequest::finished, [this](AssetRequest* req) { + connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) { Q_ASSERT(_state == InProgress); Q_ASSERT(req == _assetRequest); Q_ASSERT(req->getState() == AssetRequest::Finished); From 3fa4f7138af635b1276fb363d339a50129176f0b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 27 Oct 2015 10:58:31 -0700 Subject: [PATCH 036/171] add more sounds to the crowd, ping AssetServer from Agent --- assignment-client/src/Agent.cpp | 2 +- examples/acScripts/baseballCrowd.js | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 88f5aafccd..668a9228ed 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -403,7 +403,7 @@ void Agent::sendPingRequests() { case NodeType::AvatarMixer: case NodeType::AudioMixer: case NodeType::EntityServer: - case NodeType::AssetClient: + case NodeType::AssetServer: return true; default: return false; diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 1f82b65f54..b0038d5865 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -10,11 +10,31 @@ // var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); +var extras = [ + SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba + SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge + SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game + SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping +]; function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { - Audio.playSound(chatter, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); + Audio.playSound(chatter, { loop: true, volume: 0.5 }); } } chatter.ready.connect(playChatter); + +var currentInjector = null; + +function playRandomExtras() { + if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) { + // play a random extra sound about every 30s + currentInjector = Audio.playSound( + extras[Math.floor(Math.random() * extras.length)], + { volume: 0.33 } + ); + } +} + +Script.update.connect(playRandomExtras); From 7e8aec9db90da9da07904a6a4468a14f0e10e6aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 27 Oct 2015 11:48:52 -0700 Subject: [PATCH 037/171] fix double URL scheme --- examples/baseball/baseball.js | 126 +++++----------------------------- 1 file changed, 16 insertions(+), 110 deletions(-) diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js index 504d067885..71f3f2c049 100755 --- a/examples/baseball/baseball.js +++ b/examples/baseball/baseball.js @@ -13,128 +13,34 @@ var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; -var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" -var BAT_COLLISION_MODEL = "atp:atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" -var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; -var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; +var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx" +var BAT_COLLISION_MODEL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" // add the fresh robot at home plate -var robot = Entities.addEntity({ - name: 'Robot', - type: 'Model', - modelURL: ROBOT_MODEL, - position: ROBOT_POSITION, -// dimensions: ROBOT_DIMENSIONS,a - animationIsPlaying: true, - animation: { - url: ROBOT_MODEL, - fps: 30 - } -}); +// var robot = Entities.addEntity({ +// name: 'Robot', +// type: 'Model', +// modelURL: ROBOT_MODEL, +// position: ROBOT_POSITION, +// // dimensions: ROBOT_DIMENSIONS, +// animationIsPlaying: true, +// animation: { +// url: ROBOT_MODEL, +// fps: 30 +// } +// }); // add the bat var bat = Entities.addEntity({ name: 'Bat', - /*/ - type: 'Box', - /*/ type: 'Model', - modelURL: BAT_COLLISION_MODEL, - /**/ + modelURL: BAT_MODEL, collisionModelURL: BAT_COLLISION_MODEL, -// dimensions: BAT_DIMENSIONS, - registrationPoint: BAT_REGISTRATION_POINT, - visible: false + userData: "{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":10,"y":0,"z":0}},"kinematicGrab":true}}" }) -var lastTriggerValue = 0.0; - -function checkTriggers() { - var rightTrigger = Controller.getTriggerValue(1); - - if (rightTrigger == 0) { - if (lastTriggerValue > 0) { - // the trigger was just released, play out to the last frame of the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 21, - lastFrame: 115 - } - }); - } - } else { - if (lastTriggerValue == 0) { - // the trigger was just depressed, start the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 0, - lastFrame: 21 - } - }); - } - } - - lastTriggerValue = rightTrigger; -} - -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var ACTION_LIFETIME = 15; // seconds - -var action = null; -var factor = 0.0; -var STEP = 0.05; -function moveBat() { - var JOINT_INDEX = 19; - - var forearmPosition = Entities.getJointPosition(robot, JOINT_INDEX); - var forearmRotation = Entities.getJointRotation(robot, JOINT_INDEX); - - /*/ - var properties = Entities.getEntityProperties(bat, ["position", "rotation"]); - var offsetPosition = Vec3.subtract(properties.position, forearmPosition); - var offsetRotation = Quat.multiply(Quat.inverse(forearmRotation), properties.rotation); - print("offsetPosition = " + JSON.stringify(offsetPosition)); - print("offsetRotation = " + JSON.stringify(Quat.safeEulerAngles(offsetRotation))); - /*/ - Entities.editEntity(bat, { - position: forearmPosition, - rotation: forearmRotation, - }); - /**/ - -// var actionProperties = { -// relativePosition: forearmPosition, -// relativeRotation: forearmRotation, -//// tag: "bat-to-forearm", -//// linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, -//// angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, -//// lifetime: ACTION_LIFETIME -// hand: "left", -// timeScale: 0.15 -// }; -// -// if (action === null) { -// Entities.addAction("hold", bat, actionProperties); -// } else { -// Entities.editAction(bat, action, actionProperties); -// } -} - -function update() { -// checkTriggers(); - moveBat(); -} - function scriptEnding() { - Entities.deleteEntity(robot); Entities.deleteEntity(bat); - if (action) { - Entities.deleteAction(bat, action); - } } -// hook the update so we can check controller triggers -Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); From c9f49ca992227fef4ea3b42bb0cb02a5c97330f9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 27 Oct 2015 11:53:46 -0700 Subject: [PATCH 038/171] Remove baseball script --- examples/baseball/baseball.js | 46 ----------------------------------- 1 file changed, 46 deletions(-) delete mode 100755 examples/baseball/baseball.js diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js deleted file mode 100755 index 71f3f2c049..0000000000 --- a/examples/baseball/baseball.js +++ /dev/null @@ -1,46 +0,0 @@ -// -// baseball.js -// examples/toys -// -// Created by Stephen Birarda on 10/20/15. -// 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 -// - -var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d665a5de.fbx"; -var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; -var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; - -var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx" -var BAT_COLLISION_MODEL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" - -// add the fresh robot at home plate -// var robot = Entities.addEntity({ -// name: 'Robot', -// type: 'Model', -// modelURL: ROBOT_MODEL, -// position: ROBOT_POSITION, -// // dimensions: ROBOT_DIMENSIONS, -// animationIsPlaying: true, -// animation: { -// url: ROBOT_MODEL, -// fps: 30 -// } -// }); - -// add the bat -var bat = Entities.addEntity({ - name: 'Bat', - type: 'Model', - modelURL: BAT_MODEL, - collisionModelURL: BAT_COLLISION_MODEL, - userData: "{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":10,"y":0,"z":0}},"kinematicGrab":true}}" -}) - -function scriptEnding() { - Entities.deleteEntity(bat); -} - -Script.scriptEnding.connect(scriptEnding); From b46d42889d2f418fa140cae6cbd9e31b47eaabc2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Oct 2015 13:25:43 -0700 Subject: [PATCH 039/171] Add foul and strike audio to baseball game --- examples/baseball/pitching.js | 104 +++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 1f8df39a7b..6f7d8e686a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -14,6 +14,15 @@ var AUDIO = { SoundCache.getSound("atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", false), SoundCache.getSound("atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", false), SoundCache.getSound("atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", false), + ], + strike: [ + SoundCache.getSound("atp:2a258076a85fffde4ba04b5ddc1de9034c7ae7d2af8c5d93d4fed0bcdef3472a.wav", false), + SoundCache.getSound("atp:518363524af3ed9b9ae4ca2ceee61f01aecd37e266a51c5a5f5487efe2520fd5.wav", false), + SoundCache.getSound("atp:d51d38b089574acbdfdf53ef733bfb3ab41d848fb8c0b6659c7790a785240009.wav", false), + ], + foul: [ + SoundCache.getSound("atp:316fa18ff9eef457f670452b449a8dc5a41ccabd4e948781c50aaafaae63b0ab.wav", false), + SoundCache.getSound("atp:c84d88352d38437edd7414b26dc74e567618712caeb59fec70822398b0c5a279.wav", false), ] } @@ -105,6 +114,12 @@ var BASEBALL_PROPERTIES = { z: 0 } }; +var BASEBALL_STATE = { + PITCHING: 0, + HIT: 1, + STRIKE: 2, + FOUL: 3 +}; var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); @@ -159,10 +174,10 @@ function orientationOf(vector) { var Y_AXIS = { x: 0, y: 1, z: 0 }; var X_AXIS = { x: 1, y: 0, z: 0 }; var direction = Vec3.normalize(vector); - + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); var pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); - + return Quat.multiply(yaw, pitch); } @@ -176,7 +191,7 @@ function cleanupTrail() { if (trail) { Script.clearInterval(this.trailInterval); trailInterval = null; - + trail.destroy(); trail = null; } @@ -184,7 +199,7 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); - + var lastPosition = position; trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); trailInterval = Script.setInterval(function() { @@ -199,7 +214,9 @@ function setupTrail(entityID, position) { function Baseball(position, velocity, ballScale) { var self = this; - // Setup entity properties + this.state = BASEBALL_STATE.PITCHING; + + // Setup entity properties var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; @@ -211,7 +228,7 @@ function Baseball(position, velocity, ballScale) { z: 0.0, }; */ - + // Create entity this.entityID = Entities.addEntity(properties); @@ -242,7 +259,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var myPosition = myProperties.position; var myVelocity = myProperties.velocity; - + // Activate gravity Entities.editEntity(self.entityID, { gravity: { x: 0, y: -9.8, z: 0 } @@ -251,35 +268,57 @@ Baseball.prototype = { var name = Entities.getEntityProperties(entityB, ["name"]).name; print("Hit: " + name); if (name == "Bat") { - print("HIT"); - - // Update ball velocity - Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, myVelocity), - }); - - // Setup line update interval - setupTrail(self.entityID, myPosition); - - // Setup bat hit sound - playRandomSound(AUDIO.batHit, { - position: myPosition, - volume: 2.0 - }); - - // Setup crowd reaction sound - var speed = Vec3.length(myVelocity); - Script.setTimeout(function() { - playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { - position: { x: 0 ,y: 0, z: 0 }, - volume: 1.0 + if (this.state == BASEBALL_STATE.PITCHING) { + print("HIT"); + + // Update ball velocity + Entities.editEntity(self.entityID, { + velocity: Vec3.multiply(2, myVelocity), }); - }, 500); + + // Setup line update interval + setupTrail(self.entityID, myPosition); + + // Setup bat hit sound + playRandomSound(AUDIO.batHit, { + position: myPosition, + volume: 2.0 + }); + + // Setup crowd reaction sound + var speed = Vec3.length(myVelocity); + Script.setTimeout(function() { + playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0 + }); + }, 500); + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + var foul = yaw > -135 && yaw < 135; + if (foul) { + print("FOUL ", yaw) + this.state = BASEBALL_STATE.FOUL; + playRandomSound(AUDIO.foul, { + position: myPosition, + volume: 2.0 + }); + } else { + print("HIT ", yaw); + this.state = BASEBALL_STATE.HIT; + } + } } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); } else if (name == "backstop") { - print("STRIKE"); + if (this.state == BASEBALL_STATE.PITCHING) { + this.state = BASEBALL_STATE.STRIKE; + print("STRIKE"); + playRandomSound(AUDIO.strike, { + position: myPosition, + volume: 2.0 + }); + } } } } @@ -317,7 +356,7 @@ function entityCollisionWithGround(ground, entity, collision) { var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); var displayTime = 400; var orientationChange = orientationOf(collision.velocityChange); - + var dustEffect = Entities.addEntity({ type: "ParticleEffect", name: "Dust-Puff", @@ -349,4 +388,3 @@ Script.scriptEnding.connect(function() { }); Script.setInterval(pitchBall, PITCH_RATE); - From e9a2e9137435d137bab2a1c928b56e05ceb0ff27 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Oct 2015 15:35:30 -0700 Subject: [PATCH 040/171] Add tunneling handling to pitching.js --- examples/baseball/pitching.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 6f7d8e686a..4e40b0aca8 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -270,6 +270,18 @@ Baseball.prototype = { if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + var foul = yaw > -135 && yaw < 135; + + if (foul && myVelocity.z > 0) { + var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); + var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; + print("Pitch: ", pitch); + if (Math.abs(pitch) < 15) { + print("Reversing hit"); + myVelocity.z *= -1; + } + } // Update ball velocity Entities.editEntity(self.entityID, { @@ -293,8 +305,6 @@ Baseball.prototype = { volume: 1.0 }); }, 500); - var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; - var foul = yaw > -135 && yaw < 135; if (foul) { print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; From 2ecec2623c143b651dd26cbb0c803b92996df0fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 28 Oct 2015 17:03:25 -0700 Subject: [PATCH 041/171] add a script for bat creation on button click --- examples/baseball/createBatButton.js | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 examples/baseball/createBatButton.js diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js new file mode 100644 index 0000000000..0ffc9cb829 --- /dev/null +++ b/examples/baseball/createBatButton.js @@ -0,0 +1,61 @@ +// +// createBatButton.js +// examples/baseball/moreBatsButton.js +// +// Created by Stephen Birarda on 10/28/2015. +// 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 +// + +(function(){ + this.clickReleaseOnEntity = function(entityID, mouseEvent) { + if (!mouseEvent.isLeftButton) { + return; + } + this.dropBats(); + }; + this.startNearGrabNonColliding = function() { + this.dropBats(); + }; + this.dropBats = function() { + // if the bat box is near us, grab it's position + var nearby = Entities.findEntities(this.position, 20); + + nearby.forEach(function(id) { + var properties = Entities.getEntityProperties(id, ["name", "position"]); + if (properties.name && properties.name == "Bat Box") { + boxPosition = properties.position; + } + }); + + var BAT_DROP_HEIGHT = 2.0; + + var dropPosition; + + if (!boxPosition) { + // we got no bat box position, drop in front of the avatar instead + } else { + // drop the bat above the bat box + dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); + } + + var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; + var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + + // add the fresh bat at the drop position + var bat = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: dropPosition, + compoundShapeURL: BAT_COLLISION_HULL, + collisionsWillMove: true, + velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add + gravity: { x: 0, y: -9.81, z: 0}, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), + userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":0,"y":0,"z":0.4617486000061035,"w":0.8870108127593994}},"kinematicGrab":true}}' + }); + } +}) From a7517ff21049ed0b0c2297a16b80b03483de84d0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 14:01:53 -0700 Subject: [PATCH 042/171] CP --- examples/baseball/pitching.js | 55 ++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 4e40b0aca8..a609476bef 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -117,8 +117,9 @@ var BASEBALL_PROPERTIES = { var BASEBALL_STATE = { PITCHING: 0, HIT: 1, - STRIKE: 2, - FOUL: 3 + HIT_LANDED: 2, + STRIKE: 3, + FOUL: 4 }; @@ -232,6 +233,11 @@ function Baseball(position, velocity, ballScale) { // Create entity this.entityID = Entities.addEntity(properties); + this.timeSincePitched = 0; + this.timeSinceHit = 0; + this.hitBallAtPosition = null; + this.distanceTravelled = 0; + // Listen for collision for the lifetime of the entity Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { self.collisionCallback(entityA, entityB, collision); @@ -254,6 +260,31 @@ function Baseball(position, velocity, ballScale) { } Baseball.prototype = { + finished: function() { + return this.state == BASEBALL_STATE.FOUL + || this.state == BASEBALL_STATE.STRIKE + || this.state == BASEBALL_STATE.HIT_LANDED; + }, + update: function(dt) { + this.timeSincePitched += dt; + if (this.state == BASEBALL_STATE.HIT) { + this.timeSinceHit += dt; + var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + var speed = Vec3.length(myProperties.velocity); + this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); + if (this.timeSinceHit > 10 || speed < 1) { + this.state = BASEBALL_STATE.HIT_LANDED; + print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); + print("Ball travelled " + this.distanceTravelled + " meters") + } + } else if (this.state == BASEBALL_STATE.PITCHING) { + if (this.timeSincePitched > 10) { + print("TIMED OUT WHILE PITCHING"); + this.state = BASEBALL_STATE.STRIKE; + + } + } + }, collisionCallback: function(entityA, entityB, collision) { var self = this; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); @@ -280,6 +311,7 @@ Baseball.prototype = { if (Math.abs(pitch) < 15) { print("Reversing hit"); myVelocity.z *= -1; + foul = false; } } @@ -333,6 +365,8 @@ Baseball.prototype = { } } +var baseball = null; + function pitchBall() { var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; @@ -346,7 +380,7 @@ function pitchBall() { var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; - var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); + baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); if (!injector) { injector = Audio.playSound(pitchSound, { @@ -358,6 +392,17 @@ function pitchBall() { } } +function update(dt) { + if (baseball) { + baseball.update(dt); + if (baseball.finished()) { + print("BALL IS FINSIEHD"); + baseball = null; + pitchBall(); + } + } +} + function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -397,4 +442,6 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -Script.setInterval(pitchBall, PITCH_RATE); +//Script.setInterval(pitchBall, PITCH_RATE); +Script.update.connect(update); +pitchBall(); From 8a29f4fc615d57b228b38ffdefa7d81162f56bf8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 14:47:34 -0700 Subject: [PATCH 043/171] Add distances and billboard display to pitching.js --- examples/baseball/pitching.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index a609476bef..eea7c391c6 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,5 +1,7 @@ Script.include("line.js"); +var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; + var AUDIO = { crowdBoos: [ SoundCache.getSound("atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", false) @@ -106,6 +108,7 @@ var BASEBALL_PROPERTIES = { damping: 0.0, restitution: 0.5, friction: 0.0, + friction: 0.5, lifetime: 20, //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { @@ -259,6 +262,12 @@ function Baseball(position, velocity, ballScale) { */ } +function updateBillboard(value) { + Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { + text: value, + }); +} + Baseball.prototype = { finished: function() { return this.state == BASEBALL_STATE.FOUL @@ -272,6 +281,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); + updateBillboard(Math.ceil(this.distanceTravelled)); if (this.timeSinceHit > 10 || speed < 1) { this.state = BASEBALL_STATE.HIT_LANDED; print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); @@ -338,6 +348,7 @@ Baseball.prototype = { }); }, 500); if (foul) { + updateBillboard("FOUL!"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -352,9 +363,13 @@ Baseball.prototype = { } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); + if (this.state == BASEBALL_STATE.HIT) { + this.state = BASEBALL_STATE.HIT_LANDED; + } } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; + updateBillboard("STRIKE!"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, @@ -368,6 +383,7 @@ Baseball.prototype = { var baseball = null; function pitchBall() { + updateBillboard(""); var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -398,7 +414,7 @@ function update(dt) { if (baseball.finished()) { print("BALL IS FINSIEHD"); baseball = null; - pitchBall(); + Script.setTimeout(pitchBall, 3000); } } } From 03a082383fb380f7fd5b760a8486567c3e8572bd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 16:10:17 -0700 Subject: [PATCH 044/171] Convert billboard display to feet and cleanup trails earlier --- examples/baseball/pitching.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index eea7c391c6..6ec4d2df85 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,7 @@ Script.include("line.js"); var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var METERS_TO_FEET = 3.28084; var AUDIO = { crowdBoos: [ @@ -163,9 +164,9 @@ function playRandomSound(sounds, options) { function vec3Mult(a, b) { return { - x: a.x * b.x, - y: a.y * b.y, - z: a.z * b.z, + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, }; } @@ -281,7 +282,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); - updateBillboard(Math.ceil(this.distanceTravelled)); + updateBillboard(Math.ceil(this.distanceTravelled * METERS_TO_FEET)); if (this.timeSinceHit > 10 || speed < 1) { this.state = BASEBALL_STATE.HIT_LANDED; print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); @@ -383,6 +384,7 @@ Baseball.prototype = { var baseball = null; function pitchBall() { + cleanupTrail(); updateBillboard(""); var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; From f4bbf8db60d399f5967a2e91ea3f2ef1cffe1bdb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 Oct 2015 16:42:48 -0700 Subject: [PATCH 045/171] Check keyLight is defined --- examples/edit.js | 4 ++-- examples/html/entityProperties.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 447455e999..7a16030afc 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1510,7 +1510,7 @@ PropertiesTool = function(opts) { if (entity.properties.rotation !== undefined) { entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation); } - if (entity.properties.type === "Zone" && entity.properties.keyLight.direction !== undefined) { + if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) { entity.properties.keyLight.direction = Vec3.multiply(RADIANS_TO_DEGREES, Vec3.toPolar(entity.properties.keyLight.direction)); entity.properties.keyLight.direction.z = 0.0; } @@ -1541,7 +1541,7 @@ PropertiesTool = function(opts) { var rotation = data.properties.rotation; data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z); } - if (entity.properties.type === "Zone" && data.properties.keyLight.direction !== undefined) { + if (data.properties.keyLight !== undefined && data.properties.keyLight.direction !== undefined) { data.properties.keyLight.direction = Vec3.fromPolar( data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS); } diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index fe40311b5f..412b413b2b 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -830,7 +830,7 @@ elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction); - elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('intensity','keyLight')); + elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','intensity')); elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','ambientIntensity')); var zoneKeyLightDirectionChangeFunction = createEmitGroupVec3PropertyUpdateFunction('keyLight','direction', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ); elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); From d2c17bfdd483371062d28475e494dda7d3b35c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Fri, 30 Oct 2015 12:51:30 -0700 Subject: [PATCH 046/171] DO NOT MERGE --- interface/src/Application.cpp | 10 +++++-- interface/src/avatar/AvatarActionHold.cpp | 22 +++++++++++++-- .../input-plugins/ViveControllerManager.cpp | 28 +++++++++++++++---- .../src/input-plugins/ViveControllerManager.h | 8 ++++-- libraries/shared/src/PhysicsHelpers.h | 2 +- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eebd26c3c3..8f9fc9b16e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -950,8 +950,8 @@ void Application::initializeGL() { checkFPStimer.start(1000); // call our idle function whenever we can - connect(&idleTimer, &QTimer::timeout, this, &Application::idle); - idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); + // connect(&idleTimer, &QTimer::timeout, this, &Application::idle); + // idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); _idleLoopStdev.reset(); // update before the first render @@ -1023,6 +1023,10 @@ void Application::paintGL() { if (_inPaint) { return; } + + // this is a good idea + idle(); + _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2070,7 +2074,7 @@ void Application::idle() { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - return; // bail early, we're throttled and not enough time has elapsed + //return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 59bfd88be6..941e876075 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,7 +35,8 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } - +#include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -51,7 +52,24 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { + + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "right") ? 0 : 1; auto userInputMapper = DependencyManager::get(); + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; + } else if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index bb8267b616..28e001208c 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -217,6 +217,15 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +glm::vec3 ViveControllerManager::getPosition(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return extractTranslation(mat); +} +glm::quat ViveControllerManager::getRotation(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return glm::quat_cast(mat); +} + void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN _poseStateMap.clear(); @@ -250,7 +259,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { numTrackedControllers++; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } @@ -372,16 +381,23 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - + + float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); - rotation = rotation * offset * yFlip * quarterX; + + + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); - position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 5cae8daaf4..f6220ca97a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,6 +27,8 @@ class ViveControllerManager : public InputPlugin, public InputDevice { Q_OBJECT public: + static const QString NAME; + enum JoystickAxisChannel { AXIS_Y_POS = 1U << 1, AXIS_Y_NEG = 1U << 2, @@ -74,6 +76,10 @@ public: UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JointChannel joint); + + int getNumDevices() const; + glm::vec3 getPosition(int device) const; + glm::quat getRotation(int device) const; private: void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index); @@ -92,8 +98,6 @@ private: int _rightHandRenderID; bool _renderControllers; - - static const QString NAME; }; #endif // hifi__ViveControllerManager diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 7ceafea915..3b6fccdc99 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -16,7 +16,7 @@ #include const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. -const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; +const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); From b0650cc2c180ec77777e6066a18b97d021fd681a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 Oct 2015 14:37:06 -0700 Subject: [PATCH 047/171] Remove accidentally commited file --- examples/map.js~ | 323 ----------------------------------------------- 1 file changed, 323 deletions(-) delete mode 100644 examples/map.js~ diff --git a/examples/map.js~ b/examples/map.js~ deleted file mode 100644 index 5a4e0f0f8c..0000000000 --- a/examples/map.js~ +++ /dev/null @@ -1,323 +0,0 @@ -Script.include("entityManager.js"); -Script.include("overlayManager.js"); - - -// Poll for nearby map data - -var entityManager = new EntityManager(); - -// From http://evanw.github.io/lightgl.js/docs/raytracer.html -function raySphereIntersection(origin, ray, center, radius) { - var offset = Vec3.subtract(origin, center); - var a = Vec3.dot(ray, ray); - // var a = ray.dot(ray); - var b = 2 * Vec3.dot(ray, offset); - // var b = 2 * ray.dot(offset); - var c = Vec3.dot(offset, offset) - radius * radius; - // var c = offset.dot(offset) - radius * radius; - var discriminant = b * b - 4 * a * c; - - if (discriminant > 0) { - return true; - } - - return null; -}; - - -Map = function(data) { - var visible = false; - - var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - - var ROOT_SCALE = 0.0005; - - // Create object in objectManager - var rootObject = entityManager.addBare(); - var position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - rootObject.scale = ROOT_SCALE - Vec3.print("Position:", position); - - // Search for all nearby objects that have the userData "mapped" - // TODO Update to use the zone's bounds - var entities = Entities.findEntities(MyAvatar.position, 32000); - var mappedEntities = []; - var minCorner = { - x: 4294967295, - y: 4294967295, - z: 4294967295, - }; - var maxCorner = { - x: -4294967295, - y: -4294967295, - z: -4294967295, - }; - - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - if (properties.userData == "mapped" || properties.userData == "tracked") { - - print("Found: ", properties.name); - - minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); - minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); - minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); - maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); - maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - } - // if (properties.userData == "mapped") { - // properties.visible = false; - // var entity = entityManager.add(properties.type, properties); - // mappedEntities.push(entity); - // } else if (properties.userData == "tracked") { - // // TODO implement tracking of objects - // } - } - - var dimensions = { - x: maxCorner.x - minCorner.x, - y: maxCorner.y - minCorner.y, - z: maxCorner.z - minCorner.z, - }; - Vec3.print("dims", dimensions); - - var center = { - x: minCorner.x + (dimensions.x / 2), - y: minCorner.y + (dimensions.y / 2), - z: minCorner.z + (dimensions.z / 2), - }; - Vec3.print("center", center); - - var trackedEntities = []; - var waypointEntities = []; - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - var mapData = null; - try { - var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); - mapData = data.mapData; - } catch (e) { - print("Caught: ", properties.name); - } - - if (mapData) { - print("Creating copy of", properties.name); - properties.name += " (COPY)"; - properties.userData = ""; - properties.visible = true; - var position = properties.position; - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - var extra = { }; - - if (mapData.track) { - extra.trackingEntityID= entityID; - trackedEntities.push(entity); - rootObject.addChild(entity); - } - if (mapData.waypoint) { - print("Waypoint: ", mapData.waypoint.name); - // properties.type = "Model"; - // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; - extra.waypoint = mapData.waypoint; - extra.waypoint.position = position; - } - - var entity = entityManager.add(properties.type, properties); - entity.__extra__ = extra; - if (mapData.waypoint) { - waypointEntities.push(entity); - } - mappedEntities.push(entity); - - rootObject.addChild(entity); - - } else { - // print("Not creating copy of", properties.name); - } - } - - var avatarArrowEntity = entityManager.add("Model", { - name: "You Are Here", - modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", - position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), - dimensions: { x: 30, y: 100, z: 100 }, - }); - rootObject.addChild(avatarArrowEntity); - - this.isVisible = function() { - return visible; - } - - Controller.mousePressEvent.connect(mousePressEvent); - function mousePressEvent(event) { - // Entities.setZonesArePickable(false); - - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - // var result = Entities.findRayIntersection(pickRay, false); - // if (result.intersects) { - // var entity = entityManager.get(result.entityID); - // if (entity) { - // print("Pressed entity: ", entity.id); - // } - // if (entity && entity.__extra__.waypoint) { - // print("Pressed waypoint: ", entity.__extra__.waypoint.name); - // print("Teleporting..."); - // MyAvatar.position = entity.__extra__.waypoint.position; - // } - // } - - // Entities.setZonesArePickable(true); - }; - - var time = 0; - Script.update.connect(function(dt) { - time += dt; - // Update tracked entities - for (var i = 0; i < trackedEntities.length; ++i) { - entity = trackedEntities[i]; - var entityID = entity.__extra__.trackingEntityID; - var properties = Entities.getEntityProperties(entityID); - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - entity.position = properties.position; - } - - - var position = Vec3.subtract(MyAvatar.position, center) - position.y += 60 + (Math.sin(time) * 10); - position = Vec3.multiply(position, ROOT_SCALE); - avatarArrowEntity.position = position; - // Vec3.print("Position:", avatarArrowEntity.position); - - // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); - //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - // position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - entityManager.update(); - - // Update waypoint highlights - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - }); - - function setVisible(newValue) { - if (visible != newValue) { - visible = newValue; - - if (visible) { - } else { - } - } - } - - this.show = function() { - setVisible(true); - } - - this.hide = function() { - setVisible(false); - } -}; - -var map = null; -map = Map(mapData); - -// On press key -Controller.keyPressEvent.connect(function(event) { - if (event.text == "m") { - if (!map) { - map = Map(mapData); - } - - map.show(); - print("MAP!"); - } -}); - - - - - -var mapData = { - config: { - // World dimensions that the minimap maps to - worldDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - // The center of the map should map to this location in the center of the area - worldCenter: { - x: 5.0, - y: 5.0, - z: 5.0, - }, - // Map dimensions - mapDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - - // Can this be automated? Tag entities that should be included? Store in UserData? - objects: [ - { - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", - }, - ], - }, - waypoints: [ - { - name: "Forest's Edge", - position: { - }, - }, - ], -}; - - -// entityManager = new OverlayManager(); -// entityManager = new EntityManager(); -// -// var rootEntity = entityManager.addBare(); -// -// var time = 0; -// -// -// rootEntity.scale = 0.1; -// Script.include("sfData.js"); -// rootEntity.addChild(entity); -entityManager.update(); From 017cee696151429c9df7810cfc2361144791ce36 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 11:59:09 -0800 Subject: [PATCH 048/171] make shouldRenderLocally do the right thing --- interface/src/avatar/MyAvatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b567b62747..ca57fa0e21 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -537,7 +537,7 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (!_shouldRender) { return; // exit early } - + Avatar::render(renderArgs, cameraPosition); // don't display IK constraints in shadow mode @@ -1372,7 +1372,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (!_skeletonModel.isRenderable()) { return; // wait until all models are loaded } - + fixupModelsInScene(); // Render head so long as the camera isn't inside it diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5f75b7cf14..4a27615f67 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -226,6 +226,7 @@ public slots: void setEnableAnimGraph(bool isEnabled); void setEnableDebugDrawBindPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled); + bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); } void setEnableMeshVisible(bool isEnabled); void setAnimGraphUrl(const QString& url) { _animGraphUrl = url; } @@ -248,7 +249,7 @@ private: virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; - void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } + void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); } bool getShouldRenderLocally() const { return _shouldRender; } bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; bool isMyAvatar() const override { return true; } From 72775a7af8a6c58443edac9bd82e4b184f6741ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:05 -0800 Subject: [PATCH 049/171] Clean up pitching.js so the pitching machine code is separate --- examples/baseball/pitching.js | 233 ++++++++++++++++++++++++++-------- 1 file changed, 179 insertions(+), 54 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 6ec4d2df85..9d84cf7a27 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,11 @@ -Script.include("line.js"); +print("Loading pitching"); +//Script.include("../libraries/line.js"); +Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); + +// These are hard-coded to the relevant entity IDs on the sport server +var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; -var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; var METERS_TO_FEET = 3.28084; var AUDIO = { @@ -76,6 +81,110 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + for (var i = 0; i < entities.length; ++i) { + var match = true; + for (var key in properties) { + if (entities[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + +getPitchingMachine = function() { + // Search for pitching machine + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var pitchingMachineID = null; + + // Create if it doesn't exist + if (entities.length == 0) { + pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); + } else { + pitchingMachineID = entities[0]; + } + + // Wrap with PitchingMachine object and return + return new PitchingMachine(pitchingMachineID); +} + +function PitchingMachine(pitchingMachineID) { + this.pitchingMachineID = pitchingMachineID; + this.enabled = false; + this.baseball = null; + this.injector = null; +} + +PitchingMachine.prototype = { + pitchBall: function() { + cleanupTrail(); + updateBillboard(""); + + if (!this.enabled) { + return; + } + + print("Pitching ball"); + var pitchDirection = { x: 0, y: 0, z: 1 }; + var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); + print("PROPS"); + print("props ", JSON.stringify(machineProperties)); + var pitchFromPositionBase = machineProperties.position; + var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); + pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); + var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); + var pitchDirection = Quat.getFront(machineProperties.rotation); + var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; + print("Creating baseball"); + + var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED); + var velocity = Vec3.multiply(speed, pitchDirection); + + this.baseball = new Baseball(pitchFromPosition, velocity, ballScale); + Vec3.print("vel", velocity); + Vec3.print("pos", pitchFromPosition); + + if (!this.injector) { + this.injector = Audio.playSound(pitchSound, { + position: pitchFromPosition, + volume: 1.0 + }); + } else { + this.injector.restart(); + } + print("Created baseball"); + }, + start: function() { + print("Starting Pitching Machine"); + this.enabled = true; + }, + stop: function() { + print("Stopping Pitching Machine"); + this.enabled = false; + }, + update: function(dt) { + if (this.baseball) { + this.baseball.update(dt); + if (this.baseball.finished()) { + print("BALL IS FINISHED"); + this.baseball = null; + var self = this; + Script.setTimeout(function() { self.pitchBall() }, 3000); + } + } + } +}; + var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; var BASEBALL_MIN_SPEED = 2.7; var BASEBALL_MAX_SPEED = 5.7; @@ -111,10 +220,9 @@ var BASEBALL_PROPERTIES = { friction: 0.0, friction: 0.5, lifetime: 20, - //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { x: 0, - y: 0,//-9.8, + y: 0, z: 0 } }; @@ -127,11 +235,6 @@ var BASEBALL_STATE = { }; -var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); - -var pitchFromPosition = { x: 0, y: 1.0, z: 0 }; -var pitchDirection = { x: 0, y: 0, z: 1 }; - function shallowCopy(obj) { var copy = {} for (var key in obj) { @@ -186,9 +289,41 @@ function orientationOf(vector) { return Quat.multiply(yaw, pitch); } -var injector = null; +var ACCELERATION_SPREAD = 0.35; -var ACCELERATION_SPREAD = 10.15; +var TRAIL_COLOR = { red: 128, green: 255, blue: 89 }; +var TRAIL_LIFETIME = 20; + +function ObjectTrail(entityID, startPosition) { + this.entityID = entityID; + this.line = null; + var lineInterval = null; + + print("Creating Trail!"); + var lastPosition = startPosition; + trail = new InfiniteLine(startPosition, trailColor, trailLifetime); + trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + Vec3.print("Adding trail", properties.position); + var strokeWidth = Math.log(1 + trail.size) * 0.05; + trail.enqueuePoint(properties.position, strokeWidth); + lastPosition = properties.position; + } + }, 50); +} + +ObjectTrail.prototype = { + destroy: function() { + if (this.line) { + Script.clearInterval(this.lineInterval); + this.lineInterval = null; + + this.line.destroy(); + this.line = null; + } + } +}; var trail = null; var trailInterval = null; @@ -205,12 +340,15 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); + print("Creating Trail!"); var lastPosition = position; - trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); + trail = new InfiniteLine(position, { red: 128, green: 255, blue: 89 }, 20); trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - trail.enqueuePoint(properties.position); + Vec3.print("Adding trail", properties.position); + var strokeWidth = Math.log(1 + trail.size) * 0.05; + trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; } }, 50); @@ -228,8 +366,8 @@ function Baseball(position, velocity, ballScale) { properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); /* properties.gravity = { - x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), - y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, }; */ @@ -246,27 +384,39 @@ function Baseball(position, velocity, ballScale) { Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { self.collisionCallback(entityA, entityB, collision); }); - /* - if (false && Math.random() < 0.5) { + if (Math.random() < 0.5) { for (var i = 0; i < 50; i++) { Script.setTimeout(function() { Entities.editEntity(entityID, { gravity: { - x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), - y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, } }) }, i * 100); } } - */ } -function updateBillboard(value) { +// Update the stadium billboard with the current distance and update the high score +// if it has been beaten. +function updateBillboard(distance) { Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: value, + text: distance, }); + + // If a number was passed in, let's see if it is larger than the current high score + // and update it if so. + if (!isNaN(distance)) { + var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); + var bestDistance = parseInt(properties.text); + if (distance > bestDistance) { + Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { + text: distance, + }); + } + } } Baseball.prototype = { @@ -292,7 +442,6 @@ Baseball.prototype = { if (this.timeSincePitched > 10) { print("TIMED OUT WHILE PITCHING"); this.state = BASEBALL_STATE.STRIKE; - } } }, @@ -383,33 +532,6 @@ Baseball.prototype = { var baseball = null; -function pitchBall() { - cleanupTrail(); - updateBillboard(""); - var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); - var pitchFromPositionBase = machineProperties.position; - var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); - pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); - var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); - var pitchDirection = Quat.getFront(machineProperties.rotation); - var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; - print("Creating baseball"); - - var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) - var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; - - baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); - - if (!injector) { - injector = Audio.playSound(pitchSound, { - position: pitchFromPosition, - volume: 1.0 - }); - } else { - injector.restart(); - } -} - function update(dt) { if (baseball) { baseball.update(dt); @@ -425,7 +547,7 @@ function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); var position = Entities.getEntityProperties(entity, "position").position; - var particleRadius = 0.3;//map(dVelocityMagnitude, 0.05, 3, 0.5, 2); + var particleRadius = 0.3; var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); var displayTime = 400; var orientationChange = orientationOf(collision.velocityChange); @@ -460,6 +582,9 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -//Script.setInterval(pitchBall, PITCH_RATE); -Script.update.connect(update); -pitchBall(); +//Script.update.connect(update); +//var pitchingMachine = getPitchingMachine(); +//pitchingMachine.pitchBall(); +//Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + +print("Done loading pitching.js"); From 3820adf3f68da1694b911320b674fd26529dfef2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:21 -0800 Subject: [PATCH 050/171] Add bat.js --- examples/baseball/bat.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/baseball/bat.js diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js new file mode 100644 index 0000000000..b04a77ec3e --- /dev/null +++ b/examples/baseball/bat.js @@ -0,0 +1,15 @@ +(function() { + Script.include("file:///c:%5CUsers%5CRyan%5Cdev%5Chifi%5Cexamples%5Cbaseball%5Cpitching.js"); + var pitchingMachine = getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + this.startNearGrab = function() { + print("Started near grab!"); + pitchingMachine.start(); + }; + this.releaseGrab = function() { + print("Stopped near grab!"); + if (pitchingMachine) { + pitchingMachine.stop(); + } + }; +}); From b8d90ab28e976ddc1ab86b74708028f9fad6940d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:54 -0800 Subject: [PATCH 051/171] Replace pitching.js include with relative path --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index b04a77ec3e..76e9a0a588 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,5 +1,5 @@ (function() { - Script.include("file:///c:%5CUsers%5CRyan%5Cdev%5Chifi%5Cexamples%5Cbaseball%5Cpitching.js"); + Script.include("pitching.js"); var pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); this.startNearGrab = function() { From 8eded438db046f258a906f45276428777080a92e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 14:09:24 -0800 Subject: [PATCH 052/171] Remove _controllerScriptingInterface from ScriptEngine.h --- libraries/script-engine/src/ScriptEngine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index bd3912ea18..e67a1637c5 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -188,7 +188,6 @@ private: static bool checkSyntax(const QScriptProgram& program); static bool checkExceptions(QScriptEngine& engine, const QString& fileName); - AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; Quat _quatLibrary; Vec3 _vec3Library; From ed610d69e029f2ea09f5d2ed9426a9982e6d644e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 14:18:39 -0800 Subject: [PATCH 053/171] resolve conflicts merging with huffman/baseball --- libraries/script-engine/src/ScriptEngine.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 39885e313a..1ae2aa05ca 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -141,7 +141,10 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - + +public slots: + void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); + signals: void scriptLoaded(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename); @@ -181,9 +184,6 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - - static bool checkSyntax(const QScriptProgram& program); - static bool checkExceptions(QScriptEngine& engine, const QString& fileName); QString _fileNameString; Quat _quatLibrary; From 8b6db3b6c095b2775e66a1c409aa12185b2f8f0e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:13:07 -0800 Subject: [PATCH 054/171] Add shouldRenderLocally to bat.js and fix findEntities --- examples/baseball/bat.js | 2 ++ examples/baseball/pitching.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 76e9a0a588..cc4629c089 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -5,11 +5,13 @@ this.startNearGrab = function() { print("Started near grab!"); pitchingMachine.start(); + MyAvatar.shouldRenderLocally = false; }; this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } + MyAvatar.shouldRenderLocally = true; }; }); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9d84cf7a27..9c5654d652 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -85,10 +85,12 @@ var PITCH_RATE = 5000; function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); var matchedEntities = []; + var keys = Object.keys(properties); for (var i = 0; i < entities.length; ++i) { var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); for (var key in properties) { - if (entities[key] != properties[key]) { + if (candidateProperties[key] != properties[key]) { // This isn't a match, move to next entity match = false; break; From def8294b604c890fe04d7d1f3165477a02cd4f21 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:28:18 -0800 Subject: [PATCH 055/171] Fix pitching machine not starting when enabled --- examples/baseball/pitching.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9c5654d652..47876aafdf 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -106,7 +106,7 @@ function findEntities(properties, searchRadius) { getPitchingMachine = function() { // Search for pitching machine - var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; // Create if it doesn't exist @@ -183,6 +183,8 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } + } else if (this.enabled) { + this.pitchBall(); } } }; From 3cbcc6494f3fd210c730bf8589c1af85c4105c9f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:34:42 -0800 Subject: [PATCH 056/171] Update bat.js to lazy load the pitching machine --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index cc4629c089..c8857095d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,8 +1,11 @@ (function() { Script.include("pitching.js"); - var pitchingMachine = getPitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + var pitchingMachine = null; this.startNearGrab = function() { + if (!pitchingMachine) { + getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; From 1b673a99c03c87f15c18f9acab98d12b12853f18 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:59:55 -0800 Subject: [PATCH 057/171] Fix updating of distance/high score --- examples/baseball/pitching.js | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 47876aafdf..8710a33cce 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,9 +2,35 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + // These are hard-coded to the relevant entity IDs on the sport server -var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var DISTANCE_BILLBOARD_NAME = "CurrentScore"; +var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; @@ -81,29 +107,6 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} - getPitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); From 91a13788899efc9cda4177755c640c6caa157283 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 16:09:51 -0800 Subject: [PATCH 058/171] Clean up foul/strike in pitching.js --- examples/baseball/pitching.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8710a33cce..647ee834c2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -133,7 +133,6 @@ function PitchingMachine(pitchingMachineID) { PitchingMachine.prototype = { pitchBall: function() { cleanupTrail(); - updateBillboard(""); if (!this.enabled) { return; @@ -171,9 +170,17 @@ PitchingMachine.prototype = { }, start: function() { print("Starting Pitching Machine"); + if (this.enabled) { + print("Already enabled") + return; + } this.enabled = true; + this.pitchBall(); }, stop: function() { + if (!this.enabled) { + return; + } print("Stopping Pitching Machine"); this.enabled = false; }, @@ -186,8 +193,6 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } - } else if (this.enabled) { - this.pitchBall(); } } }; @@ -312,7 +317,6 @@ function ObjectTrail(entityID, startPosition) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -505,7 +509,7 @@ Baseball.prototype = { }); }, 500); if (foul) { - updateBillboard("FOUL!"); + updateBillboard("FOUL"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -526,7 +530,7 @@ Baseball.prototype = { } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; - updateBillboard("STRIKE!"); + updateBillboard("STRIKE"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, From 31d92fd90ab37a482de3db966d77f419855df172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Fri, 30 Oct 2015 12:51:30 -0700 Subject: [PATCH 059/171] Baseball test code --- interface/src/Application.cpp | 10 +++++-- interface/src/avatar/AvatarActionHold.cpp | 22 +++++++++++++-- .../input-plugins/ViveControllerManager.cpp | 28 +++++++++++++++---- .../src/input-plugins/ViveControllerManager.h | 8 ++++-- libraries/shared/src/PhysicsHelpers.h | 2 +- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eebd26c3c3..8f9fc9b16e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -950,8 +950,8 @@ void Application::initializeGL() { checkFPStimer.start(1000); // call our idle function whenever we can - connect(&idleTimer, &QTimer::timeout, this, &Application::idle); - idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); + // connect(&idleTimer, &QTimer::timeout, this, &Application::idle); + // idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); _idleLoopStdev.reset(); // update before the first render @@ -1023,6 +1023,10 @@ void Application::paintGL() { if (_inPaint) { return; } + + // this is a good idea + idle(); + _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2070,7 +2074,7 @@ void Application::idle() { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - return; // bail early, we're throttled and not enough time has elapsed + //return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 59bfd88be6..941e876075 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,7 +35,8 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } - +#include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -51,7 +52,24 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { + + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "right") ? 0 : 1; auto userInputMapper = DependencyManager::get(); + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; + } else if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index bb8267b616..28e001208c 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -217,6 +217,15 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +glm::vec3 ViveControllerManager::getPosition(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return extractTranslation(mat); +} +glm::quat ViveControllerManager::getRotation(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return glm::quat_cast(mat); +} + void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN _poseStateMap.clear(); @@ -250,7 +259,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { numTrackedControllers++; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } @@ -372,16 +381,23 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - + + float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); - rotation = rotation * offset * yFlip * quarterX; + + + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); - position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 5cae8daaf4..f6220ca97a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,6 +27,8 @@ class ViveControllerManager : public InputPlugin, public InputDevice { Q_OBJECT public: + static const QString NAME; + enum JoystickAxisChannel { AXIS_Y_POS = 1U << 1, AXIS_Y_NEG = 1U << 2, @@ -74,6 +76,10 @@ public: UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JointChannel joint); + + int getNumDevices() const; + glm::vec3 getPosition(int device) const; + glm::quat getRotation(int device) const; private: void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index); @@ -92,8 +98,6 @@ private: int _rightHandRenderID; bool _renderControllers; - - static const QString NAME; }; #endif // hifi__ViveControllerManager diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 7ceafea915..3b6fccdc99 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -16,7 +16,7 @@ #include const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. -const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; +const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); From 01bbd3665e2cdcb78a4770b0e7ca5da88e80915f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 Oct 2015 14:37:06 -0700 Subject: [PATCH 060/171] Remove accidentally commited file --- examples/map.js~ | 323 ----------------------------------------------- 1 file changed, 323 deletions(-) delete mode 100644 examples/map.js~ diff --git a/examples/map.js~ b/examples/map.js~ deleted file mode 100644 index 5a4e0f0f8c..0000000000 --- a/examples/map.js~ +++ /dev/null @@ -1,323 +0,0 @@ -Script.include("entityManager.js"); -Script.include("overlayManager.js"); - - -// Poll for nearby map data - -var entityManager = new EntityManager(); - -// From http://evanw.github.io/lightgl.js/docs/raytracer.html -function raySphereIntersection(origin, ray, center, radius) { - var offset = Vec3.subtract(origin, center); - var a = Vec3.dot(ray, ray); - // var a = ray.dot(ray); - var b = 2 * Vec3.dot(ray, offset); - // var b = 2 * ray.dot(offset); - var c = Vec3.dot(offset, offset) - radius * radius; - // var c = offset.dot(offset) - radius * radius; - var discriminant = b * b - 4 * a * c; - - if (discriminant > 0) { - return true; - } - - return null; -}; - - -Map = function(data) { - var visible = false; - - var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - - var ROOT_SCALE = 0.0005; - - // Create object in objectManager - var rootObject = entityManager.addBare(); - var position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - rootObject.scale = ROOT_SCALE - Vec3.print("Position:", position); - - // Search for all nearby objects that have the userData "mapped" - // TODO Update to use the zone's bounds - var entities = Entities.findEntities(MyAvatar.position, 32000); - var mappedEntities = []; - var minCorner = { - x: 4294967295, - y: 4294967295, - z: 4294967295, - }; - var maxCorner = { - x: -4294967295, - y: -4294967295, - z: -4294967295, - }; - - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - if (properties.userData == "mapped" || properties.userData == "tracked") { - - print("Found: ", properties.name); - - minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); - minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); - minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); - maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); - maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - } - // if (properties.userData == "mapped") { - // properties.visible = false; - // var entity = entityManager.add(properties.type, properties); - // mappedEntities.push(entity); - // } else if (properties.userData == "tracked") { - // // TODO implement tracking of objects - // } - } - - var dimensions = { - x: maxCorner.x - minCorner.x, - y: maxCorner.y - minCorner.y, - z: maxCorner.z - minCorner.z, - }; - Vec3.print("dims", dimensions); - - var center = { - x: minCorner.x + (dimensions.x / 2), - y: minCorner.y + (dimensions.y / 2), - z: minCorner.z + (dimensions.z / 2), - }; - Vec3.print("center", center); - - var trackedEntities = []; - var waypointEntities = []; - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - var mapData = null; - try { - var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); - mapData = data.mapData; - } catch (e) { - print("Caught: ", properties.name); - } - - if (mapData) { - print("Creating copy of", properties.name); - properties.name += " (COPY)"; - properties.userData = ""; - properties.visible = true; - var position = properties.position; - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - var extra = { }; - - if (mapData.track) { - extra.trackingEntityID= entityID; - trackedEntities.push(entity); - rootObject.addChild(entity); - } - if (mapData.waypoint) { - print("Waypoint: ", mapData.waypoint.name); - // properties.type = "Model"; - // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; - extra.waypoint = mapData.waypoint; - extra.waypoint.position = position; - } - - var entity = entityManager.add(properties.type, properties); - entity.__extra__ = extra; - if (mapData.waypoint) { - waypointEntities.push(entity); - } - mappedEntities.push(entity); - - rootObject.addChild(entity); - - } else { - // print("Not creating copy of", properties.name); - } - } - - var avatarArrowEntity = entityManager.add("Model", { - name: "You Are Here", - modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", - position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), - dimensions: { x: 30, y: 100, z: 100 }, - }); - rootObject.addChild(avatarArrowEntity); - - this.isVisible = function() { - return visible; - } - - Controller.mousePressEvent.connect(mousePressEvent); - function mousePressEvent(event) { - // Entities.setZonesArePickable(false); - - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - // var result = Entities.findRayIntersection(pickRay, false); - // if (result.intersects) { - // var entity = entityManager.get(result.entityID); - // if (entity) { - // print("Pressed entity: ", entity.id); - // } - // if (entity && entity.__extra__.waypoint) { - // print("Pressed waypoint: ", entity.__extra__.waypoint.name); - // print("Teleporting..."); - // MyAvatar.position = entity.__extra__.waypoint.position; - // } - // } - - // Entities.setZonesArePickable(true); - }; - - var time = 0; - Script.update.connect(function(dt) { - time += dt; - // Update tracked entities - for (var i = 0; i < trackedEntities.length; ++i) { - entity = trackedEntities[i]; - var entityID = entity.__extra__.trackingEntityID; - var properties = Entities.getEntityProperties(entityID); - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - entity.position = properties.position; - } - - - var position = Vec3.subtract(MyAvatar.position, center) - position.y += 60 + (Math.sin(time) * 10); - position = Vec3.multiply(position, ROOT_SCALE); - avatarArrowEntity.position = position; - // Vec3.print("Position:", avatarArrowEntity.position); - - // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); - //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - // position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - entityManager.update(); - - // Update waypoint highlights - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - }); - - function setVisible(newValue) { - if (visible != newValue) { - visible = newValue; - - if (visible) { - } else { - } - } - } - - this.show = function() { - setVisible(true); - } - - this.hide = function() { - setVisible(false); - } -}; - -var map = null; -map = Map(mapData); - -// On press key -Controller.keyPressEvent.connect(function(event) { - if (event.text == "m") { - if (!map) { - map = Map(mapData); - } - - map.show(); - print("MAP!"); - } -}); - - - - - -var mapData = { - config: { - // World dimensions that the minimap maps to - worldDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - // The center of the map should map to this location in the center of the area - worldCenter: { - x: 5.0, - y: 5.0, - z: 5.0, - }, - // Map dimensions - mapDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - - // Can this be automated? Tag entities that should be included? Store in UserData? - objects: [ - { - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", - }, - ], - }, - waypoints: [ - { - name: "Forest's Edge", - position: { - }, - }, - ], -}; - - -// entityManager = new OverlayManager(); -// entityManager = new EntityManager(); -// -// var rootEntity = entityManager.addBare(); -// -// var time = 0; -// -// -// rootEntity.scale = 0.1; -// Script.include("sfData.js"); -// rootEntity.addChild(entity); -entityManager.update(); From 57a68edaa3befacdc76e83108164e55f8495141e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 14:18:39 -0800 Subject: [PATCH 061/171] resolve conflicts merging with huffman/baseball --- libraries/script-engine/src/ScriptEngine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index b0595cf3c6..8ec06dd89d 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -141,10 +141,10 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - + public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); - + signals: void scriptLoaded(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename); @@ -184,7 +184,7 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - + QString _fileNameString; Quat _quatLibrary; Vec3 _vec3Library; From f18d8f5fbbc3285d3487acc368189b3638d7f705 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:13:07 -0800 Subject: [PATCH 062/171] Add shouldRenderLocally to bat.js and fix findEntities --- examples/baseball/bat.js | 2 ++ examples/baseball/pitching.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 76e9a0a588..cc4629c089 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -5,11 +5,13 @@ this.startNearGrab = function() { print("Started near grab!"); pitchingMachine.start(); + MyAvatar.shouldRenderLocally = false; }; this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } + MyAvatar.shouldRenderLocally = true; }; }); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9d84cf7a27..9c5654d652 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -85,10 +85,12 @@ var PITCH_RATE = 5000; function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); var matchedEntities = []; + var keys = Object.keys(properties); for (var i = 0; i < entities.length; ++i) { var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); for (var key in properties) { - if (entities[key] != properties[key]) { + if (candidateProperties[key] != properties[key]) { // This isn't a match, move to next entity match = false; break; From d535bb6ed8272fdb01e7112272621668ea756be3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:28:18 -0800 Subject: [PATCH 063/171] Fix pitching machine not starting when enabled --- examples/baseball/pitching.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9c5654d652..47876aafdf 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -106,7 +106,7 @@ function findEntities(properties, searchRadius) { getPitchingMachine = function() { // Search for pitching machine - var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; // Create if it doesn't exist @@ -183,6 +183,8 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } + } else if (this.enabled) { + this.pitchBall(); } } }; From bb0ce67f6b103b671e1598f6cbaf1291c10e21ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:34:42 -0800 Subject: [PATCH 064/171] Update bat.js to lazy load the pitching machine --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index cc4629c089..c8857095d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,8 +1,11 @@ (function() { Script.include("pitching.js"); - var pitchingMachine = getPitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + var pitchingMachine = null; this.startNearGrab = function() { + if (!pitchingMachine) { + getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; From 14cdc5801e9f76e57e641ec60a7faf6289f4d265 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:59:55 -0800 Subject: [PATCH 065/171] Fix updating of distance/high score --- examples/baseball/pitching.js | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 47876aafdf..8710a33cce 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,9 +2,35 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + // These are hard-coded to the relevant entity IDs on the sport server -var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var DISTANCE_BILLBOARD_NAME = "CurrentScore"; +var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; @@ -81,29 +107,6 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} - getPitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); From e8b550be9fb3c84b160624a74ad29c4979368bde Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 16:09:51 -0800 Subject: [PATCH 066/171] Clean up foul/strike in pitching.js --- examples/baseball/pitching.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8710a33cce..647ee834c2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -133,7 +133,6 @@ function PitchingMachine(pitchingMachineID) { PitchingMachine.prototype = { pitchBall: function() { cleanupTrail(); - updateBillboard(""); if (!this.enabled) { return; @@ -171,9 +170,17 @@ PitchingMachine.prototype = { }, start: function() { print("Starting Pitching Machine"); + if (this.enabled) { + print("Already enabled") + return; + } this.enabled = true; + this.pitchBall(); }, stop: function() { + if (!this.enabled) { + return; + } print("Stopping Pitching Machine"); this.enabled = false; }, @@ -186,8 +193,6 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } - } else if (this.enabled) { - this.pitchBall(); } } }; @@ -312,7 +317,6 @@ function ObjectTrail(entityID, startPosition) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -505,7 +509,7 @@ Baseball.prototype = { }); }, 500); if (foul) { - updateBillboard("FOUL!"); + updateBillboard("FOUL"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -526,7 +530,7 @@ Baseball.prototype = { } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; - updateBillboard("STRIKE!"); + updateBillboard("STRIKE"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, From c63fc8557cda1fa992ca12ac9134ce355f6f790c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Tue, 3 Nov 2015 10:11:25 -0800 Subject: [PATCH 067/171] More baseball test code --- interface/src/avatar/AvatarActionHold.cpp | 53 ++++++++++--------- .../input-plugins/ViveControllerManager.cpp | 32 ++++++----- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5bec513fd4..b6e3ea408f 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -52,32 +52,35 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - - const auto& plugins = PluginManager::getInstance()->getInputPlugins(); - auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { - return plugin->getName() == ViveControllerManager::NAME; - }); - - if (it != std::end(plugins)) { - const auto& vive = it->dynamicCast(); - auto index = (_hand == "right") ? 0 : 1; + +#ifdef Q_OS_WIN + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); - auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; - } else if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + } else +#endif + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index b8755ea2e3..f5863c6ed0 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -278,12 +278,18 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); handleButtonEvent(i, pressed, left); } - for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); + if (pressed || true) { + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + } else { + handleAxisEvent(i, 0.0f, 0.0f, left); + } } } } @@ -412,16 +418,14 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - - const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; - const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - 2.0f * CONTROLLER_LENGTH_OFFSET); - - position += rotation * translationOffset; - rotation = rotation * rotationOffset; - //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} - + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); + + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation); } From 0508091130fff5b0c155d75989cfee49a22d2219 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 11:37:57 -0800 Subject: [PATCH 068/171] Rebase fixes --- interface/src/avatar/AvatarActionHold.cpp | 23 ++++++++------- .../input-plugins/ViveControllerManager.cpp | 29 ++++++++++--------- .../src/input-plugins/ViveControllerManager.h | 8 +++-- libraries/script-engine/src/ScriptEngine.cpp | 8 ++--- libraries/script-engine/src/ScriptEngine.h | 2 +- 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b6e3ea408f..767c60defe 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -37,17 +37,18 @@ AvatarActionHold::~AvatarActionHold() { } #include #include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; glm::vec3 position; std::shared_ptr holdingAvatar = nullptr; - + gotLock = withTryReadLock([&]{ QSharedPointer avatarManager = DependencyManager::get(); AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID); holdingAvatar = std::static_pointer_cast(holdingAvatarData); - + if (holdingAvatar) { glm::vec3 offset; glm::vec3 palmPosition; @@ -70,23 +71,23 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); } else #endif - if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; } }); - + if (holdingAvatar) { if (gotLock) { gotLock = withTryWriteLock([&]{ diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index f5863c6ed0..b083d06a2a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -223,6 +223,7 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +#ifdef Q_OS_WIN glm::vec3 ViveControllerManager::getPosition(int hand) const { const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; return extractTranslation(mat); @@ -231,6 +232,7 @@ glm::quat ViveControllerManager::getRotation(int hand) const { const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; return glm::quat_cast(mat); } +#endif void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN @@ -278,22 +280,22 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); handleButtonEvent(i, pressed, left); } - for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); - if (pressed || true) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); - } else { - handleAxisEvent(i, 0.0f, 0.0f, left); - } + for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); + if (pressed || true) { + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + } else { + handleAxisEvent(i, 0.0f, 0.0f, left); + } } } } - + auto userInputMapper = DependencyManager::get(); if (numTrackedControllers == 0) { @@ -412,12 +414,13 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) float sign = left ? -1.0f : 1.0f; - + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); + const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index ad0474073c..eee6083102 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,8 +27,8 @@ class ViveControllerManager : public InputPlugin, public controller::InputDevice { Q_OBJECT public: - static const QString NAME; - + static const QString NAME; + ViveControllerManager(); // Plugin functions @@ -52,9 +52,11 @@ public: void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } - int getNumDevices() const; + +#ifdef Q_OS_WIN glm::vec3 getPosition(int device) const; glm::quat getRotation(int device) const; +#endif private: void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 4e53f6e60b..0173009995 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -367,10 +367,10 @@ void ScriptEngine::init() { registerGlobalObject("AnimationCache", DependencyManager::get().data()); qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); - + // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); - + auto scriptingInterface = DependencyManager::get(); registerGlobalObject("Controller", scriptingInterface.data()); UserInputMapper::registerControllerTypes(this); @@ -706,7 +706,7 @@ void ScriptEngine::run() { } } lastUpdate = now; - + // Debug and clear exceptions hadUncaughtExceptions(*this, _fileNameString); } @@ -1263,4 +1263,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS entityScript.property(methodName).call(entityScript, args); } } -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8ec06dd89d..1ae2aa05ca 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -205,4 +205,4 @@ private: }; -#endif // hifi_ScriptEngine_h \ No newline at end of file +#endif // hifi_ScriptEngine_h From 9be8d1edf94ac4bf9417d5581817cfc4836b725e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 11:44:33 -0800 Subject: [PATCH 069/171] Remove now unecessary vive hack --- .../src/input-plugins/ViveControllerManager.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index b083d06a2a..fb0021d7d5 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -285,13 +285,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { handleButtonEvent(i, pressed, left); } for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); - if (pressed || true) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); - } else { - handleAxisEvent(i, 0.0f, 0.0f, left); - } + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); } } } From 3056432b0c8ebea30cce79d6541c9b2dbcc005a3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 12:14:04 -0800 Subject: [PATCH 070/171] Add fireworks --- examples/baseball/firework.js | 144 ++++++++++++++++++++++++++++++++++ examples/baseball/utils.js | 35 +++++++++ 2 files changed, 179 insertions(+) create mode 100644 examples/baseball/firework.js create mode 100644 examples/baseball/utils.js diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js new file mode 100644 index 0000000000..8e7a9637ec --- /dev/null +++ b/examples/baseball/firework.js @@ -0,0 +1,144 @@ +Script.include("utils.js"); + +var emitters = []; + +var smokeTrailSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "velocity": { x: 0, y: 18.0, z: 0 }, + "lifetime": 20, + "lifespan":3, + "emitRate":1000, + "emitSpeed":0.5, + "speedSpread":1, + "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":1, + "polarFinish":1, + "azimuthStart":-Math.PI, + "azimuthFinish":Math.PI, + "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.03999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":0, + "alphaFinish":1, + "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}; + +var fireworkSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "lifetime": 20, + "lifespan":6, + "emitRate":1000, + "emitSpeed":1.5, + "speedSpread":1.0, + "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":1, + "polarFinish":1.2, + "azimuthStart":-Math.PI, + "azimuthFinish":Math.PI, + "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.03999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":0, + "alphaFinish":1, + "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/spark_2.png", + //"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/spark.png" +}; + +var popSounds = getSounds([ + "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav", + "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav", + "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav", + "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" +]); +var fireSounds = getSounds([ + "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", + "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", + "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", + "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav" +]) + +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +function shootFirework(position, color, options) { + smokeTrailSettings.position = position; + smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); + smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + var smokeID = Entities.addEntity(smokeTrailSettings); + emitters.push(smokeID); + Script.scriptEnding.connect(function() { + Entities.deleteEntity(smokeID); + }); + Script.setTimeout(function() { + Entities.editEntity(smokeID, { emitRate: 0 }); + var position = Entities.getEntityProperties(smokeID, ['position']).position; + Vec3.print("pos", position); + options.position = position; + options.colorStart = color; + options.colorFinish = color; + var id = Entities.addEntity(options); + emitters.push(id); + playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + Script.setTimeout(function() { + Entities.editEntity(id, { emitRate: 0 }); + Entities.deleteEntity(smokeID); + }, 500); + }, 2000); +} + +Script.scriptEnding.connect(function() { + for (var i = 0; i < emitters.lengths; ++i) { + Entities.deleteEntity(emitters[i]); + } +}); + +playFireworkShow = function(numberOfFireworks, duration) { + var position = { x: 0, y: 0, z: -78.0 }; + + for (var i = 0; i < numberOfFireworks; i++) { + var randomOffset = randomVec3(-15, 15, -3, 3, -1, 1); + var randomPosition = Vec3.sum(position, randomOffset); + Script.setTimeout(function(position) { + return function() { + var color = randomColor(128, 255, 128, 255, 128, 255); + shootFirework(position, color, fireworkSettings); + } + }(randomPosition), Math.random() * duration) + } +} + +//playFireworkShow(50, 10000); diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js new file mode 100644 index 0000000000..7266666cc9 --- /dev/null +++ b/examples/baseball/utils.js @@ -0,0 +1,35 @@ +randomInt = function(low, high) { + return Math.floor(randomFloat(low, high)); +}; + +randomFloat = function(low, high) { + if (high === undefined) { + high = low; + low = 0; + } + return low + Math.random() * (high - low); +}; + +randomColor = function(redMin, redMax, greenMin, greenMax, blueMin, blueMax) { + return { + red: Math.ceil(randomFloat(redMin, redMax)), + green: Math.ceil(randomFloat(greenMin, greenMax)), + blue: Math.ceil(randomFloat(blueMin, blueMax)), + } +}; + +randomVec3 = function(xMin, xMax, yMin, yMax, zMin, zMax) { + return { + x: randomFloat(xMin, xMax), + y: randomFloat(yMin, yMax), + z: randomFloat(zMin, zMax), + } +}; + +getSounds = function(soundURLs) { + var sounds = []; + for (var i = 0; i < soundURLs.length; ++i) { + sounds.push(SoundCache.getSound(soundURLs[i], false)); + } + return sounds; +}; From 2b8c6ebaf1ae027c5c58fea196c3bcbab60cf998 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 12:14:55 -0800 Subject: [PATCH 071/171] Add firework show when distance hit > 200 --- examples/baseball/pitching.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 647ee834c2..dedb4ba04a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +Script.include("firework.js") // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { @@ -357,7 +358,6 @@ function setupTrail(entityID, position) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -430,6 +430,8 @@ function updateBillboard(distance) { } } +var FIREWORK_SHOW_DISTANCE_FEET = 200; + Baseball.prototype = { finished: function() { return this.state == BASEBALL_STATE.FOUL @@ -442,12 +444,10 @@ Baseball.prototype = { this.timeSinceHit += dt; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); - this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); - updateBillboard(Math.ceil(this.distanceTravelled * METERS_TO_FEET)); + this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position) * METERS_TO_FEET; + updateBillboard(Math.ceil(this.distanceTravelled)); if (this.timeSinceHit > 10 || speed < 1) { - this.state = BASEBALL_STATE.HIT_LANDED; - print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); - print("Ball travelled " + this.distanceTravelled + " meters") + this.ballLanded(); } } else if (this.state == BASEBALL_STATE.PITCHING) { if (this.timeSincePitched > 10) { @@ -456,6 +456,15 @@ Baseball.prototype = { } } }, + ballLanded: function() { + this.state = BASEBALL_STATE.HIT_LANDED; + if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { + print("PLAYING SHOW") + playFireworkShow(50, 10000); + } + print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); + print("Ball travelled " + this.distanceTravelled + " feet") + }, collisionCallback: function(entityA, entityB, collision) { var self = this; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); @@ -525,7 +534,7 @@ Baseball.prototype = { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); if (this.state == BASEBALL_STATE.HIT) { - this.state = BASEBALL_STATE.HIT_LANDED; + this.ballLanded(); } } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { From 644e1008bd7a5ce96ed6a100a00675c497cbf3a9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 13:32:28 -0800 Subject: [PATCH 072/171] Fix bat.js not setting pitchingMachine variable --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c8857095d8..2eaf9df31f 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,11 +2,11 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { + print("Started near grab!"); if (!pitchingMachine) { - getPitchingMachine(); + pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } - print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; From 06dbe2693a5c07ab35dd419882d978444f9d6c3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:21:52 -0800 Subject: [PATCH 073/171] fix for created bat properties --- examples/baseball/createBatButton.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 0ffc9cb829..ed6f808947 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,6 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + var SCRIPT_URL = "https://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ @@ -55,7 +56,8 @@ velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add gravity: { x: 0, y: -9.81, z: 0}, rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), - userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":0,"y":0,"z":0.4617486000061035,"w":0.8870108127593994}},"kinematicGrab":true}}' + script: SCRIPT_URL, + userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' }); } }) From 501b905e7a70c03d46f653fede692efb5f9b6a26 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:25:38 -0800 Subject: [PATCH 074/171] change script URL for bat to HTTP --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index ed6f808947..6f5ae61d76 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "https://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From 5211824e0eccb29ca5c463c1f2e8c16d948dc9dd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 14:43:43 -0800 Subject: [PATCH 075/171] Fix script include paths in firework.js and pitching.js --- examples/baseball/firework.js | 2 +- examples/baseball/pitching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 8e7a9637ec..df9573d7e8 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,4 +1,4 @@ -Script.include("utils.js"); +Script.include(Script.resolvePath("utils.js")); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index dedb4ba04a..b67449b73d 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,7 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include("firework.js") +Script.include(Script.include("firework.js")); // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { From 8c0592cababc804bfa8e49821dd7fa0e5e49b1a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:52:40 -0800 Subject: [PATCH 076/171] add semicolons to createBatButton script --- examples/baseball/createBatButton.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 6f5ae61d76..6a19a30a00 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -59,5 +59,5 @@ script: SCRIPT_URL, userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' }); - } -}) + }; +}); From 804db537bf2e2556838acda205e93f1fc1ccfe3c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:11:13 -0800 Subject: [PATCH 077/171] volume changes for crowd, bat avatar suppression fix --- examples/acScripts/baseballCrowd.js | 7 +++++-- examples/baseball/bat.js | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index b0038d5865..7db93c5b34 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,9 +17,12 @@ var extras = [ SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; +var CHATTER_VOLUME = 0.10 +var EXTRA_VOLUME = 0.15 + function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { - Audio.playSound(chatter, { loop: true, volume: 0.5 }); + Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME }); } } @@ -32,7 +35,7 @@ function playRandomExtras() { // play a random extra sound about every 30s currentInjector = Audio.playSound( extras[Math.floor(Math.random() * extras.length)], - { volume: 0.33 } + { volume: EXTRA_VOLUME } ); } } diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c8857095d8..1ec85021c8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -10,6 +10,9 @@ pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; + this.continueNearGrab = function() { + MyAvatar.shouldRenderLocally = false; + } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From 5b3809b543a3e5fdb789a24814573be95022af5a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:13:14 -0800 Subject: [PATCH 078/171] update the bat script URL --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 6a19a30a00..f0320a7f75 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "https://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From 9488a8ed240ce0a7b71fe85435f8e7c362ee11b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:42:31 -0800 Subject: [PATCH 079/171] use HTTP URL for bat script URL --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index f0320a7f75..821277d6d0 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "https://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From e7bc2e349a97c4bae0568b663e228c12767250be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:55:11 -0800 Subject: [PATCH 080/171] use real userData in createBatButton script --- examples/baseball/createBatButton.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 821277d6d0..473550fdd2 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -45,6 +45,17 @@ var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var batUserData = { + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0.9, y: 0, z: 0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 0) + } + } + } + // add the fresh bat at the drop position var bat = Entities.addEntity({ name: 'Bat', @@ -57,7 +68,7 @@ gravity: { x: 0, y: -9.81, z: 0}, rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), script: SCRIPT_URL, - userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' + userData: JSON.stringify(batUserData) }); }; }); From 9ae3c8b59322c94ecc7a740f8bbb07d43ffc4b32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:58:30 -0800 Subject: [PATCH 081/171] change bat relative rotation yaw to 90 --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 473550fdd2..2465c31d55 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,7 +51,7 @@ relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 0) + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0) } } } From eb990c9c1ce383cd3a29f3b1032782a990861fad Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 17:45:01 -0800 Subject: [PATCH 082/171] More basebal test code --- interface/src/avatar/AvatarActionHold.cpp | 20 ++++----- .../input-plugins/ViveControllerManager.cpp | 42 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 767c60defe..a4fcd3689e 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -50,7 +50,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { holdingAvatar = std::static_pointer_cast(holdingAvatarData); if (holdingAvatar) { - glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; @@ -64,14 +63,16 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { const auto& vive = it->dynamicCast(); auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); - auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rot = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + palmPosition = pos + rot * vive->getPosition(index); + palmRotation = rot * vive->getRotation(index);// * viveToHand * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); } else #endif if (_hand == "right") { @@ -83,8 +84,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } rotation = palmRotation * _relativeRotation; - offset = rotation * _relativePosition; - position = palmPosition + offset; + position = palmPosition + rotation * _relativePosition; } }); diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index fb0021d7d5..317a31a794 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -35,6 +35,7 @@ extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches +const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, 2.0f * CONTROLLER_LENGTH_OFFSET); // three inches const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const QString ViveControllerManager::NAME = "OpenVR"; @@ -354,14 +355,11 @@ void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, boo } void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { - glm::vec3 position = extractTranslation(mat); - glm::quat rotation = glm::quat_cast(mat); - // When the sensor-to-world rotation is identity the coordinate axes look like this: // // user // forward - // z + // -z // | // y| user // y o----x right @@ -406,22 +404,26 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - - float sign = left ? -1.0f : 1.0f; - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - - - const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; - const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - 2.0f * CONTROLLER_LENGTH_OFFSET); - - position += rotation * translationOffset; - rotation = rotation * rotationOffset; + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + glm::vec3 position = extractTranslation(mat); + glm::quat rotation = glm::quat_cast(mat); + + position += rotation * (left ? leftTranslationOffset : rightTranslationOffset); + rotation = rotation * (left ? leftRotationOffset : rightRotationOffset); _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation); } From 3a545399e383bdd19b61874f0939c1cc5d90c125 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 17:54:58 -0800 Subject: [PATCH 083/171] Remove our idle() from paintGL now that it's in master --- interface/src/Application.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c7f46858b5..d31d9de4a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1074,10 +1074,6 @@ void Application::paintGL() { if (_inPaint) { return; } - - // this is a good idea - idle(); - _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2125,7 +2121,7 @@ void Application::idle(uint64_t now) { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - //return; // bail early, we're throttled and not enough time has elapsed + return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); From cb2a698488001d800e2d00169ebfc58c583a2d5d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 09:22:05 -0800 Subject: [PATCH 084/171] Update urls in baseball scripts to be absolute --- examples/baseball/firework.js | 2 +- examples/baseball/pitching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index df9573d7e8..1b6e621e4d 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,4 +1,4 @@ -Script.include(Script.resolvePath("utils.js")); +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index b67449b73d..9483af00bc 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,7 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include(Script.include("firework.js")); +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { From 73aa016d8caf54eb3ea7b87bc7b44e57be49b119 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:23:16 -0800 Subject: [PATCH 085/171] use rawgit URL for bat script --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 2465c31d55..69b7af859e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From ea2b9e906b9dcbf4c606339bcf863404bf615da2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:33:09 -0800 Subject: [PATCH 086/171] remove continueNearGrab from bat script --- examples/baseball/bat.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 1ec85021c8..2eaf9df31f 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,17 +2,14 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { + print("Started near grab!"); if (!pitchingMachine) { - getPitchingMachine(); + pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } - print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; - this.continueNearGrab = function() { - MyAvatar.shouldRenderLocally = false; - } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From c2b0d127f30a9739ae7717bcd96c9e3262121b07 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:33:42 -0800 Subject: [PATCH 087/171] use bat script without continued near grab --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 69b7af859e..7d09b02c17 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From 8607a1ef5064b27eacfb70b40cbcb056f6124403 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 10:22:53 -0800 Subject: [PATCH 088/171] Revert "remove continueNearGrab from bat script" This reverts commit ea2b9e906b9dcbf4c606339bcf863404bf615da2. --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 2eaf9df31f..1ec85021c8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,14 +2,17 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { - print("Started near grab!"); if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } + print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; + this.continueNearGrab = function() { + MyAvatar.shouldRenderLocally = false; + } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From ff2438ef03f04c7ca5246135cb53604b44c14e39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 10:23:06 -0800 Subject: [PATCH 089/171] use bat script that fully hides avatar --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 7d09b02c17..69b7af859e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From d5c6b0bdc0fef725502c18f1c556875ff05142ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 11:31:01 -0800 Subject: [PATCH 090/171] allow a distance grab on the create bat button --- examples/baseball/createBatButton.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 69b7af859e..b105253347 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -19,6 +19,9 @@ this.startNearGrabNonColliding = function() { this.dropBats(); }; + this.startFarGrabNonColliding = function() { + this.dropBats(); + }; this.dropBats = function() { // if the bat box is near us, grab it's position var nearby = Entities.findEntities(this.position, 20); From d0d3aaa09ccd734761aaae667a78e4e28e6fc77b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:10:19 -0800 Subject: [PATCH 091/171] Update bat.js to ensure pitching machine is running in continueNearGrab --- examples/baseball/bat.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index d142df8b86..011fdbe27a 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -11,6 +11,11 @@ MyAvatar.shouldRenderLocally = false; }; this.continueNearGrab = function() { + if (!pitchingMachine) { + pitchingMachine = getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } + pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; } this.releaseGrab = function() { From bed7a1f5c3c99c5f1f5c0962c287a7cbd9ddcc4c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:10:42 -0800 Subject: [PATCH 092/171] Improve performance of fireworks --- examples/baseball/firework.js | 85 ++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 1b6e621e4d..8fd0f977ec 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -2,24 +2,28 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; +var currentIdx = 0; +var smokeTrailEmitters = []; +var burstEmitters = []; + var smokeTrailSettings = { "name":"ParticlesTest Emitter", "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, "velocity": { x: 0, y: 18.0, z: 0 }, - "lifetime": 20, + //"lifetime": 20, "lifespan":3, "emitRate":1000, "emitSpeed":0.5, - "speedSpread":1, - "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "speedSpread":0, + "emitOrientation":{"x":0,"y":0,"z":0,"w":1}, "emitDimensions":{"x":0,"y":0,"z":0}, "emitRadiusStart":0.5, "polarStart":1, "polarFinish":1, - "azimuthStart":-Math.PI, - "azimuthFinish":Math.PI, + "azimuthStart":0, + "azimuthFinish":0, "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, "accelerationSpread":{"x":0,"y":0,"z":0}, "particleRadius":0.03999999910593033, @@ -41,8 +45,8 @@ var fireworkSettings = { "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, - "lifetime": 20, - "lifespan":6, + //"lifetime": 20, + "lifespan":4, "emitRate":1000, "emitSpeed":1.5, "speedSpread":1.0, @@ -67,7 +71,6 @@ var fireworkSettings = { "alphaStart":0, "alphaFinish":1, "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/spark_2.png", - //"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/spark.png" }; var popSounds = getSounds([ @@ -84,48 +87,41 @@ var fireSounds = getSounds([ ]) function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } Audio.playSound(sounds[randomInt(sounds.length)], options); } function shootFirework(position, color, options) { - smokeTrailSettings.position = position; - smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); - smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + var updatedSmokeProperties = { + position: position, + velocity: randomVec3(-5, 5, 10, 20, 10, 15), + gravity: randomVec3(-5, 5, -9.8, -9.8, 20, 40), + emitRate: 100 + }; + + var idx = currentIdx; + currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - var smokeID = Entities.addEntity(smokeTrailSettings); - emitters.push(smokeID); - Script.scriptEnding.connect(function() { - Entities.deleteEntity(smokeID); - }); + var smokeID = smokeTrailEmitters[idx]; + var burstID = burstEmitters[idx]; + Entities.editEntity(smokeID, updatedSmokeProperties); + Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); var position = Entities.getEntityProperties(smokeID, ['position']).position; - Vec3.print("pos", position); - options.position = position; - options.colorStart = color; - options.colorFinish = color; - var id = Entities.addEntity(options); - emitters.push(id); + var updatedBurstProperties = { + position: position, + colorStart: color, + colorFinish: color, + emitRate: 1000 + }; + Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { - Entities.editEntity(id, { emitRate: 0 }); - Entities.deleteEntity(smokeID); + Entities.editEntity(burstID, { emitRate: 0 }); }, 500); }, 2000); } -Script.scriptEnding.connect(function() { - for (var i = 0; i < emitters.lengths; ++i) { - Entities.deleteEntity(emitters[i]); - } -}); - playFireworkShow = function(numberOfFireworks, duration) { var position = { x: 0, y: 0, z: -78.0 }; @@ -141,4 +137,19 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -//playFireworkShow(50, 10000); +var MAX_SIMULTANEOUS_FIREWORKS = 50; + +smokeTrailSettings.emitRate = 0; +fireworkSettings.emitRate = 0; +for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { + smokeTrailEmitters.push(Entities.addEntity(smokeTrailSettings)); + burstEmitters.push(Entities.addEntity(fireworkSettings)); +} +Script.scriptEnding.connect(function() { + for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { + Entities.deleteEntity(smokeTrailEmitters[i]); + Entities.deleteEntity(burstEmitters[i]); + } +}); + +//playFireworkShow(30, 2000); From 8056498f39db5396beb2b15f5fc8da1c6c1cb9c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:11:07 -0800 Subject: [PATCH 093/171] Update pitching machine to shoot fewer fireworks --- examples/baseball/pitching.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9483af00bc..bc668ee12a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -74,9 +74,9 @@ var PITCHING_MACHINE_PROPERTIES = { name: "Pitching Machine", type: "Model", position: { - x: 0, + x: -0.93, y: 0.8, - z: -18.3, + z: -19.8, }, velocity: { x: 0, @@ -170,11 +170,10 @@ PitchingMachine.prototype = { print("Created baseball"); }, start: function() { - print("Starting Pitching Machine"); if (this.enabled) { - print("Already enabled") return; } + print("Starting Pitching Machine"); this.enabled = true; this.pitchBall(); }, @@ -390,6 +389,8 @@ function Baseball(position, velocity, ballScale) { this.timeSinceHit = 0; this.hitBallAtPosition = null; this.distanceTravelled = 0; + this.wasHighScore = false; + this.landed = false; // Listen for collision for the lifetime of the entity Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { @@ -422,15 +423,17 @@ function updateBillboard(distance) { if (!isNaN(distance)) { var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); var bestDistance = parseInt(properties.text); - if (distance > bestDistance) { + if (distance >= bestDistance) { Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { text: distance, }); + return true; } } + return false; } -var FIREWORK_SHOW_DISTANCE_FEET = 200; +var FIREWORK_SHOW_DISTANCE_FEET = 2; Baseball.prototype = { finished: function() { @@ -445,8 +448,9 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position) * METERS_TO_FEET; - updateBillboard(Math.ceil(this.distanceTravelled)); - if (this.timeSinceHit > 10 || speed < 1) { + var wasHighScore = updateBillboard(Math.ceil(this.distanceTravelled)); + if (this.landed || this.timeSinceHit > 10 || speed < 1) { + this.wasHighScore = wasHighScore; this.ballLanded(); } } else if (this.state == BASEBALL_STATE.PITCHING) { @@ -460,7 +464,11 @@ Baseball.prototype = { this.state = BASEBALL_STATE.HIT_LANDED; if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { print("PLAYING SHOW") - playFireworkShow(50, 10000); + var numberOfFireworks = Math.floor(this.distanceTraveled / 100); + if (this.wasHighScore) { + numberOfFireworks = 30; + } + playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); print("Ball travelled " + this.distanceTravelled + " feet") @@ -533,9 +541,7 @@ Baseball.prototype = { } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); - if (this.state == BASEBALL_STATE.HIT) { - this.ballLanded(); - } + this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; From de69b2298beb9212faf5375b5a01d54ff81a7b1f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:55:18 -0800 Subject: [PATCH 094/171] Decrease number of fireworks on high score --- examples/baseball/pitching.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index bc668ee12a..661a8786fd 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -466,7 +466,7 @@ Baseball.prototype = { print("PLAYING SHOW") var numberOfFireworks = Math.floor(this.distanceTraveled / 100); if (this.wasHighScore) { - numberOfFireworks = 30; + numberOfFireworks = 20; } playFireworkShow(numberOfFireworks, 2000); } From 2a115fc9abad7edad704f1d692a24f77f9b316b3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 13:11:20 -0800 Subject: [PATCH 095/171] Remove preallocation of particles in firework.js --- examples/baseball/firework.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 8fd0f977ec..fbb8ff8dc5 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -98,12 +98,20 @@ function shootFirework(position, color, options) { emitRate: 100 }; + smokeTrailSettings.position = position; + smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); + smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + smokeTrailSettings.emitRate = 100; + + var idx = currentIdx; currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; + playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - var smokeID = smokeTrailEmitters[idx]; - var burstID = burstEmitters[idx]; - Entities.editEntity(smokeID, updatedSmokeProperties); + //var smokeID = smokeTrailEmitters[idx]; + //var burstID = burstEmitters[idx]; + //Entities.editEntity(smokeID, updatedSmokeProperties); + var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); @@ -114,7 +122,12 @@ function shootFirework(position, color, options) { colorFinish: color, emitRate: 1000 }; - Entities.editEntity(burstID, updatedBurstProperties); + fireworkSettings.position = position; + fireworkSettings.colorStart = color; + fireworkSettings.colorFinish = color; + fireworkSettings.emitRate = 1000; + var burstID = Entities.addEntity(fireworkSettings); + //Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); @@ -137,7 +150,7 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -var MAX_SIMULTANEOUS_FIREWORKS = 50; +var MAX_SIMULTANEOUS_FIREWORKS = 0; smokeTrailSettings.emitRate = 0; fireworkSettings.emitRate = 0; From e0ad714ab71f662aafb4808104830b4371d796ba Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 13:11:34 -0800 Subject: [PATCH 096/171] Clean up print messages in pitching.js --- examples/baseball/pitching.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 661a8786fd..8bcf9d9e81 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -142,8 +142,8 @@ PitchingMachine.prototype = { print("Pitching ball"); var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); - print("PROPS"); - print("props ", JSON.stringify(machineProperties)); + //print("PROPS"); + //print("props ", JSON.stringify(machineProperties)); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); @@ -539,8 +539,8 @@ Baseball.prototype = { } } } else if (name == "stadium") { - print("PARTICLES"); - entityCollisionWithGround(entityB, this.entityID, collision); + //iprint("PARTICLES"); + //entityCollisionWithGround(entityB, this.entityID, collision); this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { From f67d4d33f4c65040d082d3ddb863b0f518401acf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 14:32:36 -0800 Subject: [PATCH 097/171] make the crowd a bit louder --- examples/acScripts/baseballCrowd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 7db93c5b34..bc8965e54d 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,8 +17,8 @@ var extras = [ SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; -var CHATTER_VOLUME = 0.10 -var EXTRA_VOLUME = 0.15 +var CHATTER_VOLUME = 0.20 +var EXTRA_VOLUME = 0.25 function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { From 4d5ed2efcf854ca55ea8a7f2eb4f973f4b903488 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 14:38:30 -0800 Subject: [PATCH 098/171] Fix fireworks not being deleted --- examples/baseball/firework.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index fbb8ff8dc5..c00e97e8e0 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -132,6 +132,10 @@ function shootFirework(position, color, options) { Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); }, 500); + Script.setTimeout(function() { + Entities.deleteEntity(smokeID); + Entities.deleteEntity(burstID); + }, 10000); }, 2000); } From 6ae4ef78dd0038cf8f5f199b5b899df930e9da19 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 14:38:48 -0800 Subject: [PATCH 099/171] Update max fireworks in pitching.js to be 10 --- examples/baseball/pitching.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8bcf9d9e81..d63dbf171d 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -464,10 +464,8 @@ Baseball.prototype = { this.state = BASEBALL_STATE.HIT_LANDED; if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { print("PLAYING SHOW") - var numberOfFireworks = Math.floor(this.distanceTraveled / 100); - if (this.wasHighScore) { - numberOfFireworks = 20; - } + var numberOfFireworks = Math.floor(this.distanceTravelled / 200); + numberOfFireworks = Math.min(10, numberOfFireworks); playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); From 1c9e3434a9d126cd4f3642a80bee1a7fc6a5ffc4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 16:01:08 -0800 Subject: [PATCH 100/171] Adjust behavior of tunnel-detection in pitching.js --- examples/baseball/pitching.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index d63dbf171d..16a88dc7b6 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -490,6 +490,8 @@ Baseball.prototype = { var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; var foul = yaw > -135 && yaw < 135; + var speedMultiplier = 2; + if (foul && myVelocity.z > 0) { var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; @@ -497,13 +499,16 @@ Baseball.prototype = { if (Math.abs(pitch) < 15) { print("Reversing hit"); myVelocity.z *= -1; + myVelocity.y *= -1; + Vec3.length(myVelocity); foul = false; + speedMultiplier = 10; } } // Update ball velocity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, myVelocity), + velocity: Vec3.multiply(speedMultiplier, myVelocity), }); // Setup line update interval From 5d2df1abbb3bc6e5b0de16d46e2f53e91649e724 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 09:55:18 -0800 Subject: [PATCH 101/171] Add helped function findEntity --- examples/baseball/pitching.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 16a88dc7b6..81a5b22de2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -3,6 +3,11 @@ print("Loading pitching"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); +function findEntity(properties, searchRadius) { + var entities = findEntities(properties, searchRadius); + return entities.length > 0 ? entities[0] : null; +} + // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); @@ -26,11 +31,11 @@ function findEntities(properties, searchRadius) { return matchedEntities; } -// These are hard-coded to the relevant entity IDs on the sport server var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; -var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); + print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; From 7da611d44b14a7a28217828753318291a4b676af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:03:57 -0800 Subject: [PATCH 102/171] Adjust fireworks configuration in pitching.js --- examples/baseball/pitching.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 81a5b22de2..d8ae3d1a34 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -438,7 +438,8 @@ function updateBillboard(distance) { return false; } -var FIREWORK_SHOW_DISTANCE_FEET = 2; +var FIREWORK_PER_X_FEET = 100; +var MAX_FIREWORKS = 10; Baseball.prototype = { finished: function() { @@ -467,10 +468,9 @@ Baseball.prototype = { }, ballLanded: function() { this.state = BASEBALL_STATE.HIT_LANDED; - if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { - print("PLAYING SHOW") - var numberOfFireworks = Math.floor(this.distanceTravelled / 200); - numberOfFireworks = Math.min(10, numberOfFireworks); + var numberOfFireworks = Math.floor(this.distanceTravelled / FIREWORK_PER_X_FEET); + if (numberOfFireworks > 0) { + numberOfFireworks = Math.min(MAX_FIREWORKS, numberOfFireworks); playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); From d5336db039bd4b890f1af76b3d0131fcb11d00df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:04:19 -0800 Subject: [PATCH 103/171] Cleanup print statements in pitching.js --- examples/baseball/pitching.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index d8ae3d1a34..3060b203fd 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -68,6 +68,7 @@ var AUDIO = { var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); +updateBillboard(""); var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { @@ -147,22 +148,17 @@ PitchingMachine.prototype = { print("Pitching ball"); var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); - //print("PROPS"); - //print("props ", JSON.stringify(machineProperties)); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); var pitchDirection = Quat.getFront(machineProperties.rotation); var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; - print("Creating baseball"); var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED); var velocity = Vec3.multiply(speed, pitchDirection); this.baseball = new Baseball(pitchFromPosition, velocity, ballScale); - Vec3.print("vel", velocity); - Vec3.print("pos", pitchFromPosition); if (!this.injector) { this.injector = Audio.playSound(pitchSound, { @@ -193,7 +189,6 @@ PitchingMachine.prototype = { if (this.baseball) { this.baseball.update(dt); if (this.baseball.finished()) { - print("BALL IS FINISHED"); this.baseball = null; var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); @@ -316,7 +311,6 @@ function ObjectTrail(entityID, startPosition) { this.line = null; var lineInterval = null; - print("Creating Trail!"); var lastPosition = startPosition; trail = new InfiniteLine(startPosition, trailColor, trailLifetime); trailInterval = Script.setInterval(function() { @@ -356,7 +350,6 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); - print("Creating Trail!"); var lastPosition = position; trail = new InfiniteLine(position, { red: 128, green: 255, blue: 89 }, 20); trailInterval = Script.setInterval(function() { @@ -488,7 +481,6 @@ Baseball.prototype = { }); var name = Entities.getEntityProperties(entityB, ["name"]).name; - print("Hit: " + name); if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); @@ -533,9 +525,10 @@ Baseball.prototype = { volume: 1.0 }); }, 500); + if (foul) { + print("FOUL, yaw: ", yaw); updateBillboard("FOUL"); - print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { position: myPosition, @@ -547,14 +540,13 @@ Baseball.prototype = { } } } else if (name == "stadium") { - //iprint("PARTICLES"); //entityCollisionWithGround(entityB, this.entityID, collision); this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { + print("STRIKE"); this.state = BASEBALL_STATE.STRIKE; updateBillboard("STRIKE"); - print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, volume: 2.0 @@ -570,7 +562,6 @@ function update(dt) { if (baseball) { baseball.update(dt); if (baseball.finished()) { - print("BALL IS FINSIEHD"); baseball = null; Script.setTimeout(pitchBall, 3000); } From 94bf2ecf275e9629641dfe03c9a797b4cea4a766 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:45:22 -0800 Subject: [PATCH 104/171] Remove emitter pool from firework.js --- examples/baseball/firework.js | 48 +++++------------------------------ 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index c00e97e8e0..c8b58462fa 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -3,8 +3,6 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; var currentIdx = 0; -var smokeTrailEmitters = []; -var burstEmitters = []; var smokeTrailSettings = { "name":"ParticlesTest Emitter", @@ -12,9 +10,9 @@ var smokeTrailSettings = { "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, "velocity": { x: 0, y: 18.0, z: 0 }, - //"lifetime": 20, + "lifetime": 20, "lifespan":3, - "emitRate":1000, + "emitRate":100, "emitSpeed":0.5, "speedSpread":0, "emitOrientation":{"x":0,"y":0,"z":0,"w":1}, @@ -45,7 +43,7 @@ var fireworkSettings = { "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, - //"lifetime": 20, + "lifetime": 20, "lifespan":4, "emitRate":1000, "emitSpeed":1.5, @@ -79,55 +77,36 @@ var popSounds = getSounds([ "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav", "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" ]); + var fireSounds = getSounds([ "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav" -]) +]); function playRandomSound(sounds, options) { Audio.playSound(sounds[randomInt(sounds.length)], options); } function shootFirework(position, color, options) { - var updatedSmokeProperties = { - position: position, - velocity: randomVec3(-5, 5, 10, 20, 10, 15), - gravity: randomVec3(-5, 5, -9.8, -9.8, 20, 40), - emitRate: 100 - }; - smokeTrailSettings.position = position; smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - smokeTrailSettings.emitRate = 100; - var idx = currentIdx; currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - //var smokeID = smokeTrailEmitters[idx]; - //var burstID = burstEmitters[idx]; - //Entities.editEntity(smokeID, updatedSmokeProperties); var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); var position = Entities.getEntityProperties(smokeID, ['position']).position; - var updatedBurstProperties = { - position: position, - colorStart: color, - colorFinish: color, - emitRate: 1000 - }; fireworkSettings.position = position; fireworkSettings.colorStart = color; fireworkSettings.colorFinish = color; - fireworkSettings.emitRate = 1000; var burstID = Entities.addEntity(fireworkSettings); - //Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); @@ -154,19 +133,4 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -var MAX_SIMULTANEOUS_FIREWORKS = 0; - -smokeTrailSettings.emitRate = 0; -fireworkSettings.emitRate = 0; -for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { - smokeTrailEmitters.push(Entities.addEntity(smokeTrailSettings)); - burstEmitters.push(Entities.addEntity(fireworkSettings)); -} -Script.scriptEnding.connect(function() { - for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { - Entities.deleteEntity(smokeTrailEmitters[i]); - Entities.deleteEntity(burstEmitters[i]); - } -}); - -//playFireworkShow(30, 2000); +playFireworkShow(10, 2000); From fbb47ecddab8ef23735e85f388c51dee47c1bb99 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 11:39:46 -0800 Subject: [PATCH 105/171] Remove hard-coded fireworks position from firework.js --- examples/baseball/firework.js | 4 +--- examples/baseball/pitching.js | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index c8b58462fa..9e4e8d01a7 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -118,9 +118,7 @@ function shootFirework(position, color, options) { }, 2000); } -playFireworkShow = function(numberOfFireworks, duration) { - var position = { x: 0, y: 0, z: -78.0 }; - +playFireworkShow = function(position, numberOfFireworks, duration) { for (var i = 0; i < numberOfFireworks; i++) { var randomOffset = randomVec3(-15, 15, -3, 3, -1, 1); var randomPosition = Vec3.sum(position, randomOffset); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 3060b203fd..dc0a4e9169 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -431,6 +431,7 @@ function updateBillboard(distance) { return false; } +var FIREWORKS_SHOW_POSITION = { x: 0, y: 0, z: -78.0 }; var FIREWORK_PER_X_FEET = 100; var MAX_FIREWORKS = 10; @@ -464,7 +465,7 @@ Baseball.prototype = { var numberOfFireworks = Math.floor(this.distanceTravelled / FIREWORK_PER_X_FEET); if (numberOfFireworks > 0) { numberOfFireworks = Math.min(MAX_FIREWORKS, numberOfFireworks); - playFireworkShow(numberOfFireworks, 2000); + playFireworkShow(FIREWORKS_SHOW_POSITION, numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); print("Ball travelled " + this.distanceTravelled + " feet") From 4cce57881f122308ca8f4620fec754a916d3f347 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:24:19 -0800 Subject: [PATCH 106/171] Remove MAX_SIMULTANEOUS_FIREWORKS from firework.js --- examples/baseball/firework.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 9e4e8d01a7..a3db59e533 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -2,8 +2,6 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; -var currentIdx = 0; - var smokeTrailSettings = { "name":"ParticlesTest Emitter", "type": "ParticleEffect", @@ -94,9 +92,6 @@ function shootFirework(position, color, options) { smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - var idx = currentIdx; - currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; - playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); var smokeID = Entities.addEntity(smokeTrailSettings); From 42e2c683fdf7c2b39d20f85b69ffb5cecbd799af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:24:52 -0800 Subject: [PATCH 107/171] Rename fireSounds to launchSounds --- examples/baseball/firework.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index a3db59e533..49c4093082 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -76,7 +76,7 @@ var popSounds = getSounds([ "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" ]); -var fireSounds = getSounds([ +var launchSounds = getSounds([ "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", @@ -92,7 +92,7 @@ function shootFirework(position, color, options) { smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + playRandomSound(launchSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { From c964363ce53d7ca8121166f641925410d6ec26f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:25:13 -0800 Subject: [PATCH 108/171] Disable automatic playing of show in firework.js --- examples/baseball/firework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 49c4093082..fee8aa8e35 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -126,4 +126,4 @@ playFireworkShow = function(position, numberOfFireworks, duration) { } } -playFireworkShow(10, 2000); +//playFireworkShow(10, 2000); From 51b14386a09774d2b3e6de73f87e1839e751108c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:08:35 -0800 Subject: [PATCH 109/171] Adjust baseball pitch speed to 5-20 m/s --- examples/baseball/pitching.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index dc0a4e9169..11b60cbfa1 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -198,8 +198,8 @@ PitchingMachine.prototype = { }; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_MIN_SPEED = 2.7; -var BASEBALL_MAX_SPEED = 5.7; +var BASEBALL_MIN_SPEED = 5.0; +var BASEBALL_MAX_SPEED = 20.0; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", From bc035b7e1e83ffe3fa430157f09581c26dff9ddc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:29:57 -0800 Subject: [PATCH 110/171] Adjust baseball speed to 7-15 m/s --- examples/baseball/pitching.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 11b60cbfa1..698810b87f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -198,8 +198,8 @@ PitchingMachine.prototype = { }; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_MIN_SPEED = 5.0; -var BASEBALL_MAX_SPEED = 20.0; +var BASEBALL_MIN_SPEED = 7.0; +var BASEBALL_MAX_SPEED = 15.0; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", From e145d4955cd9b0d2fbaf8586c5c84d384e837cca Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:30:16 -0800 Subject: [PATCH 111/171] Update tunnel detection to reverse all axes --- examples/baseball/pitching.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 698810b87f..05f108b165 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -496,8 +496,9 @@ Baseball.prototype = { print("Pitch: ", pitch); if (Math.abs(pitch) < 15) { print("Reversing hit"); - myVelocity.z *= -1; + myVelocity.x *= -1; myVelocity.y *= -1; + myVelocity.z *= -1; Vec3.length(myVelocity); foul = false; speedMultiplier = 10; From 30841169ee2e293f48d4c9a46d91288a33de6f2b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:04:19 -0800 Subject: [PATCH 112/171] Move functions in baseball.js to utils.js --- examples/baseball/pitching.js | 58 +---------------------------------- examples/baseball/utils.js | 46 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 57 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 05f108b165..fe585d4f4a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,34 +2,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); - -function findEntity(properties, searchRadius) { - var entities = findEntities(properties, searchRadius); - return entities.length > 0 ? entities[0] : null; -} - -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; @@ -247,35 +220,6 @@ var BASEBALL_STATE = { }; -function shallowCopy(obj) { - var copy = {} - for (var key in obj) { - copy[key] = obj[key]; - } - return copy; -} - -function randomInt(low, high) { - return Math.floor(randomFloat(low, high)); -} - -function randomFloat(low, high) { - if (high === undefined) { - high = low; - low = 0; - } - return low + Math.random() * (high - low); -} - -function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } - Audio.playSound(sounds[randomInt(sounds.length)], options); -} function vec3Mult(a, b) { return { diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js index 7266666cc9..f128797345 100644 --- a/examples/baseball/utils.js +++ b/examples/baseball/utils.js @@ -33,3 +33,49 @@ getSounds = function(soundURLs) { } return sounds; }; + +playRandomSound = function(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + return Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +shallowCopy = function(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +findEntity = function(properties, searchRadius) { + var entities = findEntities(properties, searchRadius); + return entities.length > 0 ? entities[0] : null; +} + +// Return all entities with properties `properties` within radius `searchRadius` +findEntities = function(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} From 20bdc7ee85a414b3e6cbc864ffb66405da05e790 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:10:59 -0800 Subject: [PATCH 113/171] Rename getPitchingMachine to getOrCreatePitchingMachine --- examples/baseball/bat.js | 4 ++-- examples/baseball/pitching.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 011fdbe27a..98ad8b7bf4 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -4,7 +4,7 @@ this.startNearGrab = function() { print("Started near grab!"); if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); @@ -12,7 +12,7 @@ }; this.continueNearGrab = function() { if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index fe585d4f4a..93c114baa4 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -80,14 +80,14 @@ var PITCHING_MACHINE_PROPERTIES = { z: 0.39 }, collisionsWillMove: false, - shapeType: "Box", + shapeType: "Box" }; PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -getPitchingMachine = function() { +getOrCreatePitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; From ec31504c1178c0c9a73b7ae6a5987cfa01188aa9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:30:21 -0800 Subject: [PATCH 114/171] Add detection of missing entity billboards in pitching.js --- examples/baseball/pitching.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 93c114baa4..0e6fe0b61f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -9,7 +9,12 @@ var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); -print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) +if (DISTANCE_BILLBOARD_ENTITY_ID === null) { + print("WARNING: Distance billboard cannot be found."); +} +if (HIGH_SCORE_BILLBOARD_ENTITY_ID === null) { + print("WARNING: High Score billboard cannot be found."); +} var METERS_TO_FEET = 3.28084; From b6d26862fd2fc303d9bfebd3d7cd19b9ef83f0bb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:33:07 -0800 Subject: [PATCH 115/171] Add headers to baseball script files --- examples/baseball/bat.js | 11 +++++++++++ examples/baseball/firework.js | 11 +++++++++++ examples/baseball/pitching.js | 11 +++++++++++ examples/baseball/utils.js | 11 +++++++++++ 4 files changed, 44 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 98ad8b7bf4..eedda1e82a 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,3 +1,14 @@ +// +// bat.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + (function() { Script.include("pitching.js"); var pitchingMachine = null; diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index fee8aa8e35..89287c5a8b 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,3 +1,14 @@ +// +// firework.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 0e6fe0b61f..f8d5eba137 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,3 +1,14 @@ +// +// pitching.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js index f128797345..80f4c62f32 100644 --- a/examples/baseball/utils.js +++ b/examples/baseball/utils.js @@ -1,3 +1,14 @@ +// +// utils.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + randomInt = function(low, high) { return Math.floor(randomFloat(low, high)); }; From 1b3d595d1e9063697d894fc132fdecf99a610a1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:58:18 -0800 Subject: [PATCH 116/171] Add comment to PITCHING_MACHINE_OUTPUT_OFFSET_PCT --- examples/baseball/pitching.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index f8d5eba137..8fdb53dcdc 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -60,6 +60,11 @@ var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); updateBillboard(""); var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; +// This defines an offset to pitch a ball from with respect to the machine's position. The offset is a +// percentage of the machine's dimensions. So, { x: 0.5, y: -1.0, z: 0.0 } would offset on 50% on the +// machine's x axis, -100% on the y axis, and 0% on the z-axis. For the dimensions { x: 100, y: 100, z: 100 }, +// that would result in an offset of { x: 50, y: -100, z: 0 }. This makes it easy to calculate an offset if +// the machine's dimensions change. var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { x: 0.0, y: 0.25, From dad3ccb238a2d29d3fa7ea19101ca0cbcae359af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:58:36 -0800 Subject: [PATCH 117/171] Cleanup pitching.js --- examples/baseball/pitching.js | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8fdb53dcdc..7cb8abba33 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -76,7 +76,7 @@ var PITCHING_MACHINE_PROPERTIES = { position: { x: -0.93, y: 0.8, - z: -19.8, + z: -19.8 }, velocity: { x: 0, @@ -91,7 +91,7 @@ var PITCHING_MACHINE_PROPERTIES = { registrationPoint: { x: 0.5, y: 0.5, - z: 0.5, + z: 0.5 }, rotation: Quat.fromPitchYawRollDegrees(0, 180, 0), modelURL: PITCHING_MACHINE_URL, @@ -124,6 +124,8 @@ getOrCreatePitchingMachine = function() { return new PitchingMachine(pitchingMachineID); } +// The pitching machine wraps an entity ID and uses it's position & rotation to determin where to +// pitch the ball from and in which direction, and uses the dimensions to determine the scale of them ball. function PitchingMachine(pitchingMachineID) { this.pitchingMachineID = pitchingMachineID; this.enabled = false; @@ -271,35 +273,6 @@ var ACCELERATION_SPREAD = 0.35; var TRAIL_COLOR = { red: 128, green: 255, blue: 89 }; var TRAIL_LIFETIME = 20; -function ObjectTrail(entityID, startPosition) { - this.entityID = entityID; - this.line = null; - var lineInterval = null; - - var lastPosition = startPosition; - trail = new InfiniteLine(startPosition, trailColor, trailLifetime); - trailInterval = Script.setInterval(function() { - var properties = Entities.getEntityProperties(entityID, ['position']); - if (Vec3.distance(properties.position, lastPosition)) { - var strokeWidth = Math.log(1 + trail.size) * 0.05; - trail.enqueuePoint(properties.position, strokeWidth); - lastPosition = properties.position; - } - }, 50); -} - -ObjectTrail.prototype = { - destroy: function() { - if (this.line) { - Script.clearInterval(this.lineInterval); - this.lineInterval = null; - - this.line.destroy(); - this.line = null; - } - } -}; - var trail = null; var trailInterval = null; function cleanupTrail() { From 661b2180f57d313b6221067cc60c5770a7fd1a47 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:59:31 -0800 Subject: [PATCH 118/171] Update updateBillboard argument --- examples/baseball/pitching.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 7cb8abba33..8d33d25fd3 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -347,21 +347,21 @@ function Baseball(position, velocity, ballScale) { } } -// Update the stadium billboard with the current distance and update the high score +// Update the stadium billboard with the current distance or a text message and update the high score // if it has been beaten. -function updateBillboard(distance) { +function updateBillboard(distanceOrMessage) { Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: distance, + text: distanceOrMessage, }); // If a number was passed in, let's see if it is larger than the current high score // and update it if so. - if (!isNaN(distance)) { + if (!isNaN(distanceOrMessage)) { var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); var bestDistance = parseInt(properties.text); - if (distance >= bestDistance) { + if (distanceOrMessage >= bestDistance) { Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { - text: distance, + text: distanceOrMessage, }); return true; } From 38fcdc3efff404d50170165157fb3e63360094a7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:59:46 -0800 Subject: [PATCH 119/171] Remove unused code from pitching.js --- examples/baseball/pitching.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8d33d25fd3..e749310b9b 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -498,16 +498,6 @@ Baseball.prototype = { var baseball = null; -function update(dt) { - if (baseball) { - baseball.update(dt); - if (baseball.finished()) { - baseball = null; - Script.setTimeout(pitchBall, 3000); - } - } -} - function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -547,9 +537,4 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -//Script.update.connect(update); -//var pitchingMachine = getPitchingMachine(); -//pitchingMachine.pitchBall(); -//Script.update.connect(function(dt) { pitchingMachine.update(dt); }); - print("Done loading pitching.js"); From a5c7269096f1b57c02865251b2cb0fc6737f85e4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 11:28:02 -0800 Subject: [PATCH 120/171] Use make_shared --- interface/src/InterfaceActionFactory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 67b3b4a649..8ace11c0a0 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -21,17 +21,17 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) { switch (type) { case ACTION_TYPE_NONE: - return nullptr; + return EntityActionPointer(); case ACTION_TYPE_OFFSET: - return (EntityActionPointer) new ObjectActionOffset(id, ownerEntity); + return std::make_shared(id, ownerEntity); case ACTION_TYPE_SPRING: - return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); + return std::make_shared(id, ownerEntity); case ACTION_TYPE_HOLD: - return (EntityActionPointer) new AvatarActionHold(id, ownerEntity); + return std::make_shared(id, ownerEntity); } - assert(false); - return nullptr; + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type"); + return EntityActionPointer(); } From 278c921a50031ed8d85d7ce48665d7643163d9dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 11:35:56 -0800 Subject: [PATCH 121/171] Clean up bat.js --- examples/baseball/bat.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index eedda1e82a..5ca41b6c64 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("pitching.js"); + (function() { - Script.include("pitching.js"); var pitchingMachine = null; - this.startNearGrab = function() { - print("Started near grab!"); + + this.startNearGrab = this.continueNearGrab = function() { if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); @@ -21,16 +22,8 @@ pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; - this.continueNearGrab = function() { - if (!pitchingMachine) { - pitchingMachine = getOrCreatePitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); - } - pitchingMachine.start(); - MyAvatar.shouldRenderLocally = false; - } + this.releaseGrab = function() { - print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } From 069284d8d192961194d3f7da591b404f8a83c50e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 11:51:08 -0800 Subject: [PATCH 122/171] Remove unused variable and print in pitching.js --- examples/baseball/pitching.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index e749310b9b..1b633081d5 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -496,8 +496,6 @@ Baseball.prototype = { } } -var baseball = null; - function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -536,5 +534,3 @@ Script.scriptEnding.connect(function() { cleanupTrail(); Entities.deleteEntity(pitchingMachineID); }); - -print("Done loading pitching.js"); From 5d4ce6aefcbce7046eab40e25bd66049ba7d6fb3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 12:02:10 -0800 Subject: [PATCH 123/171] Update include paths in pitching.js to be relative --- examples/baseball/pitching.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 1b633081d5..acba31cc3f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -10,13 +10,14 @@ // print("Loading pitching"); -//Script.include("../libraries/line.js"); -Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); + +Script.include("../libraries/line.js"); +Script.include("firework.js"); +Script.include("utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; + var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); From a400d639604c468aeb08e11075f86c12fccaf856 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 12:02:28 -0800 Subject: [PATCH 124/171] Cleanup Baseball in pitching.js --- examples/baseball/pitching.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index acba31cc3f..db90d6658a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -143,7 +143,6 @@ PitchingMachine.prototype = { } print("Pitching ball"); - var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -165,7 +164,6 @@ PitchingMachine.prototype = { } else { this.injector.restart(); } - print("Created baseball"); }, start: function() { if (this.enabled) { @@ -188,7 +186,7 @@ PitchingMachine.prototype = { if (this.baseball.finished()) { this.baseball = null; var self = this; - Script.setTimeout(function() { self.pitchBall() }, 3000); + Script.setTimeout(function() { self.pitchBall(); }, 3000); } } } @@ -424,29 +422,38 @@ Baseball.prototype = { if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); + + var FOUL_MIN_YAW = -135.0; + var FOUL_MAX_YAW = 135.0; + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; - var foul = yaw > -135 && yaw < 135; + var foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW; var speedMultiplier = 2; if (foul && myVelocity.z > 0) { + var TUNNELED_PITCH_RANGE = 15.0; var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; print("Pitch: ", pitch); - if (Math.abs(pitch) < 15) { + // If the pitch is going straight out the back and has a pitch in the range TUNNELED_PITCH_RANGE, + // let's assume the ball tunneled through the bat and reverse its direction. + if (Math.abs(pitch) < TUNNELED_PITCH_RANGE) { print("Reversing hit"); myVelocity.x *= -1; myVelocity.y *= -1; myVelocity.z *= -1; - Vec3.length(myVelocity); - foul = false; - speedMultiplier = 10; + + yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW; + + speedMultiplier = 3; } } // Update ball velocity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(speedMultiplier, myVelocity), + velocity: Vec3.multiply(speedMultiplier, myVelocity) }); // Setup line update interval From 9ec51d822e518ae677ef677ae9a4d638dd5df580 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:35:54 -0800 Subject: [PATCH 125/171] send the avatar to /baseball on bat pickup --- examples/baseball/bat.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 5ca41b6c64..c7e3d8ebfb 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -15,6 +15,9 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = this.continueNearGrab = function() { + // send the avatar to the baseball location so that they're ready to bat + MyAvatar.location = "/baseball" + if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); From d65571ea41aaab67653c88e13767fc63a9a3da46 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:36:18 -0800 Subject: [PATCH 126/171] use the birarda baseball script on the createBatButton --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index b105253347..81bcaed089 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -46,7 +46,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From 962881ad31725c3e3b2c8f2741215ff3c5a3f2a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:43:52 -0800 Subject: [PATCH 127/171] use startNearTrigger and startFarTrigger for create button --- examples/baseball/createBatButton.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 81bcaed089..2a462bca65 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -16,10 +16,10 @@ } this.dropBats(); }; - this.startNearGrabNonColliding = function() { + this.startNearTrigger = function() { this.dropBats(); }; - this.startFarGrabNonColliding = function() { + this.startFarTrigger = function() { this.dropBats(); }; this.dropBats = function() { From cea2e0fafdd9dec22abb4ee6fd1f26d3a93b6fd6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 14:21:14 -0800 Subject: [PATCH 128/171] don't force location in continueNearGrab --- examples/baseball/bat.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c7e3d8ebfb..a4509c53d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -14,18 +14,26 @@ Script.include("pitching.js"); (function() { var pitchingMachine = null; - this.startNearGrab = this.continueNearGrab = function() { - // send the avatar to the baseball location so that they're ready to bat - MyAvatar.location = "/baseball" - + this.pitchAndHideAvatar = function() { if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; + } + + this.startNearGrab = function() { + // send the avatar to the baseball location so that they're ready to bat + MyAvatar.location = "/baseball" + + pitchAndHideAvatar() }; + this.continueNearGrab = function() { + pitchAndHideAvatar() + } + this.releaseGrab = function() { if (pitchingMachine) { pitchingMachine.stop(); From 4ab653610914063c4c89e0880711e73d56cdb276 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 15:06:43 -0800 Subject: [PATCH 129/171] Fix Vive dynamic pointer cast compile error on Windows --- interface/src/avatar/AvatarActionHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index d2842e325b..31e33a9b22 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -60,7 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { }); if (it != std::end(plugins)) { - const auto& vive = it->dynamicCast(); + const auto& vive = std::dynamic_pointer_cast(*it); auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); From 244fd86d1e4cbeed52e29413ce9249ea882f7de1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:31:53 -0800 Subject: [PATCH 130/171] add semi-colons to bat.js --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index a4509c53d8..0b0902d67e 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -21,7 +21,7 @@ Script.include("pitching.js"); } pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; - } + }; this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat @@ -32,7 +32,7 @@ Script.include("pitching.js"); this.continueNearGrab = function() { pitchAndHideAvatar() - } + }; this.releaseGrab = function() { if (pitchingMachine) { From 44ab236673af5cc4dc3f49872f3ccc3eee369b69 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:33:23 -0800 Subject: [PATCH 131/171] Fix include in bat.js --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 0b0902d67e..d259b99f32 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -9,9 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("pitching.js"); - (function() { + Script.include("pitching.js"); + var pitchingMachine = null; this.pitchAndHideAvatar = function() { From b6c4ae757bd4f8f0b3e567e0d10bb2ad0dd1b2e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:41:11 -0800 Subject: [PATCH 132/171] fix reference to pitchAndHideAvatar --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index d259b99f32..7c69e3c590 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -27,11 +27,11 @@ // send the avatar to the baseball location so that they're ready to bat MyAvatar.location = "/baseball" - pitchAndHideAvatar() + this.pitchAndHideAvatar() }; this.continueNearGrab = function() { - pitchAndHideAvatar() + this.pitchAndHideAvatar() }; this.releaseGrab = function() { From 57b4302e0df519bdd171f43f80f8146e256463c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:44:23 -0800 Subject: [PATCH 133/171] Fix setting of location in bat.js --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 7c69e3c590..164a6bb2e4 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -25,7 +25,7 @@ this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat - MyAvatar.location = "/baseball" + Window.location = "/baseball" this.pitchAndHideAvatar() }; From 0b1ecdec740a589992083d8a236e0150f587cab2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:49:54 -0800 Subject: [PATCH 134/171] use just location to go to path --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 164a6bb2e4..40c3d43670 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -25,7 +25,7 @@ this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat - Window.location = "/baseball" + location = "/baseball" this.pitchAndHideAvatar() }; From b3cdee278a37f84443140543e140f772347a7135 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 16:14:18 -0800 Subject: [PATCH 135/171] Different approach for bat positionning --- interface/src/avatar/AvatarActionHold.cpp | 52 ++++++++++++----------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 31e33a9b22..b230138110 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,9 +35,7 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } -#include -#include -#include + void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -53,28 +51,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; -#ifdef Q_OS_WIN - const auto& plugins = PluginManager::getInstance()->getInputPlugins(); - auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { - return plugin->getName() == ViveControllerManager::NAME; - }); - - if (it != std::end(plugins)) { - const auto& vive = std::dynamic_pointer_cast(*it); - auto index = (_hand == "left") ? 0 : 1; - auto userInputMapper = DependencyManager::get(); - auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rot = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - palmPosition = pos + rot * vive->getPosition(index); - palmRotation = rot * vive->getRotation(index);// * viveToHand * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); - } else -#endif if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); @@ -83,6 +59,32 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getLeftPalmRotation(); } + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + if (_hand == "left") { + _relativeRotation = leftRotationOffset; + _relativePosition = glm::inverse(_relativeRotation) * leftTranslationOffset; + } else { + _relativeRotation = rightRotationOffset; + _relativePosition = glm::inverse(_relativeRotation) * rightTranslationOffset; + } + rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; } From 03dd234253a7b9c1aaebbddbee4509ebd6ddc1e9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 16:48:54 -0800 Subject: [PATCH 136/171] Update pitching.js to get billboard ids lazily --- examples/baseball/pitching.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index db90d6658a..62492c9563 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -18,14 +18,20 @@ Script.include("utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; -var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); -var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); +var distanceBillboardEntityID = null; +var highScoreBillboardEntityID = null; -if (DISTANCE_BILLBOARD_ENTITY_ID === null) { - print("WARNING: Distance billboard cannot be found."); +function getDistanceBillboardEntityID() { + if (distanceBillboardEntityID === null) { + distanceBillboardEntityID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); + } + return distanceBillboardEntityID; } -if (HIGH_SCORE_BILLBOARD_ENTITY_ID === null) { - print("WARNING: High Score billboard cannot be found."); +function getHighScoreBillboardEntityID() { + if (highScoreBillboardEntityID === null) { + highScoreBillboardEntityID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); + } + return highScoreBillboardEntityID; } var METERS_TO_FEET = 3.28084; @@ -349,17 +355,21 @@ function Baseball(position, velocity, ballScale) { // Update the stadium billboard with the current distance or a text message and update the high score // if it has been beaten. function updateBillboard(distanceOrMessage) { - Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: distanceOrMessage, - }); + var distanceBillboardEntityID = getDistanceBillboardEntityID(); + if (distanceBillboardEntityID) { + Entities.editEntity(distanceBillboardEntityID, { + text: distanceOrMessage + }); + } + var highScoreBillboardEntityID = getHighScoreBillboardEntityID; // If a number was passed in, let's see if it is larger than the current high score // and update it if so. - if (!isNaN(distanceOrMessage)) { - var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); + if (!isNaN(distanceOrMessage) && highScoreBillboardEntityID) { + var properties = Entities.getEntityProperties(highScoreBillboardEntityID, ["text"]); var bestDistance = parseInt(properties.text); if (distanceOrMessage >= bestDistance) { - Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { + Entities.editEntity(highScoreBillboardEntityID, { text: distanceOrMessage, }); return true; From 765bca9a7b9b0c1a4b7ff86a224172c367c4a10c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 18:05:45 -0800 Subject: [PATCH 137/171] Work on hold action --- interface/src/avatar/AvatarActionHold.cpp | 110 +++++++++++++--------- 1 file changed, 64 insertions(+), 46 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b230138110..9384cc2216 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -51,61 +51,79 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); + bool ignoreIK = true; + if (ignoreIK) { + if (_hand == "right") { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); + } else { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); + } } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - - static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches - static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; - - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - if (_hand == "left") { - _relativeRotation = leftRotationOffset; - _relativePosition = glm::inverse(_relativeRotation) * leftTranslationOffset; - } else { - _relativeRotation = rightRotationOffset; - _relativePosition = glm::inverse(_relativeRotation) * rightTranslationOffset; + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } } + /* + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + glm::quat relRot = glm::inverse(rightRotationOffset); + glm::vec3 relPos = -rightTranslationOffset; + relRot = palmRotation * relRot; + relPos = palmPosition + relRot * relPos; + + rotation = relRot * _relativeRotation; + position = relPos + rotation * _relativePosition; + glm::quat diffRot = glm::inverse(palmRotation) * rotation; + glm::vec3 diffPos = glm::inverse(rotation) * (position - palmPosition); + qDebug() << "diffRot =" << safeEulerAngles(diffRot); + qDebug() << "diffPos =" << diffPos; + */ + //[11 / 09 17:40 : 14] [DEBUG] diffRot = { type = 'glm::vec3', x = 3.14159, y = 9.04283e-09, z = 0.785398 } + //[11 / 09 17:40 : 14][DEBUG] diffPos = { type = 'glm::vec3', x = 1.0524, y = -0.0381001, z = -0.0380997 } + //_relativeRotation = glm::quat(glm::vec3(3.14159f, 0.0f, 0.785398)); + //_relativePosition = glm::vec3(1.0524, -0.0381001, -0.0380997); rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; } }); - if (holdingAvatar) { + if (holdingAvatar && gotLock) { + gotLock = withTryWriteLock([&]{ + _positionalTarget = position; + _rotationalTarget = rotation; + _positionalTargetSet = true; + _rotationalTargetSet = true; + _active = true; + }); if (gotLock) { - gotLock = withTryWriteLock([&]{ - _positionalTarget = position; - _rotationalTarget = rotation; - _positionalTargetSet = true; - _rotationalTargetSet = true; - _active = true; - }); - if (gotLock) { - if (_kinematic) { - doKinematicUpdate(deltaTimeStep); - } else { - activateBody(); - ObjectActionSpring::updateActionWorker(deltaTimeStep); - } + if (_kinematic) { + doKinematicUpdate(deltaTimeStep); + } else { + activateBody(); + ObjectActionSpring::updateActionWorker(deltaTimeStep); } } } From 7050139a56bcd90c32b4e592e8561b7017647ac2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 13:41:19 -0800 Subject: [PATCH 138/171] Bit of code cleanup --- interface/src/avatar/AvatarActionHold.cpp | 21 ++++++++----------- interface/src/avatar/AvatarActionHold.h | 7 ++++--- .../input-plugins/ViveControllerManager.cpp | 18 +++++++++------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 9384cc2216..12759d5208 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -9,31 +9,28 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "QVariantGLM.h" +#include "AvatarActionHold.h" + +#include + #include "avatar/MyAvatar.h" #include "avatar/AvatarManager.h" -#include "AvatarActionHold.h" - const uint16_t AvatarActionHold::holdVersion = 1; AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) : - ObjectActionSpring(id, ownerEntity), - _relativePosition(glm::vec3(0.0f)), - _relativeRotation(glm::quat()), - _hand("right"), - _holderID(QUuid()) + ObjectActionSpring(id, ownerEntity) { _type = ACTION_TYPE_HOLD; - #if WANT_DEBUG +#if WANT_DEBUG qDebug() << "AvatarActionHold::AvatarActionHold"; - #endif +#endif } AvatarActionHold::~AvatarActionHold() { - #if WANT_DEBUG +#if WANT_DEBUG qDebug() << "AvatarActionHold::~AvatarActionHold"; - #endif +#endif } void AvatarActionHold::updateActionWorker(float deltaTimeStep) { diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 15a096d1ce..ec1df2f0e0 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -35,12 +35,13 @@ public: private: static const uint16_t holdVersion; - glm::vec3 _relativePosition; + void doKinematicUpdate(float deltaTimeStep); + + glm::vec3 _relativePosition { 0.0f }; glm::quat _relativeRotation; - QString _hand; + QString _hand { "right" }; QUuid _holderID; - void doKinematicUpdate(float deltaTimeStep); bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 7d8ff22f73..9c95bb9426 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -35,17 +35,19 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); -const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches -const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, 2.0f * CONTROLLER_LENGTH_OFFSET); // three inches -const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; +static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches +static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); +static const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; + +static const QString MENU_PARENT = "Avatar"; +static const QString MENU_NAME = "Vive Controllers"; +static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; +static const QString RENDER_CONTROLLERS = "Render Hand Controllers"; const QString ViveControllerManager::NAME = "OpenVR"; -const QString MENU_PARENT = "Avatar"; -const QString MENU_NAME = "Vive Controllers"; -const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; -const QString RENDER_CONTROLLERS = "Render Hand Controllers"; - bool ViveControllerManager::isSupported() const { #ifdef Q_OS_WIN auto hmd = acquireOpenVrSystem(); From 8da8b4db8c20dc0cfb50013124c3e4457269ab59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 13:42:25 -0800 Subject: [PATCH 139/171] Add option to ignore IK for my avatar's entity actions --- interface/src/avatar/AvatarActionHold.cpp | 19 +++++++++++++++---- interface/src/avatar/AvatarActionHold.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 12759d5208..ad793ab53f 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -48,8 +48,9 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; - bool ignoreIK = true; - if (ignoreIK) { + if (_ignoreIK && holdingAvatar->isMyAvatar()) { + // We cannot ignore other avatars IK and this is not the point of this option + // This is meant to make the grabbing behavior more reactive. if (_hand == "right") { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); @@ -179,6 +180,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { QUuid holderID; bool kinematic; bool kinematicSetVelocity; + bool ignoreIK; bool needUpdate = false; bool somethingChanged = ObjectAction::updateArguments(arguments); @@ -216,13 +218,19 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { _kinematic = false; } - + ok = true; kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematicSetVelocity", ok, false); if (!ok) { _kinematicSetVelocity = false; } + + ok = true; + ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false); + if (!ok) { + _ignoreIK = true; + } if (somethingChanged || relativePosition != _relativePosition || @@ -231,7 +239,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { hand != _hand || holderID != _holderID || kinematic != _kinematic || - kinematicSetVelocity != _kinematicSetVelocity) { + kinematicSetVelocity != _kinematicSetVelocity || + ignoreIK != _ignoreIK) { needUpdate = true; } }); @@ -247,6 +256,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { _holderID = holderID; _kinematic = kinematic; _kinematicSetVelocity = kinematicSetVelocity; + _ignoreIK = ignoreIK; _active = true; auto ownerEntity = _ownerEntity.lock(); @@ -270,6 +280,7 @@ QVariantMap AvatarActionHold::getArguments() { arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; arguments["kinematicSetVelocity"] = _kinematicSetVelocity; + arguments["ignoreIK"] = _ignoreIK; }); return arguments; } diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index ec1df2f0e0..2da32b9352 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -45,6 +45,7 @@ private: bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; + bool _ignoreIK { true }; glm::vec3 _previousPositionalTarget; glm::quat _previousRotationalTarget; From d79221edd2a03b073fe04322a0df5df25fcafdd1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:06:59 -0800 Subject: [PATCH 140/171] AvatarActionHold can ignore IK --- interface/src/avatar/AvatarActionHold.cpp | 89 ++++++++++--------- interface/src/avatar/AvatarActionHold.h | 3 + .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ad793ab53f..f080e947d0 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -45,13 +45,14 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { holdingAvatar = std::static_pointer_cast(holdingAvatarData); if (holdingAvatar) { + bool isRightHand = (_hand == "right"); glm::vec3 palmPosition; glm::quat palmRotation; if (_ignoreIK && holdingAvatar->isMyAvatar()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. - if (_hand == "right") { + if (isRightHand) { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); } else { @@ -59,7 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } } else { - if (_hand == "right") { + if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { @@ -67,44 +68,26 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getLeftPalmRotation(); } } - /* - static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches - static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; - - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - glm::quat relRot = glm::inverse(rightRotationOffset); - glm::vec3 relPos = -rightTranslationOffset; - relRot = palmRotation * relRot; - relPos = palmPosition + relRot * relPos; - - rotation = relRot * _relativeRotation; - position = relPos + rotation * _relativePosition; - glm::quat diffRot = glm::inverse(palmRotation) * rotation; - glm::vec3 diffPos = glm::inverse(rotation) * (position - palmPosition); - qDebug() << "diffRot =" << safeEulerAngles(diffRot); - qDebug() << "diffPos =" << diffPos; - */ - //[11 / 09 17:40 : 14] [DEBUG] diffRot = { type = 'glm::vec3', x = 3.14159, y = 9.04283e-09, z = 0.785398 } - //[11 / 09 17:40 : 14][DEBUG] diffPos = { type = 'glm::vec3', x = 1.0524, y = -0.0381001, z = -0.0380997 } - //_relativeRotation = glm::quat(glm::vec3(3.14159f, 0.0f, 0.785398)); - //_relativePosition = glm::vec3(1.0524, -0.0381001, -0.0380997); - rotation = palmRotation * _relativeRotation; - position = palmPosition + rotation * _relativePosition; + if (isRightHand) { + rotation = palmRotation * _perHandRelativeRotation; + position = palmPosition + rotation * _perHandRelativePosition; + } else { + auto mirroredRotation = _perHandRelativeRotation; + auto mirroredPosition = _perHandRelativePosition; + + // Mirror along z axis + mirroredRotation.z *= -1; + mirroredRotation.w *= -1; + + mirroredPosition.z *= -1; + + rotation = palmRotation * mirroredRotation; + position = palmPosition + rotation * mirroredPosition; + } + + rotation = rotation * _relativeRotation; + position = position + rotation * _relativePosition; } }); @@ -175,6 +158,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { bool AvatarActionHold::updateArguments(QVariantMap arguments) { glm::vec3 relativePosition; glm::quat relativeRotation; + glm::vec3 perHandRelativePosition; + glm::quat perHandRelativeRotation; float timeScale; QString hand; QUuid holderID; @@ -190,12 +175,26 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { relativePosition = _relativePosition; } - + ok = true; relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); if (!ok) { relativeRotation = _relativeRotation; } + + ok = true; + perHandRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, + "perHandRelativePosition", ok, false); + if (!ok) { + perHandRelativePosition = _perHandRelativePosition; + } + + ok = true; + perHandRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, + "perHandRelativeRotation", ok, false); + if (!ok) { + perHandRelativeRotation = _perHandRelativeRotation; + } ok = true; timeScale = EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false); @@ -235,6 +234,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (somethingChanged || relativePosition != _relativePosition || relativeRotation != _relativeRotation || + perHandRelativePosition != _perHandRelativePosition || + perHandRelativeRotation != _perHandRelativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -249,6 +250,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { withWriteLock([&] { _relativePosition = relativePosition; _relativeRotation = relativeRotation; + _perHandRelativePosition = perHandRelativePosition; + _perHandRelativeRotation = perHandRelativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -276,6 +279,8 @@ QVariantMap AvatarActionHold::getArguments() { arguments["holderID"] = _holderID; arguments["relativePosition"] = glmToQMap(_relativePosition); arguments["relativeRotation"] = glmToQMap(_relativeRotation); + arguments["perHandRelativePosition"] = glmToQMap(_perHandRelativePosition); + arguments["perHandRelativeRotation"] = glmToQMap(_perHandRelativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -297,6 +302,8 @@ QByteArray AvatarActionHold::serialize() const { dataStream << _holderID; dataStream << _relativePosition; dataStream << _relativeRotation; + dataStream << _perHandRelativePosition; + dataStream << _perHandRelativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -330,6 +337,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { dataStream >> _holderID; dataStream >> _relativePosition; dataStream >> _relativeRotation; + dataStream >> _perHandRelativePosition; + dataStream >> _perHandRelativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 2da32b9352..3979efc113 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -39,6 +39,9 @@ private: glm::vec3 _relativePosition { 0.0f }; glm::quat _relativeRotation; + glm::vec3 _perHandRelativePosition { 0.0f }; + glm::quat _perHandRelativeRotation; + QString _hand { "right" }; QUuid _holderID; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 24034ff9b3..84cde04b96 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING; + return VERSION_ENTITIES_ACTIONS_IGNORE_IK; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 82d905bf28..5d96e21e1c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -146,5 +146,6 @@ const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; +const PacketVersion VERSION_ENTITIES_ACTIONS_IGNORE_IK = 50; #endif // hifi_PacketHeaders_h From aca5cb2559043ccc53be8ba49bdd558d570e7dba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:18:27 -0800 Subject: [PATCH 141/171] Renamed header version --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 84cde04b96..5f57d5e5a5 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ACTIONS_IGNORE_IK; + return VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5d96e21e1c..efcf965bb7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -146,6 +146,6 @@ const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; -const PacketVersion VERSION_ENTITIES_ACTIONS_IGNORE_IK = 50; +const PacketVersion VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET = 50; #endif // hifi_PacketHeaders_h From 3cbe1bc4da586f708f02dbe0c6f32e7219918731 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:50:22 -0800 Subject: [PATCH 142/171] Mirror on x instead of z --- examples/baseball/createBatButton.js | 8 ++++---- interface/src/avatar/AvatarActionHold.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 2a462bca65..931ff185a4 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,10 +51,10 @@ var batUserData = { grabbableKey: { spatialKey: { - relativePosition: { - x: 0.9, y: 0, z: 0 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0) + relativePosition: { x: 0.9, y: 0, z: 0 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0), + perHandRelativePosition: { x: 0.0808223, y: 0.134704, z: 0.0381 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(-180, 90, 45) } } } diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index f080e947d0..ad2465404c 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -76,11 +76,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { auto mirroredRotation = _perHandRelativeRotation; auto mirroredPosition = _perHandRelativePosition; - // Mirror along z axis - mirroredRotation.z *= -1; + // Mirror along x axis + mirroredRotation.x *= -1; mirroredRotation.w *= -1; - mirroredPosition.z *= -1; + mirroredPosition.x *= -1; rotation = palmRotation * mirroredRotation; position = palmPosition + rotation * mirroredPosition; From 735fd70a8eff47b4060879218c935b2df37c159d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:04:53 -0800 Subject: [PATCH 143/171] Tweak perHandRotation/Position in action --- interface/src/avatar/AvatarActionHold.cpp | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ad2465404c..7ca25dad42 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,8 +35,8 @@ AvatarActionHold::~AvatarActionHold() { void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; - glm::quat rotation; - glm::vec3 position; + glm::quat rotation { Quaternions::IDENTITY }; + glm::vec3 position { Vectors::ZERO }; std::shared_ptr holdingAvatar = nullptr; gotLock = withTryReadLock([&]{ @@ -46,9 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { if (holdingAvatar) { bool isRightHand = (_hand == "right"); - glm::vec3 palmPosition; - glm::quat palmRotation; + glm::vec3 palmPosition { Vectors::ZERO }; + glm::quat palmRotation { Quaternions::IDENTITY }; + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); if (_ignoreIK && holdingAvatar->isMyAvatar()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. @@ -58,6 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } else { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); + palmRotation *= yFlip; // Match right hand frame of reference } } else { if (isRightHand) { @@ -66,28 +69,31 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } else { palmPosition = holdingAvatar->getLeftPalmPosition(); palmRotation = holdingAvatar->getLeftPalmRotation(); + palmRotation *= yFlip; // Match right hand frame of reference } } + rotation = palmRotation * _relativeRotation; + position = palmPosition + rotation * _relativePosition; + if (isRightHand) { - rotation = palmRotation * _perHandRelativeRotation; - position = palmPosition + rotation * _perHandRelativePosition; + rotation *= _perHandRelativeRotation; + position += rotation * _perHandRelativePosition; } else { auto mirroredRotation = _perHandRelativeRotation; auto mirroredPosition = _perHandRelativePosition; - // Mirror along x axis - mirroredRotation.x *= -1; - mirroredRotation.w *= -1; + // Mirror along z axis + auto eulerAngles = safeEulerAngles(mirroredRotation); + eulerAngles.x *= -1; + eulerAngles.y *= -1; + mirroredRotation = glm::quat(eulerAngles); - mirroredPosition.x *= -1; + mirroredPosition.z *= -1; - rotation = palmRotation * mirroredRotation; - position = palmPosition + rotation * mirroredPosition; + rotation *= mirroredRotation; + position += rotation * mirroredPosition; } - - rotation = rotation * _relativeRotation; - position = position + rotation * _relativePosition; } }); From 4f1420a5eeb242a6d9733981781be15de4a32c17 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:05:27 -0800 Subject: [PATCH 144/171] Tweak bat offsets --- examples/baseball/createBatButton.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 931ff185a4..f16f126f2c 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -52,9 +52,9 @@ grabbableKey: { spatialKey: { relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - perHandRelativePosition: { x: 0.0808223, y: 0.134704, z: 0.0381 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(-180, 90, 45) + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), + perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) } } } From ce57488b9fe8f668757c90a8b3922fdfc11a1d73 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:10:15 -0800 Subject: [PATCH 145/171] cleanup dead code --- .../src/input-plugins/ViveControllerManager.cpp | 12 +----------- .../src/input-plugins/ViveControllerManager.h | 11 ++++------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 9c95bb9426..88fdff4bce 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -206,16 +206,6 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } -#ifdef Q_OS_WIN -glm::vec3 ViveControllerManager::getPosition(int hand) const { - const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; - return extractTranslation(mat); -} -glm::quat ViveControllerManager::getRotation(int hand) const { - const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; - return glm::quat_cast(mat); -} -#endif void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) { _inputDevice->update(deltaTime, jointsCaptured); @@ -263,7 +253,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCapt bool left = numTrackedControllers == 2; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index d664326da8..02bdecb10a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -31,7 +31,6 @@ namespace vr { class ViveControllerManager : public InputPlugin { Q_OBJECT public: - static const QString NAME; // Plugin functions virtual bool isSupported() const override; @@ -47,12 +46,6 @@ public: void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges); void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } - - -#ifdef Q_OS_WIN - glm::vec3 getPosition(int device) const; - glm::quat getRotation(int device) const; -#endif private: class InputDevice : public controller::InputDevice { @@ -89,6 +82,10 @@ private: bool _renderControllers { false }; vr::IVRSystem* _hmd { nullptr }; std::shared_ptr _inputDevice { std::make_shared(_hmd) }; + + static const QString NAME; + + }; #endif // hifi__ViveControllerManager From 6e702a28906ab73581b2b876650ade235e64bb3c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 12 Nov 2015 11:18:05 -0800 Subject: [PATCH 146/171] Update range of LOD to go up to 20:2 --- libraries/octree/src/OctreeConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index a98f042006..0b05a8606c 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -24,7 +24,7 @@ const int HALF_TREE_SCALE = TREE_SCALE / 2; const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; // This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale -const float MAX_LOD_SIZE_MULTIPLIER = 800.0f; +const float MAX_LOD_SIZE_MULTIPLIER = 4000.0f; const int NUMBER_OF_CHILDREN = 8; From a7dfc99a2e54a2083e58739723fbd2a6294cffb9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 13 Nov 2015 16:14:53 -0800 Subject: [PATCH 147/171] Fix high score not updating in baseball --- examples/baseball/pitching.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 62492c9563..09f33c9dd4 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -362,7 +362,7 @@ function updateBillboard(distanceOrMessage) { }); } - var highScoreBillboardEntityID = getHighScoreBillboardEntityID; + var highScoreBillboardEntityID = getHighScoreBillboardEntityID(); // If a number was passed in, let's see if it is larger than the current high score // and update it if so. if (!isNaN(distanceOrMessage) && highScoreBillboardEntityID) { From 510189dfbc60705dfc5cb7847112ef6723044b1a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 17 Nov 2015 15:08:05 -0800 Subject: [PATCH 148/171] Update CCD motion threshold --- libraries/physics/src/ObjectMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 6f1b928456..f6e15d8539 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -121,7 +121,7 @@ void ObjectMotionState::updateCCDConfiguration() { btVector3 center; btScalar radius; _shape->getBoundingSphere(center, radius); - _body->setCcdMotionThreshold(radius * 2.0f); + _body->setCcdMotionThreshold(radius / 4.0f); _body->setCcdSweptSphereRadius(radius); } else { // Disable CCD From a33e57dfdb9ceb3e82d69c7601ba2d5dd4d5a773 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 14:06:09 -0800 Subject: [PATCH 149/171] remove audio files from history --- examples/baseball/audio/assets.txt | 23 ----------------------- examples/baseball/audio/attribution.txt | 8 -------- 2 files changed, 31 deletions(-) delete mode 100644 examples/baseball/audio/assets.txt delete mode 100644 examples/baseball/audio/attribution.txt diff --git a/examples/baseball/audio/assets.txt b/examples/baseball/audio/assets.txt deleted file mode 100644 index 225714cbe1..0000000000 --- a/examples/baseball/audio/assets.txt +++ /dev/null @@ -1,23 +0,0 @@ -crowd-boos.wav -atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav - -crowd-cheers-organ.wav -atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav - -crowd-medium.wav -atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav - -baseball-hitting-bat-1.wav -atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav - -baseball-hitting-bat-set-1.wav -atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav - -baseball-hitting-bat-set-2.wav -atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav - -baseball-hitting-bat-set-3.wav -atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav - -baseball-hitting-bat-set-4.wav -atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav \ No newline at end of file diff --git a/examples/baseball/audio/attribution.txt b/examples/baseball/audio/attribution.txt deleted file mode 100644 index 760951447c..0000000000 --- a/examples/baseball/audio/attribution.txt +++ /dev/null @@ -1,8 +0,0 @@ -Baseball bat hitting sounds -https://www.freesound.org/people/SocializedArtist45/sounds/266595/ -https://www.freesound.org/people/CGEffex/sounds/93136/ - -Crowd Sounds -http://freesound.org/people/AshFox/sounds/191925/ -http://freesound.org/people/AshFox/sounds/191928/ -http://freesound.org/people/AshFox/sounds/191929/ \ No newline at end of file From 2acfbd0f8f79b5dfb1f3be96298c007992f47259 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:52:03 -0800 Subject: [PATCH 150/171] revert accidental CCD change --- libraries/physics/src/ObjectMotionState.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 1199c3792a..7389d18143 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -135,7 +135,12 @@ void ObjectMotionState::updateCCDConfiguration() { btVector3 center; btScalar radius; _shape->getBoundingSphere(center, radius); - _body->setCcdMotionThreshold(radius / 4.0f); + _body->setCcdMotionThreshold(radius * RADIUS_MOTION_THRESHOLD_MULTIPLIER); + + // TODO: Ideally the swept sphere radius would be contained by the object. Using the bounding sphere + // radius works well for spherical objects, but may cause issues with other shapes. For arbitrary + // objects we may want to consider a different approach, such as grouping rigid bodies together. + _body->setCcdSweptSphereRadius(radius); } else { // Disable CCD From b1a69bb2cf877a58e58124df496986f85c245e97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:52:10 -0800 Subject: [PATCH 151/171] cleanup spacing in ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 56 +++++++++++--------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 214374af49..d578db7ca8 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -65,9 +65,9 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline message = message.replace("\\", "\\\\") - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("'", "\\'"); + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("'", "\\'"); engine->evaluate("Script.print('" + message + "')"); return QScriptValue(); @@ -123,11 +123,11 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName } ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) : -_scriptContents(scriptContents), -_timerFunctionMap(), -_wantSignals(wantSignals), -_fileNameString(fileNameString), -_arrayBufferClass(new ArrayBufferClass(this)) + _scriptContents(scriptContents), + _timerFunctionMap(), + _wantSignals(wantSignals), + _fileNameString(fileNameString), + _arrayBufferClass(new ArrayBufferClass(this)) { _allScriptsMutex.lock(); _allKnownScriptEngines.insert(this); @@ -495,7 +495,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - " name:" << name << "parent:" << parent; + " name:" << name << "parent:" << parent; #endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), @@ -528,7 +528,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << " eventName:" << eventName; + "entityID:" << entityID << " eventName:" << eventName; #endif QMetaObject::invokeMethod(this, "removeEventHandler", Q_ARG(const EntityItemID&, entityID), @@ -955,7 +955,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { if (_stoppingAllScripts) { qCDebug(scriptengine) << "Script.include() while shutting down is ignored... " - << "includeFile:" << includeFile << "parent script:" << getFilename(); + << "includeFile:" << includeFile << "parent script:" << getFilename(); return; // bail early } @@ -970,7 +970,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { void ScriptEngine::load(const QString& loadFile) { if (_stoppingAllScripts) { qCDebug(scriptengine) << "Script.load() while shutting down is ignored... " - << "loadFile:" << loadFile << "parent script:" << getFilename(); + << "loadFile:" << loadFile << "parent script:" << getFilename(); return; // bail early } @@ -1016,7 +1016,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; + "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; #endif QMetaObject::invokeMethod(this, "loadEntityScript", @@ -1027,18 +1027,20 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; + "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; #endif // If we've been called our known entityScripts should not know about us.. assert(!_entityScripts.contains(entityID)); #ifdef THREAD_DEBUGGING - qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; + qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" + << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { #ifdef THREAD_DEBUGGING - qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; + qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" + << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success); @@ -1091,11 +1093,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co if (!testConstructor.isFunction()) { qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" - " NOT CONSTRUCTOR\n" - " SCRIPT:" << scriptOrURL; + " NOT CONSTRUCTOR\n" + " SCRIPT:" << scriptOrURL; + if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } + return; // done processing script } @@ -1121,7 +1125,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID; + "entityID:" << entityID; #endif QMetaObject::invokeMethod(this, "unloadEntityScript", @@ -1130,7 +1134,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " - "entityID:" << entityID; + "entityID:" << entityID; #endif if (_entityScripts.contains(entityID)) { @@ -1195,7 +1199,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName; + "entityID:" << entityID << "methodName:" << methodName; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1206,7 +1210,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName; + "entityID:" << entityID << "methodName:" << methodName; #endif refreshFileScript(entityID); @@ -1227,7 +1231,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; + "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1238,7 +1242,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; + "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif refreshFileScript(entityID); @@ -1259,7 +1263,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; + "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1271,7 +1275,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; + "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif refreshFileScript(entityID); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 59befbdd9f..90b99d46fd 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -145,7 +145,7 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - public slots: +public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); signals: From 733665d722c75d64f8e7d04135591a006bb7880e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:53:42 -0800 Subject: [PATCH 152/171] fix spacing in baseballCrowd.js --- examples/acScripts/baseballCrowd.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index bc8965e54d..de9b53f9ec 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -11,10 +11,10 @@ var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); var extras = [ - SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba - SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge - SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game - SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping + SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba + SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge + SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game + SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; var CHATTER_VOLUME = 0.20 @@ -34,8 +34,8 @@ function playRandomExtras() { if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) { // play a random extra sound about every 30s currentInjector = Audio.playSound( - extras[Math.floor(Math.random() * extras.length)], - { volume: EXTRA_VOLUME } + extras[Math.floor(Math.random() * extras.length)], + { volume: EXTRA_VOLUME } ); } } From c3f3639374398fc76a9327d24426d05d47dbf66e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:57:10 -0800 Subject: [PATCH 153/171] more spacing adjustments in ScriptEngine.cpp --- libraries/script-engine/src/ScriptEngine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d578db7ca8..96cbd79b52 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -636,7 +636,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi QScriptValue result; #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; #endif QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QScriptValue, result), @@ -1015,7 +1015,8 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" + << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; #endif @@ -1052,8 +1053,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success; + qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" + << QThread::currentThread() << "], invoking on correct thread [" << thread() + << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" + << contents << "isURL:" << isURL << "success:" << success; #endif QMetaObject::invokeMethod(this, "entityScriptContentAvailable", From 1b1efe53d9dc2aa3913135bd7acfad4b196d83d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:59:12 -0800 Subject: [PATCH 154/171] fix for two space indentation in createBatButton.js --- examples/baseball/createBatButton.js | 90 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index f16f126f2c..75f3dee26e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -20,58 +20,58 @@ this.dropBats(); }; this.startFarTrigger = function() { - this.dropBats(); + this.dropBats(); }; this.dropBats = function() { - // if the bat box is near us, grab it's position - var nearby = Entities.findEntities(this.position, 20); + // if the bat box is near us, grab it's position + var nearby = Entities.findEntities(this.position, 20); - nearby.forEach(function(id) { - var properties = Entities.getEntityProperties(id, ["name", "position"]); - if (properties.name && properties.name == "Bat Box") { - boxPosition = properties.position; - } - }); + nearby.forEach(function(id) { + var properties = Entities.getEntityProperties(id, ["name", "position"]); + if (properties.name && properties.name == "Bat Box") { + boxPosition = properties.position; + } + }); - var BAT_DROP_HEIGHT = 2.0; + var BAT_DROP_HEIGHT = 2.0; - var dropPosition; + var dropPosition; - if (!boxPosition) { - // we got no bat box position, drop in front of the avatar instead - } else { - // drop the bat above the bat box - dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); - } - - var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; - var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" - - var batUserData = { - grabbableKey: { - spatialKey: { - relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), - perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) - } + if (!boxPosition) { + // we got no bat box position, drop in front of the avatar instead + } else { + // drop the bat above the bat box + dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); } - } - // add the fresh bat at the drop position - var bat = Entities.addEntity({ - name: 'Bat', - type: "Model", - modelURL: BAT_MODEL, - position: dropPosition, - compoundShapeURL: BAT_COLLISION_HULL, - collisionsWillMove: true, - velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add - gravity: { x: 0, y: -9.81, z: 0}, - rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), - script: SCRIPT_URL, - userData: JSON.stringify(batUserData) - }); + var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; + var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" + + var batUserData = { + grabbableKey: { + spatialKey: { + relativePosition: { x: 0.9, y: 0, z: 0 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), + perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) + } + } + } + + // add the fresh bat at the drop position + var bat = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: dropPosition, + compoundShapeURL: BAT_COLLISION_HULL, + collisionsWillMove: true, + velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add + gravity: { x: 0, y: -9.81, z: 0}, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), + script: SCRIPT_URL, + userData: JSON.stringify(batUserData) + }); }; }); From 0ed249f0e7ff9e2eff2412871de1f7b7a45fb896 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 15:59:49 -0800 Subject: [PATCH 155/171] Update script path include in firework.js --- examples/baseball/firework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 89287c5a8b..bc1d0910cf 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); +Script.include("utils.js"); var emitters = []; From 6fe370c4ef908f596a7f955179706293b0725e7f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 16:00:15 -0800 Subject: [PATCH 156/171] Remove old comment in firework.js --- examples/baseball/firework.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index bc1d0910cf..a78e1595eb 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -136,5 +136,3 @@ playFireworkShow = function(position, numberOfFireworks, duration) { }(randomPosition), Math.random() * duration) } } - -//playFireworkShow(10, 2000); From f7537e3dc374d4014c6f27b9031e8a06899dfee9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:44:14 -0800 Subject: [PATCH 157/171] add initial version of asset description --- examples/baseball/assets.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/baseball/assets.yml diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml new file mode 100644 index 0000000000..c17715179f --- /dev/null +++ b/examples/baseball/assets.yml @@ -0,0 +1,17 @@ +assets: + crowd-boos.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav" + atp_url: "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + crowd-cheers-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav" + atp_url: "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + crowd-medium.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav" + atp_url: "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + baseball-hitting-bat-1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" + atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" From 4a80e72d14587f893a45c33b919277ff4c2e9fca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:48:05 -0800 Subject: [PATCH 158/171] complete attribution for removed files --- examples/baseball/assets.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index c17715179f..2b1aa1d203 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -14,4 +14,20 @@ assets: baseball-hitting-bat-1.wav: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + attribution: "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" + baseball-hitting-bat-set-1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav" + atp_url: "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-2.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav" + atp_url: "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-3.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav" + atp_url: "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-4.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" + atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" From c451ede05176b9ffbc54a4f1818fcf1491b0eb9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:59:13 -0800 Subject: [PATCH 159/171] add crowd noises to assets yaml --- examples/baseball/assets.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index 2b1aa1d203..a9ee455b23 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -31,3 +31,23 @@ assets: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + chatter-loop.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav" + atp_url: "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + zorba-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav" + atp_url: "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + charge-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav" + atp_url: "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + ball-game.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav" + atp_url: "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + clapping.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" + atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" From cba09beff4eae99146f09b890b77d4cb7104c88d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 17:02:30 -0800 Subject: [PATCH 160/171] add pop sounds (which don't require attribution) --- examples/baseball/assets.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index a9ee455b23..f7ba1cb158 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -51,3 +51,15 @@ assets: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + pop1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav" + atp_url: "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" + pop2.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav" + atp_url: "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" + pop3.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav" + atp_url: "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" + pop4.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav" + atp_url: "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" From 52fb7116561ab72d80b75153368d9977c5e59b37 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 17:06:09 -0800 Subject: [PATCH 161/171] Move baseballCrowd to correct directory --- examples/{acScripts => baseball}/baseballCrowd.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{acScripts => baseball}/baseballCrowd.js (100%) diff --git a/examples/acScripts/baseballCrowd.js b/examples/baseball/baseballCrowd.js similarity index 100% rename from examples/acScripts/baseballCrowd.js rename to examples/baseball/baseballCrowd.js From 52dc2cf7469ff1e1626ddee52d1d152c6ee2d0f0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 17:17:06 -0800 Subject: [PATCH 162/171] change the assets file to json --- examples/baseball/assets.json | 85 +++++++++++++++++++++++++++++++++++ examples/baseball/assets.yml | 65 --------------------------- 2 files changed, 85 insertions(+), 65 deletions(-) create mode 100644 examples/baseball/assets.json delete mode 100644 examples/baseball/assets.yml diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json new file mode 100644 index 0000000000..037eb616d2 --- /dev/null +++ b/examples/baseball/assets.json @@ -0,0 +1,85 @@ +{ + "assets": { + "crowd-boos.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav", + "atp_url": "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "crowd-cheers-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav", + "atp_url": "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "crowd-medium.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav", + "atp_url": "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "baseball-hitting-bat-1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav", + "atp_url": "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav", + "attribution": "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" + }, + "baseball-hitting-bat-set-1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav", + "atp_url": "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav", + "atp_url": "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav", + "atp_url": "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav", + "atp_url": "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "chatter-loop.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav", + "atp_url": "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "zorba-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav", + "atp_url": "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "charge-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav", + "atp_url": "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "ball-game.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav", + "atp_url": "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "clapping.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav", + "atp_url": "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "pop1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav", + "atp_url": "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" + }, + "pop2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav", + "atp_url": "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" + }, + "pop3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav", + "atp_url": "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" + }, + "pop4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav", + "atp_url": "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" + } + } +} diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml deleted file mode 100644 index f7ba1cb158..0000000000 --- a/examples/baseball/assets.yml +++ /dev/null @@ -1,65 +0,0 @@ -assets: - crowd-boos.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav" - atp_url: "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - crowd-cheers-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav" - atp_url: "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - crowd-medium.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav" - atp_url: "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - baseball-hitting-bat-1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" - atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" - attribution: "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" - baseball-hitting-bat-set-1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav" - atp_url: "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-2.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav" - atp_url: "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-3.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav" - atp_url: "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-4.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" - atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - chatter-loop.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav" - atp_url: "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - zorba-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav" - atp_url: "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - charge-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav" - atp_url: "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - ball-game.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav" - atp_url: "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - clapping.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" - atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - pop1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav" - atp_url: "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" - pop2.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav" - atp_url: "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" - pop3.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav" - atp_url: "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" - pop4.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav" - atp_url: "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" From 8d9eeb3897f532cf5c7cf483fa597af47ae85234 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:04:34 -0800 Subject: [PATCH 163/171] Have separate left/right hold action offset --- interface/src/avatar/AvatarActionHold.cpp | 151 ++++++++++------------ interface/src/avatar/AvatarActionHold.h | 12 +- interface/src/avatar/AvatarManager.cpp | 2 +- 3 files changed, 73 insertions(+), 92 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index a30ba35e4a..bff6af7337 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -33,63 +33,46 @@ AvatarActionHold::~AvatarActionHold() { } std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) { - std::shared_ptr holdingAvatar = nullptr; + auto avatarManager = DependencyManager::get(); + auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); + + if (!holdingAvatar) { + return holdingAvatar; + } withTryReadLock([&]{ - QSharedPointer avatarManager = DependencyManager::get(); - AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID); - holdingAvatar = std::static_pointer_cast(holdingAvatarData); - - if (holdingAvatar) { - bool isRightHand = (_hand == "right"); - glm::vec3 palmPosition { Vectors::ZERO }; - glm::quat palmRotation { Quaternions::IDENTITY }; - - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - if (_ignoreIK && holdingAvatar->isMyAvatar()) { - // We cannot ignore other avatars IK and this is not the point of this option - // This is meant to make the grabbing behavior more reactive. - if (isRightHand) { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); - } else { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); - palmRotation *= yFlip; // Match right hand frame of reference - } - } else { - if (isRightHand) { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - palmRotation *= yFlip; // Match right hand frame of reference - } - } - - rotation = palmRotation * _relativeRotation; - position = palmPosition + rotation * _relativePosition; + bool isRightHand = (_hand == "right"); + glm::vec3 palmPosition { Vectors::ZERO }; + glm::quat palmRotation { Quaternions::IDENTITY }; + if (_ignoreIK && holdingAvatar->isMyAvatar()) { + // We cannot ignore other avatars IK and this is not the point of this option + // This is meant to make the grabbing behavior more reactive. if (isRightHand) { - rotation *= _perHandRelativeRotation; - position += rotation * _perHandRelativePosition; + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); } else { - auto mirroredRotation = _perHandRelativeRotation; - auto mirroredPosition = _perHandRelativePosition; - - // Mirror along z axis - auto eulerAngles = safeEulerAngles(mirroredRotation); - eulerAngles.x *= -1; - eulerAngles.y *= -1; - mirroredRotation = glm::quat(eulerAngles); - - mirroredPosition.z *= -1; - - rotation *= mirroredRotation; - position += rotation * mirroredPosition; + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } + } else { + if (isRightHand) { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + } + + if (isRightHand) { + rotation = palmRotation * _rightRelativeRotation; + position = palmPosition + rotation * _rightRelativePosition; + } else { + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + palmRotation *= yFlip; // Match right hand frame of reference + rotation = palmRotation * _leftRelativeRotation; + position = palmPosition + rotation * _leftRelativePosition; } }); @@ -192,10 +175,10 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { } bool AvatarActionHold::updateArguments(QVariantMap arguments) { - glm::vec3 relativePosition; - glm::quat relativeRotation; - glm::vec3 perHandRelativePosition; - glm::quat perHandRelativeRotation; + glm::vec3 leftRelativePosition; + glm::quat leftRelativeRotation; + glm::vec3 rightRelativePosition; + glm::quat rightRelativeRotation; float timeScale; QString hand; QUuid holderID; @@ -207,29 +190,27 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { bool somethingChanged = ObjectAction::updateArguments(arguments); withReadLock([&]{ bool ok = true; - relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); + leftRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "leftRelativePosition", ok, false); if (!ok) { - relativePosition = _relativePosition; + leftRelativePosition = _leftRelativePosition; } ok = true; - relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); + leftRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "leftRelativeRotation", ok, false); if (!ok) { - relativeRotation = _relativeRotation; + leftRelativeRotation = _leftRelativeRotation; } ok = true; - perHandRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, - "perHandRelativePosition", ok, false); + rightRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "rightRelativePosition", ok, false); if (!ok) { - perHandRelativePosition = _perHandRelativePosition; + rightRelativePosition = _rightRelativePosition; } ok = true; - perHandRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, - "perHandRelativeRotation", ok, false); + rightRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "rightRelativeRotation", ok, false); if (!ok) { - perHandRelativeRotation = _perHandRelativeRotation; + rightRelativeRotation = _rightRelativeRotation; } ok = true; @@ -268,10 +249,10 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { } if (somethingChanged || - relativePosition != _relativePosition || - relativeRotation != _relativeRotation || - perHandRelativePosition != _perHandRelativePosition || - perHandRelativeRotation != _perHandRelativeRotation || + leftRelativePosition != _leftRelativePosition || + leftRelativeRotation != _leftRelativeRotation || + rightRelativePosition != _rightRelativePosition || + rightRelativeRotation != _rightRelativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -284,10 +265,10 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _relativePosition = relativePosition; - _relativeRotation = relativeRotation; - _perHandRelativePosition = perHandRelativePosition; - _perHandRelativeRotation = perHandRelativeRotation; + _leftRelativePosition = leftRelativePosition; + _leftRelativeRotation = leftRelativeRotation; + _rightRelativePosition = rightRelativePosition; + _rightRelativeRotation = rightRelativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -314,10 +295,10 @@ QVariantMap AvatarActionHold::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&]{ arguments["holderID"] = _holderID; - arguments["relativePosition"] = glmToQMap(_relativePosition); - arguments["relativeRotation"] = glmToQMap(_relativeRotation); - arguments["perHandRelativePosition"] = glmToQMap(_perHandRelativePosition); - arguments["perHandRelativeRotation"] = glmToQMap(_perHandRelativeRotation); + arguments["leftRelativePosition"] = glmToQMap(_leftRelativePosition); + arguments["leftRelativeRotation"] = glmToQMap(_leftRelativeRotation); + arguments["rightRelativePosition"] = glmToQMap(_rightRelativePosition); + arguments["rightRelativeRotation"] = glmToQMap(_rightRelativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -337,10 +318,10 @@ QByteArray AvatarActionHold::serialize() const { dataStream << AvatarActionHold::holdVersion; dataStream << _holderID; - dataStream << _relativePosition; - dataStream << _relativeRotation; - dataStream << _perHandRelativePosition; - dataStream << _perHandRelativeRotation; + dataStream << _leftRelativePosition; + dataStream << _leftRelativeRotation; + dataStream << _rightRelativePosition; + dataStream << _rightRelativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -372,10 +353,10 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { withWriteLock([&]{ dataStream >> _holderID; - dataStream >> _relativePosition; - dataStream >> _relativeRotation; - dataStream >> _perHandRelativePosition; - dataStream >> _perHandRelativeRotation; + dataStream >> _leftRelativePosition; + dataStream >> _leftRelativeRotation; + dataStream >> _rightRelativePosition; + dataStream >> _rightRelativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index c9563e5e88..d3aad19384 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -41,12 +41,12 @@ private: static const uint16_t holdVersion; void doKinematicUpdate(float deltaTimeStep); - - glm::vec3 _relativePosition { 0.0f }; - glm::quat _relativeRotation; - glm::vec3 _perHandRelativePosition { 0.0f }; - glm::quat _perHandRelativeRotation; - + + glm::vec3 _leftRelativePosition{ Vectors::ZERO }; + glm::quat _leftRelativeRotation{ Quaternions::IDENTITY }; + glm::vec3 _rightRelativePosition{ Vectors::ZERO }; + glm::quat _rightRelativeRotation{ Quaternions::IDENTITY }; + QString _hand { "right" }; QUuid _holderID; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 9df597109c..9fc6855d3b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -402,7 +402,7 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) { if (sessionID == _myAvatar->getSessionUUID()) { - return std::static_pointer_cast(_myAvatar); + return _myAvatar; } return findAvatar(sessionID); From 4025504749b5d02a02fc590bca99be5c55d6bb69 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:21:14 -0800 Subject: [PATCH 164/171] Fix merge error --- libraries/audio/src/Sound.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 742d26b500..5447ca6213 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -30,9 +30,6 @@ public: const QByteArray& getByteArray() { return _byteArray; } -signals: - void ready(); - signals: void ready(); From d0e1ec3a86a23d9571e748cf67b7f0b9a9774152 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:26:04 -0800 Subject: [PATCH 165/171] Fix merge error --- libraries/audio/src/Sound.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 742d26b500..91dbef8c6a 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -29,9 +29,6 @@ public: bool isReady() const { return _isReady; } const QByteArray& getByteArray() { return _byteArray; } - -signals: - void ready(); signals: void ready(); From 05862eff0060c713747aa47b1e76837402145898 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Dec 2015 10:22:42 -0800 Subject: [PATCH 166/171] add fire sounds to assets JSON --- examples/baseball/assets.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json index 037eb616d2..aa0626edfc 100644 --- a/examples/baseball/assets.json +++ b/examples/baseball/assets.json @@ -80,6 +80,26 @@ "pop4.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav", "atp_url": "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" + }, + "fire1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav", + "atp_url": "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav", + "atp_url": "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav", + "atp_url": "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav", + "atp_url": "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" } } } From 70dd8ec19a518da29f384a6fa1a3264b733fbe05 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 11:44:42 -0800 Subject: [PATCH 167/171] Remove left/right relative pos/rot from c++ --- interface/src/avatar/AvatarActionHold.cpp | 76 ++++++------------- interface/src/avatar/AvatarActionHold.h | 9 +-- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 - 4 files changed, 26 insertions(+), 62 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index bff6af7337..8a59f91bc8 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -65,15 +65,13 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve } } - if (isRightHand) { - rotation = palmRotation * _rightRelativeRotation; - position = palmPosition + rotation * _rightRelativePosition; - } else { + if (!isRightHand) { static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); palmRotation *= yFlip; // Match right hand frame of reference - rotation = palmRotation * _leftRelativeRotation; - position = palmPosition + rotation * _leftRelativePosition; } + + rotation = palmRotation * _relativeRotation; + position = palmPosition + rotation * _relativePosition; }); return holdingAvatar; @@ -175,10 +173,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { } bool AvatarActionHold::updateArguments(QVariantMap arguments) { - glm::vec3 leftRelativePosition; - glm::quat leftRelativeRotation; - glm::vec3 rightRelativePosition; - glm::quat rightRelativeRotation; + glm::vec3 relativePosition; + glm::quat relativeRotation; float timeScale; QString hand; QUuid holderID; @@ -190,27 +186,15 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { bool somethingChanged = ObjectAction::updateArguments(arguments); withReadLock([&]{ bool ok = true; - leftRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "leftRelativePosition", ok, false); + relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); if (!ok) { - leftRelativePosition = _leftRelativePosition; + relativePosition = _relativePosition; } - + ok = true; - leftRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "leftRelativeRotation", ok, false); + relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); if (!ok) { - leftRelativeRotation = _leftRelativeRotation; - } - - ok = true; - rightRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "rightRelativePosition", ok, false); - if (!ok) { - rightRelativePosition = _rightRelativePosition; - } - - ok = true; - rightRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "rightRelativeRotation", ok, false); - if (!ok) { - rightRelativeRotation = _rightRelativeRotation; + relativeRotation = _relativeRotation; } ok = true; @@ -234,25 +218,17 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { _kinematic = false; } - + ok = true; kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematicSetVelocity", ok, false); if (!ok) { _kinematicSetVelocity = false; } - - ok = true; - ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false); - if (!ok) { - _ignoreIK = true; - } if (somethingChanged || - leftRelativePosition != _leftRelativePosition || - leftRelativeRotation != _leftRelativeRotation || - rightRelativePosition != _rightRelativePosition || - rightRelativeRotation != _rightRelativeRotation || + relativePosition != _relativePosition || + relativeRotation != _relativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -265,10 +241,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _leftRelativePosition = leftRelativePosition; - _leftRelativeRotation = leftRelativeRotation; - _rightRelativePosition = rightRelativePosition; - _rightRelativeRotation = rightRelativeRotation; + _relativePosition = relativePosition; + _relativeRotation = relativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -295,10 +269,8 @@ QVariantMap AvatarActionHold::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&]{ arguments["holderID"] = _holderID; - arguments["leftRelativePosition"] = glmToQMap(_leftRelativePosition); - arguments["leftRelativeRotation"] = glmToQMap(_leftRelativeRotation); - arguments["rightRelativePosition"] = glmToQMap(_rightRelativePosition); - arguments["rightRelativeRotation"] = glmToQMap(_rightRelativeRotation); + arguments["relativePosition"] = glmToQMap(_relativePosition); + arguments["relativeRotation"] = glmToQMap(_relativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -318,10 +290,8 @@ QByteArray AvatarActionHold::serialize() const { dataStream << AvatarActionHold::holdVersion; dataStream << _holderID; - dataStream << _leftRelativePosition; - dataStream << _leftRelativeRotation; - dataStream << _rightRelativePosition; - dataStream << _rightRelativeRotation; + dataStream << _relativePosition; + dataStream << _relativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -353,10 +323,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { withWriteLock([&]{ dataStream >> _holderID; - dataStream >> _leftRelativePosition; - dataStream >> _leftRelativeRotation; - dataStream >> _rightRelativePosition; - dataStream >> _rightRelativeRotation; + dataStream >> _relativePosition; + dataStream >> _relativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index d3aad19384..8a6948dde2 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -38,15 +38,12 @@ public: std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position); private: - static const uint16_t holdVersion; - void doKinematicUpdate(float deltaTimeStep); - glm::vec3 _leftRelativePosition{ Vectors::ZERO }; - glm::quat _leftRelativeRotation{ Quaternions::IDENTITY }; - glm::vec3 _rightRelativePosition{ Vectors::ZERO }; - glm::quat _rightRelativeRotation{ Quaternions::IDENTITY }; + static const uint16_t holdVersion; + glm::vec3 _relativePosition { Vectors::ZERO }; + glm::quat _relativeRotation { Quaternions::IDENTITY }; QString _hand { "right" }; QUuid _holderID; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 7bb3a1e46f..2f685b7e08 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET; + return VERSION_ENTITIES_POLYLINE_TEXTURE; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5610d31661..23df89b3d7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -160,6 +160,5 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; -const PacketVersion VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET = 51; #endif // hifi_PacketHeaders_h From 97454ae4466dc60faf86774ca4b417fee866b6b8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 12:10:49 -0800 Subject: [PATCH 168/171] Update handControllerGrab.js --- examples/controllers/handControllerGrab.js | 68 +++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0812dc8980..fca668c5e0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -200,6 +200,34 @@ function entityIsGrabbedByOther(entityID) { return false; } +function getSpatialOffsetPosition(hand, spatialKey) { + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + return spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + return spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + return spatialKey.relativePosition; + } + + return Vec3.ZERO; +} + +function getSpatialOffsetRotation(hand, spatialKey) { + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + return spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + return spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + return spatialKey.relativeRotation; + } + + return Quat.IDENTITY; +} + function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -223,17 +251,8 @@ function MyController(hand) { this.rawTriggerValue = 0; this.rawBumperValue = 0; - this.offsetPosition = { - x: 0.0, - y: 0.0, - z: 0.0 - }; - this.offsetRotation = { - x: 0.0, - y: 0.0, - z: 0.0, - w: 1.0 - }; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; var _this = this; @@ -767,12 +786,8 @@ function MyController(hand) { if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. - if (grabbableData.spatialKey.relativePosition) { - this.offsetPosition = grabbableData.spatialKey.relativePosition; - } - if (grabbableData.spatialKey.relativeRotation) { - this.offsetRotation = grabbableData.spatialKey.relativeRotation; - } + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); } else { var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); @@ -895,23 +910,8 @@ function MyController(hand) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); // use a spring to pull the object to where it will be when equipped - var relativeRotation = { - x: 0.0, - y: 0.0, - z: 0.0, - w: 1.0 - }; - var relativePosition = { - x: 0.0, - y: 0.0, - z: 0.0 - }; - if (grabbableData.spatialKey.relativePosition) { - relativePosition = grabbableData.spatialKey.relativePosition; - } - if (grabbableData.spatialKey.relativeRotation) { - relativeRotation = grabbableData.spatialKey.relativeRotation; - } + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); var targetRotation = Quat.multiply(handRotation, relativeRotation); From e6763c2208f1fc404f7a0fd7e137d0920e764bc7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 15:03:25 -0800 Subject: [PATCH 169/171] Update bow's relative position --- examples/toybox/bow/bow.js | 13 +++++++++---- examples/toybox/bow/createBow.js | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 14e3ed86ec..90199fb70f 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -67,12 +67,17 @@ } var BOW_SPATIAL_KEY = { - relativePosition: { - x: 0, + leftRelativePosition: { + x: 0.05, y: 0.06, - z: 0.11 + z: -0.05 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + rightRelativePosition: { + x: -0.05, + y: 0.06, + z: -0.05 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) } diff --git a/examples/toybox/bow/createBow.js b/examples/toybox/bow/createBow.js index 880b0920e8..9a9ed98c20 100644 --- a/examples/toybox/bow/createBow.js +++ b/examples/toybox/bow/createBow.js @@ -48,12 +48,17 @@ var bow = Entities.addEntity({ grabbableKey: { invertSolidWhileHeld: true, spatialKey: { - relativePosition: { - x: 0, + leftRelativePosition: { + x: 0.05, y: 0.06, - z: 0.11 + z: -0.05 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + rightRelativePosition: { + x: -0.05, + y: 0.06, + z: -0.05 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) } } }) From 0b93e637e8be2bf18f720d1f6032547eee0dd16e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 15:13:46 -0800 Subject: [PATCH 170/171] Update bat rotation --- examples/baseball/createBatButton.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 75f3dee26e..bbd2bea9f2 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,10 +51,9 @@ var batUserData = { grabbableKey: { spatialKey: { - relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), - perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) + leftRelativePosition: { x: 0.9, y: 0.05, z: -0.05 }, + rightRelativePosition: { x: 0.9, y: 0.05, z: 0.05 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45) } } } From 84bc947854fe4d998a2b06c0bdf35bb250d03077 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 14:00:06 -0800 Subject: [PATCH 171/171] Typo --- examples/baseball/assets.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json index aa0626edfc..00edcbe703 100644 --- a/examples/baseball/assets.json +++ b/examples/baseball/assets.json @@ -84,22 +84,22 @@ "fire1.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav", "atp_url": "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credir: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire2.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav", "atp_url": "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire3.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav", "atp_url": "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire4.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav", "atp_url": "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" } } }