diff --git a/examples/editModels.js b/examples/editModels.js index d0e69807aa..7f4c27814c 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -2787,13 +2787,13 @@ function setupModelMenus() { print("delete exists... don't add ours"); } + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Small Models", shortcutKey: "CTRL+META+S", afterItem: "Allow Select Large Models", isCheckable: true }); - Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, beforeItem: "Settings" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Models", shortcutKey: "CTRL+META+E", afterItem: "Models" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); @@ -2809,6 +2809,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } + Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Select Large Models"); Menu.removeMenuItem("Edit", "Allow Select Small Models"); @@ -2883,16 +2884,21 @@ function handeMenuEvent(menuItem) { } else { print(" Delete Entity.... not holding..."); } - } else if (menuItem == "Model List") { + } else if (menuItem == "Model List...") { var models = new Array(); models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); for (var i = 0; i < models.length; i++) { models[i].properties = Entities.getEntityProperties(models[i]); models[i].toString = function() { - var modelname = decodeURIComponent( - this.properties.modelURL.indexOf("/") != -1 ? - this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : - this.properties.modelURL); + var modelname; + if (this.properties.type == "Model") { + modelname = decodeURIComponent( + this.properties.modelURL.indexOf("/") != -1 ? + this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : + this.properties.modelURL); + } else { + modelname = this.properties.id; + } return "[" + this.properties.type + "] " + modelname; }; } diff --git a/examples/followThroughOverlappingAction.js b/examples/followThroughOverlappingAction.js new file mode 100644 index 0000000000..fdbd5e5550 --- /dev/null +++ b/examples/followThroughOverlappingAction.js @@ -0,0 +1,986 @@ +// +// follow-through-and-overlapping-action.js +// +// Simple demonstration showing the visual effect of adding the Disney +// follow through and overlapping action animation technique to avatar movement. +// +// Designed and created by David Wooldridge and Ozan Serim, August 2014 +// +// Version 1.001 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// location of overlay images +var pathToOverlays = "https://s3.amazonaws.com/hifi-public/ArmSwingScript/ArmSwingOverlays/"; + +// animation +var LEFT = 1; +var RIGHT = 2; +var DIRECTION = 0; + +// min max +var weightMin = 1; +var weightMax = 20; +var jointEffectMax = 5; + +// animation effect variables +var handEffect = 3.4; // 0 to jointEffectMax +var forearmEffect = 2.5; // 0 to jointEffectMax +var limbWeight = 8; // will only use nearest integer, as defines an array length +var effectStrength = 1; // 0 to 1 - overall effect strength +// Overshoot: false uses upper arm as driver for forearm and hand +// true uses upper arm for forearm and lower arm as driver for hand. +var overShoot = false; + +// animate self (tap the 'r' key) +var animateSelf = false; +var selfAnimateFrequency = 7.5; + +// overlay values +var handleValue = 0; +var controlPosX = Window.innerWidth / 2 - 500; +var controlPosY = 0; +var minSliderX = controlPosX + 18; +var sliderRangeX = 190; +var minHandleX = controlPosX - 50; +var handleRangeX = 350 / 2; +var handlePosition = 0; + +// background overlay +var controllerBackground = Overlays.addOverlay("image", { + bounds: {x: controlPosX, y: controlPosY, width: 250, height: 380}, + imageURL: pathToOverlays + "flourish-augmentation-control-overlay.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var controllerRadioSelectedBackground = Overlays.addOverlay("image", { + bounds: {x: controlPosX, y: controlPosY, width: 250, height: 380}, + imageURL: pathToOverlays + "flourish-augmentation-control-radio-selected-overlay.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false + }); +// handle overlay +var applyMotionHandle = Overlays.addOverlay("image", { + bounds: {x: minHandleX+handleRangeX-39, y: controlPosY+232, + width: 79, height: 100}, + imageURL: pathToOverlays + "flourish-augmentation-handle-overlay.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); +// slider overlays +var handEffectSlider = Overlays.addOverlay("image", { + bounds: {x: minSliderX + (handEffect / jointEffectMax * sliderRangeX), + y: controlPosY + 46, width: 25, height: 25}, + imageURL: pathToOverlays + "ddao-slider-handle.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var forearmEffectSlider = Overlays.addOverlay("image", { + bounds: {x: minSliderX + (forearmEffect / jointEffectMax * sliderRangeX), y: controlPosY + 86, + width: 25, height: 25}, + imageURL: pathToOverlays + "ddao-slider-handle.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var limbWeightSlider = Overlays.addOverlay("image", { + bounds: {x: minSliderX + (limbWeight / weightMax * sliderRangeX), y: controlPosY+126, + width: 25, height: 25}, + imageURL: pathToOverlays + "ddao-slider-handle.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var effectStrengthSlider = Overlays.addOverlay("image", { + bounds: {x: minSliderX + (effectStrength * sliderRangeX), y: controlPosY+206, + width: 25, height: 25}, + imageURL: pathToOverlays + "ddao-slider-handle.png", + color: {red: 255, green: 255, blue: 255}, + alpha: 1 + }); + + +// main loop - using averaging filters to add limb element follow-through +var upperArmPDampingFilter = []; +upperArmPDampingFilter.length = parseInt(limbWeight); // sets amount of damping for upper arm pitch +var forearmPDampingFilter = []; +forearmPDampingFilter.length = parseInt(limbWeight) + 2; // sets amount of damping for lower arm pitch + +var cumulativeTime = 0; + +Script.update.connect(function(deltaTime) { + + // used for self animating (press r to invoke) + cumulativeTime += deltaTime; + + // blend three keyframes using handle position to determine progress between keyframes + var animationProgress = handleValue; + + if(animateSelf) { + animationProgress = Math.sin(cumulativeTime * selfAnimateFrequency); + animationProgress++; + animationProgress /= 2; + } + + var keyframeOneWeight = 0; + var keyframeTwoWeight = 0; + var keyframeThreeWeight = 0; + + if(movingHandle || animateSelf) { + keyframeOneWeight = 0; + keyframeTwoWeight = animationProgress; + keyframeThreeWeight = 1 - animationProgress; + } + else if(!movingHandle) { + // idle + keyframeOneWeight = 1; + keyframeTwoWeight = 0; + keyframeThreeWeight = 0; + } + + var shoulderPitch = + keyframeOneWeight * keyFrameOne.joints[8].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[8].pitchOffset; + + var upperArmPitch = + keyframeOneWeight * keyFrameOne.joints[9].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[9].pitchOffset; + + // get the change in upper arm pitch and use to add weight effect to forearm (always) and hand (only for overShoot) + var deltaUpperArmPitch = effectStrength * + (upperArmPDampingFilter[upperArmPDampingFilter.length - 1] - + upperArmPDampingFilter[0]); + + var forearmPitch = + keyframeOneWeight * keyFrameOne.joints[10].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[10].pitchOffset - + (deltaUpperArmPitch/(jointEffectMax - forearmEffect)); + + // there are two methods for calculating the hand follow through + var handPitch = 0; + if(overShoot) { + + // get the change in forearm pitch and use to add weight effect to hand + var deltaForearmPitch = effectStrength * + (forearmPDampingFilter[forearmPDampingFilter.length - 1] - + forearmPDampingFilter[0]); + handPitch = + keyframeOneWeight * keyFrameOne.joints[11].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[11].pitchOffset + + (deltaForearmPitch /(jointEffectMax - handEffect)); // hand driven by forearm + + } else { + + handPitch = + keyframeOneWeight * keyFrameOne.joints[11].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[11].pitchOffset - + (deltaUpperArmPitch /(jointEffectMax - handEffect)); // hand driven by upper arm + } + + var shoulderYaw = + keyframeOneWeight * keyFrameOne.joints[8].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[8].yawOffset; + + var upperArmYaw = + keyframeOneWeight * keyFrameOne.joints[9].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[9].yawOffset; + + var lowerArmYaw = + keyframeOneWeight * keyFrameOne.joints[10].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[10].yawOffset; + + var handYaw = + keyframeOneWeight * keyFrameOne.joints[11].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[11].yawOffset; + + var shoulderRoll = + keyframeOneWeight * keyFrameOne.joints[8].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[8].rollOffset; + + var upperArmRoll = + keyframeOneWeight * keyFrameOne.joints[9].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[9].rollOffset; + + var lowerArmRoll = + keyframeOneWeight * keyFrameOne.joints[10].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[10].rollOffset; + + var handRoll = + keyframeOneWeight * keyFrameOne.joints[11].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[11].rollOffset; + + // filter upper arm pitch + upperArmPDampingFilter.push(upperArmPitch); + upperArmPDampingFilter.shift(); + var upperArmPitchFiltered = 0; + for(ea in upperArmPDampingFilter) upperArmPitchFiltered += upperArmPDampingFilter[ea]; + upperArmPitchFiltered /= upperArmPDampingFilter.length; + upperArmPitch = (effectStrength * upperArmPitchFiltered) + ((1 - effectStrength) * upperArmPitch); + + // filter forearm pitch only if using for hand follow-though + if(overShoot) { + + forearmPDampingFilter.push(forearmPitch); + forearmPDampingFilter.shift(); + var forearmPitchFiltered = 0; + for(ea in forearmPDampingFilter) forearmPitchFiltered += forearmPDampingFilter[ea]; + forearmPitchFiltered /= forearmPDampingFilter.length; + forearmPitch = (effectStrength*forearmPitchFiltered) + ((1-effectStrength) * forearmPitch); + } + + // apply the new rotation data to the joints + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(shoulderPitch, shoulderYaw, shoulderRoll)); + MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees(upperArmPitch, -upperArmYaw, upperArmRoll)); + MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(forearmPitch, lowerArmYaw, lowerArmRoll)); + MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees(handPitch, handYaw, handRoll)); +}); + + +// mouse handling +var movingHandEffectSlider = false; +var movingForearmEffectSlider = false; +var movingLimbWeightSlider = false; +var movingDampingSlider = false; +var movingEffectStrengthSlider = false; +var movingHandle = false; + +function mousePressEvent(event) { + + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if(clickedOverlay === applyMotionHandle) movingHandle = true; + else if(clickedOverlay === handEffectSlider) movingHandEffectSlider = true; + else if(clickedOverlay === forearmEffectSlider) movingForearmEffectSlider = true; + else if(clickedOverlay === limbWeightSlider) movingLimbWeightSlider = true; + else if(clickedOverlay === effectStrengthSlider) movingEffectStrengthSlider = true; + else if(clickedOverlay === controllerRadioSelectedBackground && + event.x > 477 && event.x < 497 && event.y > 338 && event.y < 360) { + + overShoot = false; + Overlays.editOverlay(controllerBackground, {visible: true}); + Overlays.editOverlay(controllerRadioSelectedBackground, {visible: false}); + } + else if(clickedOverlay === controllerBackground && + event.x > 477 && event.x < 497 && event.y > 338 && event.y < 360){ + + overShoot = true; + Overlays.editOverlay(controllerBackground, {visible: false}); + Overlays.editOverlay(controllerRadioSelectedBackground, {visible: true}); + } +} +function mouseMoveEvent(event) { + + if(movingHandle) { + + var thumbClickOffsetX = event.x - minHandleX; + var thumbPositionNormalised = (thumbClickOffsetX - handleRangeX) / handleRangeX; + if(thumbPositionNormalised <= -1) thumbPositionNormalised = -1; + else if(thumbPositionNormalised > 1) thumbPositionNormalised = 1; + + if(thumbPositionNormalised < 0) DIRECTION = LEFT; + else DIRECTION = RIGHT; + + handleValue = (thumbPositionNormalised + 1) / 2; + var handleX = (thumbPositionNormalised * handleRangeX) + handleRangeX - 39; + Overlays.editOverlay(applyMotionHandle, {x: handleX + minHandleX}); + return; + } + else if(movingHandEffectSlider) { + + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised < 0) thumbPositionNormalised = 0; + if(thumbPositionNormalised > 1) thumbPositionNormalised = 1; + handEffect = (thumbPositionNormalised - 0.08) * jointEffectMax; + var sliderX = thumbPositionNormalised * sliderRangeX ; + Overlays.editOverlay(handEffectSlider, {x: sliderX + minSliderX}); + } + else if(movingForearmEffectSlider) { + + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised < 0) thumbPositionNormalised = 0; + if(thumbPositionNormalised > 1) thumbPositionNormalised = 1; + forearmEffect = (thumbPositionNormalised - 0.1) * jointEffectMax; + var sliderX = thumbPositionNormalised * sliderRangeX ; + Overlays.editOverlay(forearmEffectSlider, {x: sliderX + minSliderX}); + } + else if(movingLimbWeightSlider) { + + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised<0) thumbPositionNormalised = 0; + if(thumbPositionNormalised>1) thumbPositionNormalised = 1; + limbWeight = thumbPositionNormalised * weightMax; + if(limbWeight < weightMin) limbWeight = weightMin; + upperArmPDampingFilter.length = parseInt(limbWeight); + var sliderX = thumbPositionNormalised * sliderRangeX ; + Overlays.editOverlay(limbWeightSlider, {x: sliderX + minSliderX}); + } + else if(movingEffectStrengthSlider) { + + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised < 0) thumbPositionNormalised = 0; + if(thumbPositionNormalised > 1) thumbPositionNormalised = 1; + effectStrength = thumbPositionNormalised; + var sliderX = thumbPositionNormalised * sliderRangeX ; + Overlays.editOverlay(effectStrengthSlider, {x: sliderX + minSliderX}); + return; + } +} +function mouseReleaseEvent(event) { + + if(movingHandle) { + + movingHandle = false; + handleValue = 0; + Overlays.editOverlay(applyMotionHandle, {x: minHandleX+handleRangeX - 39}); + } + else if(movingHandEffectSlider) movingHandEffectSlider = false; + else if(movingForearmEffectSlider) movingForearmEffectSlider = false; + else if(movingLimbWeightSlider) movingLimbWeightSlider = false; + else if(movingEffectStrengthSlider) movingEffectStrengthSlider = false; + else if(movingDampingSlider) movingDampingSlider = false; +} + +// set up mouse and keyboard callbacks +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); +Controller.keyPressEvent.connect(keyPressEvent); + +// keyboard command +function keyPressEvent(event) { + + if (event.text == "q") { + print('hand effect = ' + handEffect + '\n'); + print('forearmEffect = ' + forearmEffect + '\n'); + print('limbWeight = ' + limbWeight + '\n'); + print('effectStrength = ' + effectStrength + '\n'); + } + else if (event.text == "r") { + animateSelf = !animateSelf; + } + else if (event.text == "[") { + selfAnimateFrequency += 0.5; + print('selfAnimateFrequency = '+selfAnimateFrequency); + } + else if (event.text == "]") { + selfAnimateFrequency -= 0.5; + print('selfAnimateFrequency = '+selfAnimateFrequency); + } +} + + +// zero out all joints +function resetJoints() { + + var avatarJointNames = MyAvatar.getJointNames(); + for (var i = 0; i < avatarJointNames.length; i++) + MyAvatar.clearJointData(avatarJointNames[i]); +} + +// Script ending +Script.scriptEnding.connect(function() { + + // delete the overlays + Overlays.deleteOverlay(controllerBackground); + Overlays.deleteOverlay(controllerRadioSelectedBackground); + Overlays.deleteOverlay(handEffectSlider); + Overlays.deleteOverlay(forearmEffectSlider); + Overlays.deleteOverlay(limbWeightSlider); + Overlays.deleteOverlay(effectStrengthSlider); + Overlays.deleteOverlay(applyMotionHandle); + + // leave the avi in zeroed out stance + resetJoints(); +}); + + +// animation data. animation keyframes produced using walk.js +MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(80,0,0)); +var keyFrameOne = +{ + "name":"FemaleStandingOne", + "settings":{ + "baseFrequency":70, + "flyingHipsPitch":60, + "takeFlightVelocity":40, + "maxBankingAngle":40 + }, + "adjusters":{ + "legsSeparation":{ + "strength":-0.03679245283018867, + "separationAngle":50 + }, + "stride":{ + "strength":0, + "upperLegsPitch":30, + "lowerLegsPitch":15, + "upperLegsPitchOffset":0.2, + "lowerLegsPitchOffset":1.5 + } + }, + "joints":[ + { + "name":"hips", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0, + "thrust":0, + "bob":0, + "sway":0, + "thrustPhase":180, + "bobPhase":0, + "swayPhase":-90, + "thrustOffset":0, + "bobOffset":0, + "swayOffset":0 + }, + { + "name":"upperLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"lowerLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"feet", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"toes", + "pitch":2.0377358490566038, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":4.415094339622641, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine", + "pitch":1.660377358490566, + "yaw":0, + "roll":0, + "pitchPhase":-180, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine1", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine2", + "pitch":2.1132075471698113, + "yaw":0, + "roll":0, + "pitchPhase":-0.6792452830188722, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"shoulders", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0.6792452830188678, + "yawOffset":-5.20754716981132, + "rollOffset":-2.9433962264150937 + }, + { + "name":"upperArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":77.77358490566039, + "yawOffset":9.169811320754715, + "rollOffset":0 + }, + { + "name":"lowerArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"hands", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":1.6981132075471694, + "yawOffset":-1.0188679245283017, + "rollOffset":1.0188679245283017 + }, + { + "name":"head", + "pitch":0, + "yaw":1.7358490566037734, + "roll":1.5094339622641508, + "pitchPhase":-90.33962264150944, + "yawPhase":94.41509433962267, + "rollPhase":0, + "pitchOffset":1.6981132075471694, + "yawOffset":0, + "rollOffset":0 + } + ] +}; +var keyFrameTwo = +{ + "name":"FemaleStandingOne", + "settings":{ + "baseFrequency":70, + "flyingHipsPitch":60, + "takeFlightVelocity":40, + "maxBankingAngle":40 + }, + "adjusters":{ + "legsSeparation":{ + "strength":-0.03679245283018867, + "separationAngle":50 + }, + "stride":{ + "strength":0, + "upperLegsPitch":30, + "lowerLegsPitch":15, + "upperLegsPitchOffset":0.2, + "lowerLegsPitchOffset":1.5 + } + }, + "joints":[ + { + "name":"hips", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0, + "thrust":0, + "bob":0, + "sway":0, + "thrustPhase":180, + "bobPhase":0, + "swayPhase":-90, + "thrustOffset":0, + "bobOffset":0, + "swayOffset":0 + }, + { + "name":"upperLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"lowerLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"feet", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"toes", + "pitch":2.0377358490566038, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":4.415094339622641, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine", + "pitch":1.660377358490566, + "yaw":0, + "roll":0, + "pitchPhase":-180, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine1", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine2", + "pitch":2.1132075471698113, + "yaw":0, + "roll":0, + "pitchPhase":-0.6792452830188722, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"shoulders", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0.6792452830188678, + "yawOffset":-5.20754716981132, + "rollOffset":-2.9433962264150937 + }, + { + "name":"upperArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":49.584905660377345, + "yawOffset":9.169811320754715, + "rollOffset":0 + }, + { + "name":"lowerArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"hands", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":-13, + "yawOffset":-1.0188679245283017, + "rollOffset":1.0188679245283017 + }, + { + "name":"head", + "pitch":0, + "yaw":1.7358490566037734, + "roll":1.5094339622641508, + "pitchPhase":-90.33962264150944, + "yawPhase":94.41509433962267, + "rollPhase":0, + "pitchOffset":1.6981132075471694, + "yawOffset":0, + "rollOffset":0 + } + ] +}; +var keyFrameThree = +{ + "name":"FemaleStandingOne", + "settings":{ + "baseFrequency":70, + "flyingHipsPitch":60, + "takeFlightVelocity":40, + "maxBankingAngle":40 + }, + "adjusters":{ + "legsSeparation":{ + "strength":-0.03679245283018867, + "separationAngle":50 + }, + "stride":{ + "strength":0, + "upperLegsPitch":30, + "lowerLegsPitch":15, + "upperLegsPitchOffset":0.2, + "lowerLegsPitchOffset":1.5 + } + }, + "joints":[ + { + "name":"hips", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0, + "thrust":0, + "bob":0, + "sway":0, + "thrustPhase":180, + "bobPhase":0, + "swayPhase":-90, + "thrustOffset":0, + "bobOffset":0, + "swayOffset":0 + }, + { + "name":"upperLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"lowerLegs", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"feet", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"toes", + "pitch":2.0377358490566038, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":4.415094339622641, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine", + "pitch":1.660377358490566, + "yaw":0, + "roll":0, + "pitchPhase":-180, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine1", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"spine2", + "pitch":2.1132075471698113, + "yaw":0, + "roll":0, + "pitchPhase":-0.6792452830188722, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"shoulders", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":-21.0566037735849, + "yawOffset":-5.20754716981132, + "rollOffset":-2.9433962264150937 + }, + { + "name":"upperArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":-33.28301886792452, + "yawOffset":9.169811320754715, + "rollOffset":0 + }, + { + "name":"lowerArms", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":0, + "yawOffset":0, + "rollOffset":0 + }, + { + "name":"hands", + "pitch":0, + "yaw":0, + "roll":0, + "pitchPhase":0, + "yawPhase":0, + "rollPhase":0, + "pitchOffset":-13, + "yawOffset":-1.0188679245283017, + "rollOffset":1.0188679245283017 + }, + { + "name":"head", + "pitch":0, + "yaw":1.7358490566037734, + "roll":1.5094339622641508, + "pitchPhase":-90.33962264150944, + "yawPhase":94.41509433962267, + "rollPhase":0, + "pitchOffset":1.6981132075471694, + "yawOffset":0, + "rollOffset":0 + } + ] +}; \ No newline at end of file diff --git a/examples/inspect.js b/examples/inspect.js index b9ed5a3f00..81beea7ee9 100644 --- a/examples/inspect.js +++ b/examples/inspect.js @@ -17,13 +17,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var PI = 3.14 // No need for something more precise +var PI = Math.PI; +var RAD_TO_DEG = 180.0 / PI; var AZIMUTH_RATE = 90.0; var ALTITUDE_RATE = 200.0; var RADIUS_RATE = 1.0 / 100.0; var PAN_RATE = 50.0; +var Y_AXIS = { x: 0, y: 1, z: 0 }; +var X_AXIS = { x: 1, y: 0, z: 0 }; + var alt = false; var shift = false; var control = false; @@ -53,6 +57,18 @@ var avatarPosition; var avatarOrientation; +function orientationOf(vector) { + var direction, + yaw, + pitch; + + direction = Vec3.normalize(vector); + yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); + pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); + return Quat.multiply(yaw, pitch); +} + + function handleRadialMode(dx, dy) { azimuth += dx / AZIMUTH_RATE; radius += radius * dy * RADIUS_RATE; @@ -65,6 +81,7 @@ function handleRadialMode(dx, dy) { z: (Math.cos(altitude) * Math.sin(azimuth)) * radius }; position = Vec3.sum(center, vector); Camera.setPosition(position); + Camera.setOrientation(orientationOf(vector)); } function handleOrbitMode(dx, dy) { @@ -82,6 +99,7 @@ function handleOrbitMode(dx, dy) { z:(Math.cos(altitude) * Math.sin(azimuth)) * radius }; position = Vec3.sum(center, vector); Camera.setPosition(position); + Camera.setOrientation(orientationOf(vector)); } @@ -96,7 +114,7 @@ function handlePanMode(dx, dy) { position = Vec3.sum(position, dv); Camera.setPosition(position); - Camera.keepLookingAt(center); + Camera.setOrientation(orientationOf(vector)); } function saveCameraState() { @@ -107,7 +125,6 @@ function saveCameraState() { } function restoreCameraState() { - Camera.stopLooking(); Camera.setMode(oldMode); } @@ -245,7 +262,6 @@ function mousePressEvent(event) { azimuth = Math.atan2(vector.z, vector.x); altitude = Math.asin(vector.y / Vec3.length(vector)); - Camera.keepLookingAt(center); print(string); isActive = true; } diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index 88d0935e72..d591d33b6d 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -86,7 +86,7 @@ CameraManager = function() { that.updateCamera(); - cameraTool.setVisible(true); + cameraTool.setVisible(false); } that.disable = function(ignoreCamera) { @@ -100,7 +100,7 @@ CameraManager = function() { cameraTool.setVisible(false); } - that.focus = function(entityProperties) { + that.focus = function() { var dim = SelectionManager.worldDimensions; var size = Math.max(dim.x, Math.max(dim.y, dim.z)); diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index a325491dd3..29bf1bdd79 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -209,12 +209,6 @@ SelectionDisplay = (function () { var lastCameraOrientation = Camera.getOrientation(); var lastPlaneIntersection; - var currentSelection = { id: -1, isKnownID: false }; - var entitySelected = false; - var selectedEntityProperties; - var selectedEntityPropertiesOriginalPosition; - var selectedEntityPropertiesOriginalDimensions; - var handleHoverColor = { red: 224, green: 67, blue: 36 }; var handleHoverAlpha = 1.0; @@ -656,20 +650,12 @@ SelectionDisplay = (function () { }; that.select = function(entityID, event) { - var properties = Entities.getEntityProperties(entityID); - // if (currentSelection.isKnownID == true) { - // that.unselect(currentSelection); - // } - currentSelection = entityID; - entitySelected = true; + var properties = Entities.getEntityProperties(SelectionManager.selections[0]); - // lastCameraPosition = Camera.getPosition(); + lastCameraPosition = Camera.getPosition(); lastCameraOrientation = Camera.getOrientation(); if (event !== false) { - selectedEntityProperties = properties; - selectedEntityPropertiesOriginalPosition = properties.position; - selectedEntityPropertiesOriginalDimensions = properties.dimensions; pickRay = Camera.computePickRay(event.x, event.y); lastPlaneIntersection = rayPlaneIntersection(pickRay, properties.position, Quat.getFront(lastCameraOrientation)); @@ -678,8 +664,6 @@ SelectionDisplay = (function () { print("select() with EVENT...... "); print(" event.y:" + event.y); Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); - Vec3.print(" originalPosition:", selectedEntityPropertiesOriginalPosition); - Vec3.print(" originalDimensions:", selectedEntityPropertiesOriginalDimensions); Vec3.print(" current position:", properties.position); } @@ -939,11 +923,6 @@ SelectionDisplay = (function () { }; that.unselectAll = function () { - if (currentSelection.isKnownID == true) { - that.unselect(currentSelection); - } - currentSelection = { id: -1, isKnownID: false }; - entitySelected = false; }; that.updateHandles = function() { @@ -952,7 +931,9 @@ SelectionDisplay = (function () { return; } + that.updateRotationHandles(); + that.highlightSelectable(); var rotation, dimensions, position; @@ -1113,12 +1094,6 @@ SelectionDisplay = (function () { }; that.unselect = function (entityID) { - that.setOverlaysVisible(false); - - Entities.editEntity(entityID, { localRenderAlpha: 1.0 }); - - currentSelection = { id: -1, isKnownID: false }; - entitySelected = false; }; var initialXZPick = null; @@ -1207,15 +1182,16 @@ SelectionDisplay = (function () { } } - tooltip.updateText(selectedEntityProperties); - that.select(currentSelection, false); // TODO: this should be more than highlighted SelectionManager._update(); } }; + var lastXYPick = null addGrabberTool(grabberMoveUp, { mode: "TRANSLATE_UP_DOWN", onBegin: function(event) { + lastXYPick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, Quat.getFront(lastCameraOrientation)); + SelectionManager.saveProperties(); // Duplicate entities if alt is pressed. This will make a @@ -1243,7 +1219,7 @@ SelectionDisplay = (function () { // translate mode left/right based on view toward entity var newIntersection = rayPlaneIntersection(pickRay, - selectedEntityPropertiesOriginalPosition, + SelectionManager.worldPosition, Quat.getFront(lastCameraOrientation)); var vector = Vec3.subtract(newIntersection, lastPlaneIntersection); @@ -1253,8 +1229,6 @@ SelectionDisplay = (function () { vector.x = 0; vector.z = 0; - // newPosition = Vec3.sum(selectedEntityPropertiesOriginalPosition, vector); - var wantDebug = false; if (wantDebug) { print("translateUpDown... "); @@ -1262,8 +1236,6 @@ SelectionDisplay = (function () { Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); - Vec3.print(" originalPosition:", selectedEntityPropertiesOriginalPosition); - Vec3.print(" recentPosition:", selectedEntityProperties.position); Vec3.print(" newPosition:", newPosition); } for (var i = 0; i < SelectionManager.selections.length; i++) { @@ -1273,8 +1245,6 @@ SelectionDisplay = (function () { Entities.editEntity(SelectionManager.selections[i], properties); } - tooltip.updateText(selectedEntityProperties); - that.select(currentSelection, false); // TODO: this should be more than highlighted SelectionManager._update(); }, }); @@ -1306,7 +1276,7 @@ SelectionDisplay = (function () { var rotation = null; var onBegin = function(event) { - var properties = Entities.getEntityProperties(currentSelection); + var properties = Entities.getEntityProperties(SelectionManager.selections[0]); initialProperties = properties; rotation = spaceMode == SPACE_LOCAL ? properties.rotation : Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -1445,11 +1415,11 @@ SelectionDisplay = (function () { var changeInPosition = Vec3.multiplyQbyV(rotation, vec3Mult(p, changeInDimensions)); var newPosition = Vec3.sum(initialPosition, changeInPosition); - - selectedEntityProperties.position = newPosition; - selectedEntityProperties.dimensions = newDimensions; for (var i = 0; i < SelectionManager.selections.length; i++) { - Entities.editEntity(SelectionManager.selections[i], selectedEntityProperties); + Entities.editEntity(SelectionManager.selections[i], { + position: newPosition, + dimensions: newDimensions, + }); } var wantDebug = false; @@ -1460,18 +1430,14 @@ SelectionDisplay = (function () { Vec3.print(" vector:", vector); Vec3.print(" oldPOS:", oldPOS); Vec3.print(" newPOS:", newPOS); - Vec3.print(" oldDimensions:", selectedEntityPropertiesOriginalDimensions); Vec3.print(" changeInDimensions:", changeInDimensions); Vec3.print(" newDimensions:", newDimensions); - Vec3.print(" oldPosition:", selectedEntityPropertiesOriginalPosition); Vec3.print(" changeInPosition:", changeInPosition); Vec3.print(" newPosition:", newPosition); } - tooltip.updateText(selectedEntityProperties); SelectionManager._update(); - that.select(currentSelection, false); // TODO: this should be more than highlighted }; @@ -1590,7 +1556,6 @@ SelectionDisplay = (function () { } if (result.intersects) { - var properties = Entities.getEntityProperties(currentSelection); var center = yawCenter; var zero = yawZero; var centerToZero = Vec3.subtract(center, zero); @@ -1664,8 +1629,8 @@ SelectionDisplay = (function () { // Size the overlays to the current selection size var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); - var innerRadius = diagonal; - var outerRadius = diagonal * 1.15; + innerRadius = diagonal; + outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; Overlays.editOverlay(rotateOverlayInner, @@ -1721,7 +1686,7 @@ SelectionDisplay = (function () { } if (result.intersects) { - var properties = Entities.getEntityProperties(currentSelection); + var properties = Entities.getEntityProperties(selectionManager.selections[0]); var center = pitchCenter; var zero = pitchZero; var centerToZero = Vec3.subtract(center, zero); @@ -1794,8 +1759,8 @@ SelectionDisplay = (function () { // Size the overlays to the current selection size var diagonal = (Vec3.length(selectionManager.worldDimensions) / 2) * 1.1; var halfDimensions = Vec3.multiply(selectionManager.worldDimensions, 0.5); - var innerRadius = diagonal; - var outerRadius = diagonal * 1.15; + innerRadius = diagonal; + outerRadius = diagonal * 1.15; var innerAlpha = 0.2; var outerAlpha = 0.2; Overlays.editOverlay(rotateOverlayInner, @@ -1851,7 +1816,7 @@ SelectionDisplay = (function () { } if (result.intersects) { - var properties = Entities.getEntityProperties(currentSelection); + var properties = Entities.getEntityProperties(selectionManager.selections[0]); var center = rollCenter; var zero = rollZero; var centerToZero = Vec3.subtract(center, zero); @@ -1915,9 +1880,9 @@ SelectionDisplay = (function () { }); that.checkMove = function() { - if (currentSelection.isKnownID && + if (SelectionManager.hasSelection() && (!Vec3.equal(Camera.getPosition(), lastCameraPosition) || !Quat.equal(Camera.getOrientation(), lastCameraOrientation))){ - that.select(currentSelection, false, false); + that.select(selectionManager.selections[0], false, false); } }; @@ -2033,7 +1998,7 @@ SelectionDisplay = (function () { var overlayOrientation; var overlayCenter; - var properties = Entities.getEntityProperties(currentSelection); + var properties = Entities.getEntityProperties(selectionManager.selections[0]); var angles = Quat.safeEulerAngles(properties.rotation); var pitch = angles.x; var yaw = angles.y; @@ -2169,12 +2134,11 @@ SelectionDisplay = (function () { if (somethingClicked) { pickRay = Camera.computePickRay(event.x, event.y); - lastPlaneIntersection = rayPlaneIntersection(pickRay, selectedEntityPropertiesOriginalPosition, + lastPlaneIntersection = rayPlaneIntersection(pickRay, selectionManager.worldPosition, Quat.getFront(lastCameraOrientation)); if (wantDebug) { print("mousePressEvent()...... " + overlayNames[result.overlayID]); Vec3.print(" lastPlaneIntersection:", lastPlaneIntersection); - Vec3.print(" originalPosition:", selectedEntityPropertiesOriginalPosition); } } @@ -2289,8 +2253,8 @@ SelectionDisplay = (function () { }; that.updateHandleSizes = function() { - if (selectedEntityProperties) { - var diff = Vec3.subtract(selectedEntityProperties.position, Camera.getPosition()); + if (selectionManager.hasSelection()) { + var diff = Vec3.subtract(selectionManager.worldPosition, Camera.getPosition()); var grabberSize = Vec3.length(diff) * GRABBER_DISTANCE_TO_SIZE_RATIO; for (var i = 0; i < stretchHandles.length; i++) { Overlays.editOverlay(stretchHandles[i], { @@ -2336,15 +2300,10 @@ SelectionDisplay = (function () { mode = "UNKNOWN"; // if something is selected, then reset the "original" properties for any potential next click+move operation - if (entitySelected) { - + if (SelectionManager.hasSelection()) { if (showHandles) { - that.select(currentSelection, event); + that.select(SelectionManager.selections[0], event); } - - selectedEntityProperties = Entities.getEntityProperties(currentSelection); - selectedEntityPropertiesOriginalPosition = properties.position; - selectedEntityPropertiesOriginalDimensions = properties.dimensions; } }; diff --git a/examples/lobby.js b/examples/lobby.js index 4642d13387..b5353131a5 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -174,7 +174,7 @@ function maybeCleanupLobby() { function toggleEnvironmentRendering(shouldRender) { Menu.setIsOptionChecked("Voxels", shouldRender); - Menu.setIsOptionChecked("Models", shouldRender); + Menu.setIsOptionChecked("Entities", shouldRender); Menu.setIsOptionChecked("Metavoxels", shouldRender); Menu.setIsOptionChecked("Avatars", shouldRender); } diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 8d19a350a2..64ccb556a9 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -256,7 +256,7 @@ var toolBar = (function () { if (activeButton === toolBar.clicked(clickedOverlay)) { isActive = !isActive; if (!isActive) { - selectionDisplay.unselectAll(); + selectionManager.clearSelections(); cameraManager.disable(); } else { cameraManager.enable(); @@ -386,9 +386,7 @@ function isLocked(properties) { } -var entitySelected = false; var selectedEntityID; -var selectedEntityProperties; var mouseLastPosition; var orientation; var intersection; @@ -408,13 +406,12 @@ function mousePressEvent(event) { mouseLastPosition = { x: event.x, y: event.y }; var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + var entitySelected = false; if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event) || cameraManager.mousePressEvent(event) || selectionDisplay.mousePressEvent(event)) { // Event handled; do nothing. return; } else { - entitySelected = false; - selectionDisplay.unselectAll(); // If we aren't active and didn't click on an overlay: quit if (!isActive) { @@ -426,6 +423,7 @@ function mousePressEvent(event) { var foundIntersection = Entities.findRayIntersection(pickRay); if(!foundIntersection.accurate) { + selectionManager.clearSelections(); return; } var foundEntity = foundIntersection.entityID; @@ -434,6 +432,7 @@ function mousePressEvent(event) { var identify = Entities.identifyEntity(foundEntity); if (!identify.isKnownID) { print("Unknown ID " + identify.id + " (update loop " + foundEntity.id + ")"); + selectionManager.clearSelections(); return; } foundEntity = identify; @@ -474,7 +473,6 @@ function mousePressEvent(event) { if (0 < x && sizeOK) { entitySelected = true; selectedEntityID = foundEntity; - selectedEntityProperties = properties; orientation = MyAvatar.orientation; intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); @@ -483,29 +481,11 @@ function mousePressEvent(event) { } selectionManager.addEntity(foundEntity); - print("Model selected selectedEntityID:" + selectedEntityID.id); - + print("Model selected: " + foundEntity.id); } } } if (entitySelected) { - selectedEntityProperties.oldDimensions = selectedEntityProperties.dimensions; - selectedEntityProperties.oldPosition = { - x: selectedEntityProperties.position.x, - y: selectedEntityProperties.position.y, - z: selectedEntityProperties.position.z, - }; - selectedEntityProperties.oldRotation = { - x: selectedEntityProperties.rotation.x, - y: selectedEntityProperties.rotation.y, - z: selectedEntityProperties.rotation.z, - w: selectedEntityProperties.rotation.w, - }; - selectedEntityProperties.glowLevel = 0.0; - - print("Clicked on " + selectedEntityID.id + " " + entitySelected); - tooltip.updateText(selectedEntityProperties); - tooltip.show(true); selectionDisplay.select(selectedEntityID, event); } } @@ -554,7 +534,7 @@ function mouseReleaseEvent(event) { if (!isActive) { return; } - if (entitySelected) { + if (selectionManager.hasSelection()) { tooltip.show(false); } cameraManager.mouseReleaseEvent(event); @@ -584,6 +564,7 @@ function setupModelMenus() { print("delete exists... don't add ours"); } + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Model List...", afterItem: "Models" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste Models", shortcutKey: "CTRL+META+V", afterItem: "Edit Properties..." }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Select Large Models", shortcutKey: "CTRL+META+L", afterItem: "Paste Models", isCheckable: true }); @@ -606,6 +587,7 @@ function cleanupModelMenus() { Menu.removeMenuItem("Edit", "Delete"); } + Menu.removeMenuItem("Edit", "Model List..."); Menu.removeMenuItem("Edit", "Paste Models"); Menu.removeMenuItem("Edit", "Allow Select Large Models"); Menu.removeMenuItem("Edit", "Allow Select Small Models"); @@ -642,7 +624,7 @@ function handeMenuEvent(menuItem) { allowLargeModels = Menu.isOptionChecked("Allow Select Large Models"); } else if (menuItem == "Delete") { if (SelectionManager.hasSelection()) { - print(" Delete Entity.... selectedEntityID="+ selectedEntityID); + print(" Delete Entities"); SelectionManager.saveProperties(); var savedProperties = []; for (var i = 0; i < selectionManager.selections.length; i++) { @@ -657,11 +639,41 @@ function handeMenuEvent(menuItem) { } SelectionManager.clearSelections(); pushCommandForSelections([], savedProperties); - selectionDisplay.unselect(selectedEntityID); - entitySelected = false; } else { print(" Delete Entity.... not holding..."); } + } else if (menuItem == "Model List...") { + var models = new Array(); + models = Entities.findEntities(MyAvatar.position, Number.MAX_VALUE); + for (var i = 0; i < models.length; i++) { + models[i].properties = Entities.getEntityProperties(models[i]); + models[i].toString = function() { + var modelname; + if (this.properties.type == "Model") { + modelname = decodeURIComponent( + this.properties.modelURL.indexOf("/") != -1 ? + this.properties.modelURL.substring(this.properties.modelURL.lastIndexOf("/") + 1) : + this.properties.modelURL); + } else { + modelname = this.properties.id; + } + return "[" + this.properties.type + "] " + modelname; + }; + } + var form = [{label: "Model: ", options: models}]; + form.push({label: "Action: ", options: ["Properties", "Delete", "Teleport"]}); + form.push({ button: "Cancel" }); + if (Window.form("Model List", form)) { + var selectedModel = form[0].value; + if (form[1].value == "Properties") { + editModelID = selectedModel; + showPropertiesForm(editModelID); + } else if (form[1].value == "Delete") { + Entities.deleteEntity(selectedModel); + } else if (form[1].value == "Teleport") { + MyAvatar.position = selectedModel.properties.position; + } + } } else if (menuItem == "Edit Properties...") { // good place to put the properties dialog @@ -706,11 +718,7 @@ Controller.keyReleaseEvent.connect(function (event) { } else if (event.text == "TAB") { selectionDisplay.toggleSpaceMode(); } else if (event.text == "f") { - if (entitySelected) { - // Get latest properties - var properties = Entities.getEntityProperties(selectedEntityID); - cameraManager.focus(properties); - } + cameraManager.focus(); } else if (event.text == '[') { if (isActive) { cameraManager.enable(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a215905362..0ad5e5b6ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2349,7 +2349,7 @@ void Application::update(float deltaTime) { if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); } - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { queryOctree(NodeType::EntityServer, PacketTypeEntityQuery, _entityServerJurisdictions); } _lastQueriedViewFrustum = _viewFrustum; @@ -2996,7 +2996,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // render models... - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { PerformanceTimer perfTimer("entities"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... entities..."); diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index 4808842036..505cb6a029 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -41,7 +41,7 @@ void FileLogger::addMessage(QString message) { QFile file(_fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { QTextStream out(&file); - out << message; + out << message << "\n"; } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 002daf29d5..f915855758 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -366,7 +366,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Models, 0, true); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Entities, 0, true); QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); QActionGroup* shadowGroup = new QActionGroup(shadowMenu); @@ -433,14 +433,16 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false); - QMenu* modelDebugMenu = developerMenu->addMenu("Models"); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelBounds, 0, false); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementProxy, 0, false); - addCheckableActionToQMenuAndActionHash(modelDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); - QMenu* modelCullingMenu = modelDebugMenu->addMenu("Culling"); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); - addCheckableActionToQMenuAndActionHash(modelCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); + QMenu* entitiesDebugMenu = developerMenu->addMenu("Entities"); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelBounds, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementProxy, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisplayModelElementChildProxies, 0, false); + addCheckableActionToQMenuAndActionHash(entitiesDebugMenu, MenuOption::DisableLightEntities, 0, false); + + QMenu* entityCullingMenu = entitiesDebugMenu->addMenu("Culling"); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullOutOfViewMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontCullTooSmallMeshParts, 0, false); + addCheckableActionToQMenuAndActionHash(entityCullingMenu, MenuOption::DontReduceMaterialSwitches, 0, false); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxels"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 009d1e3097..72b43e09c8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -384,6 +384,7 @@ namespace MenuOption { const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableActivityLogger = "Disable Activity Logger"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; + const QString DisableLightEntities = "Disable Light Entities"; const QString DisableNackPackets = "Disable NACK Packets"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Show Hand Info"; @@ -400,6 +401,7 @@ namespace MenuOption { const QString Enable3DTVMode = "Enable 3DTV Mode"; const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; const QString EnableVRMode = "Enable VR Mode"; + const QString Entities = "Entities"; const QString ExpandMyAvatarSimulateTiming = "Expand /myAvatar/simulation"; const QString ExpandMyAvatarTiming = "Expand /myAvatar"; const QString ExpandOtherAvatarTiming = "Expand /otherAvatar"; @@ -430,8 +432,6 @@ namespace MenuOption { const QString MetavoxelEditor = "Metavoxel Editor..."; const QString Metavoxels = "Metavoxels"; const QString Mirror = "Mirror"; - const QString ModelOptions = "Model Options"; - const QString Models = "Models"; const QString MoveWithLean = "Move with Lean"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; diff --git a/interface/src/entities/RenderableLightEntityItem.cpp b/interface/src/entities/RenderableLightEntityItem.cpp index bf9939e164..e3e8f61e58 100644 --- a/interface/src/entities/RenderableLightEntityItem.cpp +++ b/interface/src/entities/RenderableLightEntityItem.cpp @@ -61,15 +61,18 @@ void RenderableLightEntityItem::render(RenderArgs* args) { float exponent = getExponent(); float cutoff = glm::radians(getCutoff()); - if (_isSpotlight) { - Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, - direction, exponent, cutoff); - } else { - Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, - ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); - } + bool disableLights = Menu::getInstance()->isOptionChecked(MenuOption::DisableLightEntities); + if (!disableLights) { + if (_isSpotlight) { + Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation, + direction, exponent, cutoff); + } else { + Application::getInstance()->getDeferredLightingEffect()->addPointLight(position, largestDiameter / 2.0f, + ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation); + } + } bool wantDebug = false; if (wantDebug) { glColor4f(diffuseR, diffuseG, diffuseB, 1.0f); diff --git a/interface/src/entities/RenderableModelEntityItem.cpp b/interface/src/entities/RenderableModelEntityItem.cpp index 5a3ee61bbe..ce8d497da3 100644 --- a/interface/src/entities/RenderableModelEntityItem.cpp +++ b/interface/src/entities/RenderableModelEntityItem.cpp @@ -38,12 +38,9 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { bool RenderableModelEntityItem::setProperties(const EntityItemProperties& properties, bool forceCopy) { QString oldModelURL = getModelURL(); - QString oldTextures = getTextures(); bool somethingChanged = ModelEntityItem::setProperties(properties, forceCopy); - if (somethingChanged) { - if ((oldModelURL != getModelURL()) || (oldTextures != getTextures())) { - _needsModelReload = true; - } + if (somethingChanged && oldModelURL != getModelURL()) { + _needsModelReload = true; } return somethingChanged; } @@ -60,6 +57,47 @@ int RenderableModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned c return bytesRead; } +void RenderableModelEntityItem::remapTextures() { + if (!_model) { + return; // nothing to do if we don't have a model + } + + if (_currentTextures == _textures) { + return; // nothing to do if our recently mapped textures match our desired textures + } + qDebug() << "void RenderableModelEntityItem::remapTextures()...."; + + // since we're changing here, we need to run through our current texture map + // and any textures in the recently mapped texture, that is not in our desired + // textures, we need to "unset" + QJsonDocument currentTexturesAsJson = QJsonDocument::fromJson(_currentTextures.toUtf8()); + QJsonObject currentTexturesAsJsonObject = currentTexturesAsJson.object(); + QVariantMap currentTextureMap = currentTexturesAsJsonObject.toVariantMap(); + + QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8()); + QJsonObject texturesAsJsonObject = texturesAsJson.object(); + QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); + + foreach(const QString& key, currentTextureMap.keys()) { + // if the desired texture map (what we're setting the textures to) doesn't + // contain this texture, then remove it by setting the URL to null + if (!textureMap.contains(key)) { + QUrl noURL; + qDebug() << "Removing texture named" << key << "by replacing it with no URL"; + _model->setTextureWithNameToURL(key, noURL); + } + } + + // here's where we remap any textures if needed... + foreach(const QString& key, textureMap.keys()) { + QUrl newTextureURL = textureMap[key].toUrl(); + qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; + _model->setTextureWithNameToURL(key, newTextureURL); + } + + _currentTextures = _textures; +} + void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); @@ -72,6 +110,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; if (drawAsModel) { + remapTextures(); glPushMatrix(); { float alpha = getLocalRenderAlpha(); @@ -159,6 +198,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { } assert(_myRenderer == renderer); // you should only ever render on one renderer + if (QThread::currentThread() != _myRenderer->thread()) { + return _model; + } + _needsModelReload = false; // this is the reload // if we have a URL, then we will want to end up returning a model... @@ -183,18 +226,6 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { } } - // here's where we remap any textures if needed... - if (!_textures.isEmpty() && _model) { - QJsonDocument texturesAsJson = QJsonDocument::fromJson(_textures.toUtf8()); - QJsonObject texturesAsJsonObject = texturesAsJson.object(); - QVariantMap textureMap = texturesAsJsonObject.toVariantMap(); - foreach(const QString& key, textureMap.keys()) { - QUrl newTextureURL = textureMap[key].toUrl(); - qDebug() << "Updating texture named" << key << "to texture at URL" << newTextureURL; - _model->setTextureWithNameToURL(key, newTextureURL); - } - } - return result; } diff --git a/interface/src/entities/RenderableModelEntityItem.h b/interface/src/entities/RenderableModelEntityItem.h index f36b66dba4..dbc77b7e48 100644 --- a/interface/src/entities/RenderableModelEntityItem.h +++ b/interface/src/entities/RenderableModelEntityItem.h @@ -51,12 +51,14 @@ public: virtual void render(RenderArgs* args); Model* getModel(EntityTreeRenderer* renderer); private: + void remapTextures(); bool needsSimulation() const; Model* _model; bool _needsInitialSimulation; bool _needsModelReload; EntityTreeRenderer* _myRenderer; + QString _currentTextures; }; #endif // hifi_RenderableModelEntityItem_h diff --git a/interface/src/voxels/OctreePacketProcessor.cpp b/interface/src/voxels/OctreePacketProcessor.cpp index b3cf012869..9f53492e70 100644 --- a/interface/src/voxels/OctreePacketProcessor.cpp +++ b/interface/src/voxels/OctreePacketProcessor.cpp @@ -86,13 +86,13 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, switch(voxelPacketType) { case PacketTypeEntityErase: { - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { app->_entities.processEraseMessage(mutablePacket, sendingNode); } } break; case PacketTypeEntityData: { - if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::Entities)) { app->_entities.processDatagram(mutablePacket, sendingNode); } } break;