diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5035f2e5a4..d308b3dc49 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -489,7 +489,7 @@ function MyController(hand) { if (grabbableData.wantsTrigger) { this.setState(STATE_NEAR_TRIGGER); return; - } else if (!props.locked) { + } else if (!props.locked && props.collisionsWillMove) { this.setState(STATE_NEAR_GRABBING); return; } diff --git a/examples/drylake/explodeHelicopter.js b/examples/drylake/explodeHelicopter.js new file mode 100644 index 0000000000..efca1a91cc --- /dev/null +++ b/examples/drylake/explodeHelicopter.js @@ -0,0 +1,144 @@ +var explosionSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/eric/sounds/explosion.wav"); + +var partsURLS = [{ + url: "https://s3.amazonaws.com/hifi-public/eric/models/blade.fbx", + dimensions: { + x: 2, + y: 2, + z: 2 + } +}, { + url: "https://s3.amazonaws.com/hifi-public/eric/models/body.fbx", + dimensions: { + x: 2.2, + y: 2.98, + z: 7.96 + } +}, { + url: "https://s3.amazonaws.com/hifi-public/eric/models/tail.fbx", + dimensions: { + x: 1, + y: 1, + z: 1 + } +}]; + +var parts = []; +var emitters = []; + +var explodePosition; +var helicopter; +var entities = Entities.findEntities(MyAvatar.position, 2000); +for (i = 0; i < entities.length; i++) { + var name = Entities.getEntityProperties(entities[i], 'name').name; + if (name === "Helicopter") { + var helicopter = entities[i]; + explodeHelicopter(Entities.getEntityProperties(helicopter, 'position').position); + } +} + + +function explodeHelicopter(explodePosition) { + Audio.playSound(explosionSound, { + position: explodePosition, + volume: 0.5 + }); + Entities.deleteEntity(helicopter); + for (var i = 0; i < partsURLS.length; i++) { + var position = Vec3.sum(explodePosition, { + x: 1, + y: 1, + z: 1 + }); + var part = Entities.addEntity({ + type: "Model", + modelURL: partsURLS[i].url, + dimensions: partsURLS[i].dimensions, + position: position, + shapeType: "box", + collisionsWillMove: true, + damping: 0, + gravity: { + x: 0, + y: -9.6, + z: 0 + }, + velocity: { + x: Math.random(), + y: -10, + z: Math.random() + } + }); + + var emitter = Entities.addEntity({ + type: "ParticleEffect", + name: "fire", + isEmitting: true, + textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png", + position: explodePosition, + emitRate: 100, + colorStart: { + red: 70, + green: 70, + blue: 137 + }, + color: { + red: 200, + green: 99, + blue: 42 + }, + colorFinish: { + red: 255, + green: 99, + blue: 32 + }, + radiusSpread: 0.2, + radiusStart: 0.3, + radiusEnd: 0.04, + particleRadius: 0.09, + radiusFinish: 0.0, + emitSpeed: 0.1, + speedSpread: 0.1, + alphaStart: 0.1, + alpha: 0.7, + alphaFinish: 0.1, + emitOrientation: Quat.fromPitchYawRollDegrees(-90, 0, 0), + emitDimensions: { + x: 1, + y: 1, + z: 0.1 + }, + polarFinish: Math.PI, + polarStart: 0, + + accelerationSpread: { + x: 0.1, + y: 0.01, + z: 0.1 + }, + lifespan: 1, + }); + emitters.push(emitter) + parts.push(part); + } + + Script.setTimeout(function() { + var pos = Entities.getEntityProperties(parts[1], "position").position; + Entities.editEntity(emitters[0], {position: Vec3.sum(pos, {x: Math.random(), y: Math.random(), z: Math.random()})}); + Entities.editEntity(emitters[1], {position: Vec3.sum(pos, {x: Math.random(), y: Math.random(), z: Math.random()})}); + Entities.editEntity(emitters[2], {position: Vec3.sum(pos, {x: Math.random(), y: Math.random(), z: Math.random()})}); + }, 5000) + + +} + +function cleanup() { + parts.forEach(function(part) { + Entities.deleteEntity(part); + }); + emitters.forEach(function(emitter){ + Entities.deleteEntity(emitter); + }) +} + +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/drylake/helicopter.js b/examples/drylake/helicopter.js new file mode 100644 index 0000000000..7073722e1e --- /dev/null +++ b/examples/drylake/helicopter.js @@ -0,0 +1,132 @@ +var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/helicopter.fbx?v3"; +var animationURL = "https://s3.amazonaws.com/hifi-public/eric/models/bladeAnimation.fbx?v7"; +var spawnPosition = { + x: 1031, + y: 145, + z: 1041 +}; + +var speed = 0; + +var helicopterSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/ryan/helicopter.L.wav"); +var audioInjector = Audio.playSound(helicopterSound, { + volume: 0.3, + loop: true +}); + +// These constants define the Spotlight position and orientation relative to the model +var MODEL_LIGHT_POSITION = { + x: 2, + y: 0, + z: -5 +}; +var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + 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) + }; +} + + +var helicopter = Entities.addEntity({ + type: "Model", + name: "Helicopter", + modelURL: modelURL, + animation: { + url: animationURL, + running: true, + fps: 180 + + }, + dimensions: { + x: 12.13, + y: 3.14, + z: 9.92 + }, + position: spawnPosition, +}); + + + +var spotlight = Entities.addEntity({ + type: "Light", + name: "helicopter light", + intensity: 2, + color: { + red: 200, + green: 200, + blue: 255 + }, + intensity: 1, + dimensions: { + x: 2, + y: 2, + z: 200 + }, + exponent: 0.01, + cutoff: 10, + isSpotlight: true +}); + +var debugLight = Entities.addEntity({ + type: "Box", + dimensions: { + x: .1, + y: .1, + z: .3 + }, + color: { + red: 200, + green: 200, + blue: 0 + } +}); + +function cleanup() { + Entities.deleteEntity(debugLight); + Entities.deleteEntity(helicopter); + Entities.deleteEntity(spotlight); + +} + +function update() { + var modelProperties = Entities.getEntityProperties(helicopter, ['position', 'rotation']); + var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + Entities.editEntity(spotlight, { + position: lightTransform.p, + rotation: lightTransform.q + }); + Entities.editEntity(debugLight, { + position: lightTransform.p, + rotation: lightTransform.q + }); + + audioInjector.setOptions({ + position: modelProperties.position, + }); + + //Move forward + var newRotation = Quat.multiply(modelProperties.rotation, { + x: 0, + y: .002, + z: 0, + w: 1 + }) + var newPosition = Vec3.sum(modelProperties.position, Vec3.multiply(speed, Quat.getFront(modelProperties.rotation))); + Entities.editEntity(helicopter, { + position: newPosition, + rotation: newRotation + }) +} + + +Script.update.connect(update); +Script.scriptEnding.connect(cleanup); \ No newline at end of file diff --git a/examples/example/games/satellite.js b/examples/example/games/satellite.js index db65198b87..9ae0105917 100644 --- a/examples/example/games/satellite.js +++ b/examples/example/games/satellite.js @@ -15,7 +15,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include('../utilities/tools/vector.js'); +Script.include('../../utilities/tools/vector.js'); var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/"; diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 88e01b29fe..e3e86cedb3 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("libraries/overlayUtils.js"); +Script.include("overlayUtils.js"); var MOUSE_SENSITIVITY = 0.9; var SCROLL_SENSITIVITY = 0.05; diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index bb84ce27b4..1aa08fbe2d 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -1,7 +1,9 @@ +var ENTITY_LIST_HTML_URL = Script.resolvePath('../html/entityList.html'); + EntityListTool = function(opts) { var that = {}; - var url = Script.resolvePath('html/entityList.html'); + var url = ENTITY_LIST_HTML_URL; var webView = new WebWindow('Entities', url, 200, 280, true); var searchRadius = 100; diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js index ed4e999be8..35d9858ace 100644 --- a/examples/libraries/gridTool.js +++ b/examples/libraries/gridTool.js @@ -1,3 +1,5 @@ +var GRID_CONTROLS_HTML_URL = Script.resolvePath('../html/gridControls.html'); + Grid = function(opts) { var that = {}; @@ -228,7 +230,7 @@ GridTool = function(opts) { var verticalGrid = opts.verticalGrid; var listeners = []; - var url = Script.resolvePath('html/gridControls.html'); + var url = GRID_CONTROLS_HTML_URL; var webView = new WebWindow('Grid', url, 200, 280, true); horizontalGrid.addListener(function(data) { diff --git a/examples/libraries/omniTool/modules/breakdanceOmniToolModule.js b/examples/libraries/omniTool/modules/breakdanceOmniToolModule.js index 36ee6b1fee..3764c5e381 100644 --- a/examples/libraries/omniTool/modules/breakdanceOmniToolModule.js +++ b/examples/libraries/omniTool/modules/breakdanceOmniToolModule.js @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("../toys/breakdanceCore.js"); +Script.include("../../../breakdanceCore.js"); OmniToolModules.Breakdance = function() { print("OmniToolModules.Breakdance..."); @@ -32,4 +32,4 @@ OmniToolModules.Breakdance.prototype.onUpdate = function(deltaTime) { breakdanceEnd(); } -OmniToolModuleType = "Breakdance"; \ No newline at end of file +OmniToolModuleType = "Breakdance"; diff --git a/examples/libraries/omniTool/modules/test.js b/examples/libraries/omniTool/modules/test.js index 9f7191b2d0..83472ee0f1 100644 --- a/examples/libraries/omniTool/modules/test.js +++ b/examples/libraries/omniTool/modules/test.js @@ -1,5 +1,5 @@ -Script.include("avatarRelativeOverlays.js"); +Script.include("../../avatarRelativeOverlays.js"); OmniToolModules.Test = function(omniTool, activeEntityId) { this.omniTool = omniTool; diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js index 8935380150..3a51491cac 100644 --- a/examples/libraries/walkApi.js +++ b/examples/libraries/walkApi.js @@ -14,7 +14,7 @@ // // included here to ensure walkApi.js can be used as an API, separate from walk.js -Script.include("./libraries/walkConstants.js"); +Script.include("walkConstants.js"); Avatar = function() { // if Hydras are connected, the only way to enable use is to never set any arm joint rotation diff --git a/examples/libraries/walkSettings.js b/examples/libraries/walkSettings.js index 3e5ac53572..0378f305b5 100644 --- a/examples/libraries/walkSettings.js +++ b/examples/libraries/walkSettings.js @@ -13,6 +13,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +var WALK_SETTINGS_HTML_URL = Script.resolvePath('../html/walkSettings.html'); + WalkSettings = function() { var _visible = false; var _innerWidth = Window.innerWidth; @@ -69,7 +71,7 @@ WalkSettings = function() { // web window const PANEL_WIDTH = 200; const PANEL_HEIGHT = 180; - var _url = Script.resolvePath('html/walkSettings.html'); + var _url = WALK_SETTINGS_HTML_URL; var _webWindow = new WebWindow('Walk Settings', _url, PANEL_WIDTH, PANEL_HEIGHT, false); _webWindow.setVisible(false); _webWindow.eventBridge.webEventReceived.connect(function(data) { diff --git a/examples/magBalls.js b/examples/magBalls.js index c9b45164ab..bda6ccd9c3 100644 --- a/examples/magBalls.js +++ b/examples/magBalls.js @@ -7,11 +7,11 @@ // // FIXME Script paths have to be relative to the caller, in this case libraries/OmniTool.js -Script.include("../magBalls/constants.js"); -Script.include("../magBalls/graph.js"); -Script.include("../magBalls/edgeSpring.js"); -Script.include("../magBalls/magBalls.js"); -Script.include("avatarRelativeOverlays.js"); +Script.include("magBalls/constants.js"); +Script.include("magBalls/graph.js"); +Script.include("magBalls/edgeSpring.js"); +Script.include("magBalls/magBalls.js"); +Script.include("libraries/avatarRelativeOverlays.js"); OmniToolModuleType = "MagBallsController" @@ -34,7 +34,7 @@ MODE_INFO[BALL_EDIT_MODE_ADD] = { }, colors: [ COLORS.GREEN, COLORS.BLUE ], // FIXME use an http path or find a way to get the relative path to the file - url: Script.resolvePath('../html/magBalls/addMode.html'), + url: Script.resolvePath('html/magBalls/addMode.html'), }; MODE_INFO[BALL_EDIT_MODE_DELETE] = { @@ -45,7 +45,7 @@ MODE_INFO[BALL_EDIT_MODE_DELETE] = { }, colors: [ COLORS.RED, COLORS.BLUE ], // FIXME use an http path or find a way to get the relative path to the file - url: Script.resolvePath('../html/magBalls/deleteMode.html'), + url: Script.resolvePath('html/magBalls/deleteMode.html'), }; var UI_POSITION_MODE_LABEL = Vec3.multiply(0.5, diff --git a/examples/painting/closePaint.js b/examples/painting/closePaint.js index d9f70aab3c..563ed1dafb 100644 --- a/examples/painting/closePaint.js +++ b/examples/painting/closePaint.js @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("libraries/utils.js"); +Script.include("../libraries/utils.js"); var RIGHT_HAND = 1; diff --git a/examples/toybox/bubblewand/createWand.js b/examples/toybox/bubblewand/createWand.js index d62c2064cf..4f4bc39e2c 100644 --- a/examples/toybox/bubblewand/createWand.js +++ b/examples/toybox/bubblewand/createWand.js @@ -10,7 +10,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -Script.include("../../utilities.js"); Script.include("../../libraries/utils.js"); var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/models/bubblewand/wand.fbx'; diff --git a/examples/toybox/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js index c8ba51f51d..4bdc789612 100644 --- a/examples/toybox/bubblewand/wand.js +++ b/examples/toybox/bubblewand/wand.js @@ -14,7 +14,6 @@ (function () { - Script.include("../../utilities.js"); Script.include("../../libraries/utils.js"); var BUBBLE_MODEL = "http://hifi-public.s3.amazonaws.com/models/bubblewand/bubble.fbx"; diff --git a/examples/toybox/doll/doll.js b/examples/toybox/doll/doll.js index 8f8a8cd840..577f86cae2 100644 --- a/examples/toybox/doll/doll.js +++ b/examples/toybox/doll/doll.js @@ -13,7 +13,6 @@ /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ (function() { - Script.include("../../utilities.js"); Script.include("../../libraries/utils.js"); var _this; // this is the "constructor" for the entity as a JS object we don't do much here diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 9639f75320..705671e784 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -Script.include("../../utilities.js"); +Script.include("../../libraries/utils.js"); var scriptURL = Script.resolvePath('pingPongGun.js'); diff --git a/examples/toybox/ping_pong_gun/createTargets.js b/examples/toybox/ping_pong_gun/createTargets.js index fb286b1928..fde0d6f54a 100644 --- a/examples/toybox/ping_pong_gun/createTargets.js +++ b/examples/toybox/ping_pong_gun/createTargets.js @@ -10,7 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -Script.include("../../utilities.js"); + Script.include("../../libraries/utils.js"); var scriptURL = Script.resolvePath('wallTarget.js'); diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index 8a24543b74..d4988fc00d 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -14,7 +14,7 @@ ] }, { "from": "Standard.RX", "to": "Actions.Yaw" }, - + { "from": "Standard.RY", "when": "Application.Grounded", "to": "Actions.Up", diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8595fa850e..6f60ad179c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1132,14 +1132,6 @@ void MyAvatar::setJointRotations(QVector jointRotations) { } } -void MyAvatar::setJointTranslations(QVector jointTranslations) { - int numStates = glm::min(_skeletonModel.getJointStateCount(), jointTranslations.size()); - for (int i = 0; i < numStates; ++i) { - // HACK: ATM only Recorder calls setJointTranslations() so we hardcode its priority here - _skeletonModel.setJointTranslation(i, true, jointTranslations[i], RECORDER_PRIORITY); - } -} - void MyAvatar::setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setJointData", Q_ARG(int, index), Q_ARG(const glm::quat&, rotation), diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d6f51636f3..da836b7f15 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -192,7 +192,6 @@ public: void clearLookAtTargetAvatar(); virtual void setJointRotations(QVector jointRotations) override; - virtual void setJointTranslations(QVector jointTranslations) override; virtual void setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) override; virtual void setJointRotation(int index, const glm::quat& rotation) override; virtual void setJointTranslation(int index, const glm::vec3& translation) override; diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 5e29963e4b..47fc1390d9 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -246,24 +246,38 @@ void Player::play() { nextFrame.getScale(), _frameInterpolationFactor); _avatar->setTargetScale(context->scale * scale); - - - QVector jointRotations(currentFrame.getJointRotations().size()); - for (int i = 0; i < currentFrame.getJointRotations().size(); ++i) { - jointRotations[i] = safeMix(currentFrame.getJointRotations()[i], - nextFrame.getJointRotations()[i], - _frameInterpolationFactor); + + // Joint array playback + // FIXME: THis is still using a deprecated path to assign the joint orientation since setting the full RawJointData array doesn't + // work for Avatar. We need to fix this working with the animation team + const auto& prevJointArray = currentFrame.getJointArray(); + const auto& nextJointArray = currentFrame.getJointArray(); + QVector jointArray(prevJointArray.size()); + QVector jointRotations(prevJointArray.size()); // FIXME: remove once the setRawJointData is fixed + QVector jointTranslations(prevJointArray.size()); // FIXME: remove once the setRawJointData is fixed + + for (int i = 0; i < jointArray.size(); i++) { + const auto& prevJoint = prevJointArray[i]; + const auto& nextJoint = nextJointArray[i]; + auto& joint = jointArray[i]; + + // Rotation + joint.rotationSet = prevJoint.rotationSet || nextJoint.rotationSet; + if (joint.rotationSet) { + joint.rotation = safeMix(prevJoint.rotation, nextJoint.rotation, _frameInterpolationFactor); + jointRotations[i] = joint.rotation; // FIXME: remove once the setRawJointData is fixed + } + + joint.translationSet = prevJoint.translationSet || nextJoint.translationSet; + if (joint.translationSet) { + joint.translation = glm::mix(prevJoint.translation, nextJoint.translation, _frameInterpolationFactor); + jointTranslations[i] = joint.translation; // FIXME: remove once the setRawJointData is fixed + } } - QVector jointTranslations(currentFrame.getJointTranslations().size()); - for (int i = 0; i < currentFrame.getJointTranslations().size(); ++i) { - jointTranslations[i] = - currentFrame.getJointTranslations()[i] * (1.0f - _frameInterpolationFactor) + - nextFrame.getJointTranslations()[i] * _frameInterpolationFactor; - } - - _avatar->setJointRotations(jointRotations); - _avatar->setJointTranslations(jointTranslations); + // _avatar->setRawJointData(jointArray); // FIXME: Enable once the setRawJointData is fixed + _avatar->setJointRotations(jointRotations); // FIXME: remove once the setRawJointData is fixed + // _avatar->setJointTranslations(jointTranslations); // FIXME: remove once the setRawJointData is fixed HeadData* head = const_cast(_avatar->getHeadData()); if (head) { @@ -423,3 +437,4 @@ bool Player::computeCurrentFrame() { } return true; } + diff --git a/libraries/avatars/src/Recorder.cpp b/libraries/avatars/src/Recorder.cpp index 8a90500f00..5e47c296eb 100644 --- a/libraries/avatars/src/Recorder.cpp +++ b/libraries/avatars/src/Recorder.cpp @@ -100,12 +100,15 @@ void Recorder::record() { const RecordingContext& context = _recording->getContext(); RecordingFrame frame; frame.setBlendshapeCoefficients(_avatar->getHeadData()->getBlendshapeCoefficients()); - frame.setJointRotations(_avatar->getJointRotations()); + + // Capture the full skeleton joint data + auto& jointData = _avatar->getRawJointData(); + frame.setJointArray(jointData); + frame.setTranslation(context.orientationInv * (_avatar->getPosition() - context.position)); frame.setRotation(context.orientationInv * _avatar->getOrientation()); frame.setScale(_avatar->getTargetScale() / context.scale); - - + const HeadData* head = _avatar->getHeadData(); if (head) { glm::vec3 rotationDegrees = glm::vec3(head->getFinalPitch(), @@ -123,7 +126,7 @@ void Recorder::record() { if (wantDebug) { qCDebug(avatars) << "Recording frame #" << _recording->getFrameNumber(); qCDebug(avatars) << "Blendshapes:" << frame.getBlendshapeCoefficients().size(); - qCDebug(avatars) << "JointRotations:" << frame.getJointRotations().size(); + qCDebug(avatars) << "JointArray:" << frame.getJointArray().size(); qCDebug(avatars) << "Translation:" << frame.getTranslation(); qCDebug(avatars) << "Rotation:" << frame.getRotation(); qCDebug(avatars) << "Scale:" << frame.getScale(); diff --git a/libraries/avatars/src/Recording.cpp b/libraries/avatars/src/Recording.cpp index 2e2f46552d..26c5ab66dd 100644 --- a/libraries/avatars/src/Recording.cpp +++ b/libraries/avatars/src/Recording.cpp @@ -229,22 +229,27 @@ void writeRecordingToFile(RecordingPointer recording, const QString& filename) { ++maskIndex; } - // Joint Rotations + const auto& jointArray = frame.getJointArray(); if (i == 0) { - numJoints = frame.getJointRotations().size(); + numJoints = jointArray.size(); stream << numJoints; - mask.resize(mask.size() + numJoints); + // 2 fields per joints + mask.resize(mask.size() + numJoints * 2); } - for (quint32 j = 0; j < numJoints; ++j) { - if (i == 0 || - frame._jointRotations[j] != previousFrame._jointRotations[j]) { - writeQuat(stream, frame._jointRotations[j]); - // TODO -- handle translations + for (quint32 j = 0; j < numJoints; j++) { + const auto& joint = jointArray[j]; + if (true) { //(joint.rotationSet) { + writeQuat(stream, joint.rotation); + mask.setBit(maskIndex); + } + maskIndex++; + if (joint.translationSet) { + writeVec3(stream, joint.translation); mask.setBit(maskIndex); } maskIndex++; } - + // Translation if (i == 0) { mask.resize(mask.size() + 1); @@ -408,11 +413,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString file.close(); } - if (filename.endsWith(".rec") || filename.endsWith(".REC")) { - qCDebug(avatars) << "Old .rec format"; - readRecordingFromRecFile(recording, filename, byteArray); - return recording; - } else if (!filename.endsWith(".hfr") && !filename.endsWith(".HFR")) { + if (!filename.endsWith(".hfr") && !filename.endsWith(".HFR")) { qCDebug(avatars) << "File extension not recognized"; } @@ -552,19 +553,28 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString stream >> frame._blendshapeCoefficients[j]; } } - // Joint Rotations + // Joint Array if (i == 0) { stream >> numJoints; } - frame._jointRotations.resize(numJoints); + + frame._jointArray.resize(numJoints); for (quint32 j = 0; j < numJoints; ++j) { - if (!mask[maskIndex++] || !readQuat(stream, frame._jointRotations[j])) { - frame._jointRotations[j] = previousFrame._jointRotations[j]; + auto& joint = frame._jointArray[2]; + + if (mask[maskIndex++] && readQuat(stream, joint.rotation)) { + joint.rotationSet = true; + } else { + joint.rotationSet = false; + } + + if (mask[maskIndex++] || readVec3(stream, joint.translation)) { + joint.translationSet = true; + } else { + joint.translationSet = false; } } - // TODO -- handle translations - if (!mask[maskIndex++] || !readVec3(stream, frame._translation)) { frame._translation = previousFrame._translation; } @@ -649,167 +659,3 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString return recording; } - -RecordingPointer readRecordingFromRecFile(RecordingPointer recording, const QString& filename, const QByteArray& byteArray) { - QElapsedTimer timer; - timer.start(); - - if (!recording) { - recording = QSharedPointer::create(); - } - - QDataStream fileStream(byteArray); - - fileStream >> recording->_timestamps; - RecordingFrame baseFrame; - - // Blendshape coefficients - fileStream >> baseFrame._blendshapeCoefficients; - - // Joint Rotations - int jointRotationSize; - fileStream >> jointRotationSize; - baseFrame._jointRotations.resize(jointRotationSize); - for (int i = 0; i < jointRotationSize; ++i) { - fileStream >> baseFrame._jointRotations[i].x >> baseFrame._jointRotations[i].y >> baseFrame._jointRotations[i].z >> baseFrame._jointRotations[i].w; - } - - // TODO -- handle translations - - fileStream >> baseFrame._translation.x >> baseFrame._translation.y >> baseFrame._translation.z; - fileStream >> baseFrame._rotation.x >> baseFrame._rotation.y >> baseFrame._rotation.z >> baseFrame._rotation.w; - fileStream >> baseFrame._scale; - fileStream >> baseFrame._headRotation.x >> baseFrame._headRotation.y >> baseFrame._headRotation.z >> baseFrame._headRotation.w; - fileStream >> baseFrame._leanSideways; - fileStream >> baseFrame._leanForward; - - - // Fake context - RecordingContext& context = recording->getContext(); - context.globalTimestamp = usecTimestampNow(); - context.domain = DependencyManager::get()->getDomainHandler().getHostname(); - context.position = glm::vec3(144.5f, 3.3f, 181.3f); - context.orientation = glm::angleAxis(glm::radians(-92.5f), glm::vec3(0, 1, 0));; - context.scale = baseFrame._scale; - context.headModel = "http://public.highfidelity.io/models/heads/Emily_v4.fst"; - context.skeletonModel = "http://public.highfidelity.io/models/skeletons/EmilyCutMesh_A.fst"; - context.displayName = "Leslie"; - context.attachments.clear(); - AttachmentData data; - data.modelURL = "http://public.highfidelity.io/models/attachments/fbx.fst"; - data.jointName = "RightHand" ; - data.translation = glm::vec3(0.04f, 0.07f, 0.0f); - data.rotation = glm::angleAxis(glm::radians(102.0f), glm::vec3(0, 1, 0)); - data.scale = 0.20f; - context.attachments << data; - - context.orientationInv = glm::inverse(context.orientation); - - baseFrame._translation = glm::vec3(); - baseFrame._rotation = glm::quat(); - baseFrame._scale = 1.0f; - - recording->_frames << baseFrame; - - for (int i = 1; i < recording->_timestamps.size(); ++i) { - QBitArray mask; - QByteArray buffer; - QDataStream stream(&buffer, QIODevice::ReadOnly); - RecordingFrame frame; - RecordingFrame& previousFrame = recording->_frames.last(); - - fileStream >> mask; - fileStream >> buffer; - int maskIndex = 0; - - // Blendshape Coefficients - frame._blendshapeCoefficients.resize(baseFrame._blendshapeCoefficients.size()); - for (int i = 0; i < baseFrame._blendshapeCoefficients.size(); ++i) { - if (mask[maskIndex++]) { - stream >> frame._blendshapeCoefficients[i]; - } else { - frame._blendshapeCoefficients[i] = previousFrame._blendshapeCoefficients[i]; - } - } - - // Joint Rotations - frame._jointRotations.resize(baseFrame._jointRotations.size()); - for (int i = 0; i < baseFrame._jointRotations.size(); ++i) { - if (mask[maskIndex++]) { - stream >> frame._jointRotations[i].x >> frame._jointRotations[i].y >> frame._jointRotations[i].z >> frame._jointRotations[i].w; - } else { - frame._jointRotations[i] = previousFrame._jointRotations[i]; - } - } - - // TODO -- handle translations - - if (mask[maskIndex++]) { - stream >> frame._translation.x >> frame._translation.y >> frame._translation.z; - frame._translation = context.orientationInv * frame._translation; - } else { - frame._translation = previousFrame._translation; - } - - if (mask[maskIndex++]) { - stream >> frame._rotation.x >> frame._rotation.y >> frame._rotation.z >> frame._rotation.w; - } else { - frame._rotation = previousFrame._rotation; - } - - if (mask[maskIndex++]) { - stream >> frame._scale; - } else { - frame._scale = previousFrame._scale; - } - - if (mask[maskIndex++]) { - stream >> frame._headRotation.x >> frame._headRotation.y >> frame._headRotation.z >> frame._headRotation.w; - } else { - frame._headRotation = previousFrame._headRotation; - } - - if (mask[maskIndex++]) { - stream >> frame._leanSideways; - } else { - frame._leanSideways = previousFrame._leanSideways; - } - - if (mask[maskIndex++]) { - stream >> frame._leanForward; - } else { - frame._leanForward = previousFrame._leanForward; - } - - recording->_frames << frame; - } - - QByteArray audioArray; - fileStream >> audioArray; - - // Cut down audio if necessary - int SAMPLE_SIZE = 2; // 16 bits - int MSEC_PER_SEC = 1000; - int audioLength = recording->getLength() * SAMPLE_SIZE * (AudioConstants::SAMPLE_RATE / MSEC_PER_SEC); - audioArray.chop(audioArray.size() - audioLength); - - recording->addAudioPacket(audioArray); - - qCDebug(avatars) << "Read " << byteArray.size() << " bytes in " << timer.elapsed() << " ms."; - - // Set new filename - QString newFilename = filename; - if (newFilename.startsWith("http") || newFilename.startsWith("https") || newFilename.startsWith("ftp")) { - newFilename = QUrl(newFilename).fileName(); - } - if (newFilename.endsWith(".rec") || newFilename.endsWith(".REC")) { - newFilename.chop(qstrlen(".rec")); - } - newFilename.append(".hfr"); - newFilename = QFileInfo(newFilename).absoluteFilePath(); - - // Set recording to new format - writeRecordingToFile(recording, newFilename); - qCDebug(avatars) << "Recording has been successfully converted at" << newFilename; - return recording; -} diff --git a/libraries/avatars/src/Recording.h b/libraries/avatars/src/Recording.h index 3533af6535..7657a12b46 100644 --- a/libraries/avatars/src/Recording.h +++ b/libraries/avatars/src/Recording.h @@ -25,6 +25,7 @@ class AttachmentData; class Recording; class RecordingFrame; class Sound; +class JointData; typedef QSharedPointer RecordingPointer; @@ -82,8 +83,7 @@ private: class RecordingFrame { public: QVector getBlendshapeCoefficients() const { return _blendshapeCoefficients; } - QVector getJointRotations() const { return _jointRotations; } - QVector getJointTranslations() const { return _jointTranslations; } + QVector getJointArray() const { return _jointArray; } glm::vec3 getTranslation() const { return _translation; } glm::quat getRotation() const { return _rotation; } float getScale() const { return _scale; } @@ -94,8 +94,7 @@ public: protected: void setBlendshapeCoefficients(QVector blendshapeCoefficients); - void setJointRotations(QVector jointRotations) { _jointRotations = jointRotations; } - void setJointTranslations(QVector jointTranslations) { _jointTranslations = jointTranslations; } + void setJointArray(const QVector& jointArray) { _jointArray = jointArray; } void setTranslation(const glm::vec3& translation) { _translation = translation; } void setRotation(const glm::quat& rotation) { _rotation = rotation; } void setScale(float scale) { _scale = scale; } @@ -106,8 +105,8 @@ protected: private: QVector _blendshapeCoefficients; - QVector _jointRotations; - QVector _jointTranslations; + QVector _jointArray; + glm::vec3 _translation; glm::quat _rotation; float _scale; @@ -125,6 +124,5 @@ private: void writeRecordingToFile(RecordingPointer recording, const QString& filename); RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString& filename); -RecordingPointer readRecordingFromRecFile(RecordingPointer recording, const QString& filename, const QByteArray& byteArray); #endif // hifi_Recording_h diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 405815aa5b..0f62bf8cd5 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -902,14 +902,19 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac BatchLoader* loader = new BatchLoader(urls); auto evaluateScripts = [=](const QMap& data) { + auto parentURL = _parentURL; for (QUrl url : urls) { QString contents = data[url]; if (contents.isNull()) { qCDebug(scriptengine) << "Error loading file: " << url << "line:" << __LINE__; } else { + // Set the parent url so that path resolution will be relative + // to this script's url during its initial evaluation + _parentURL = url.toString(); QScriptValue result = evaluate(contents, url.toString()); } } + _parentURL = parentURL; if (callback.isFunction()) { QScriptValue(callback).call();