diff --git a/examples/cameraExample.js b/examples/cameraExample.js index d42c3c1b0e..d55f376b76 100644 --- a/examples/cameraExample.js +++ b/examples/cameraExample.js @@ -69,6 +69,12 @@ function checkCamera() { var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER); yaw -= viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime; pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime; + if (yaw > 360) { + yaw -= 360; + } + if (yaw < -360) { + yaw += 360; + } var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll); Camera.setOrientation(orientation); } diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 96bb09e6d6..c1f0c8dc49 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -7,9 +7,11 @@ // // Captures mouse clicks and edits voxels accordingly. // -// click = create a new voxel on this face, same color as old -// Alt + click = delete this voxel +// click = create a new voxel on this face, same color as old (default color picker state) +// right click or control + click = delete this voxel // shift + click = recolor this voxel +// 1 - 8 = pick new color from palette +// 9 = create a new voxel in front of the camera // // Click and drag to create more new voxels in the same direction // @@ -18,15 +20,41 @@ function vLength(v) { return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } +function vMinus(a, b) { + var rval = { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }; + return rval; +} + +var NEW_VOXEL_SIZE = 1.0; +var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0; +var ORBIT_RATE_ALTITUDE = 200.0; +var ORBIT_RATE_AZIMUTH = 90.0; +var PIXELS_PER_EXTRUDE_VOXEL = 16; + +var oldMode = Camera.getMode(); + var key_alt = false; var key_shift = false; var isAdding = false; - +var isExtruding = false; +var isOrbiting = false; +var orbitAzimuth = 0.0; +var orbitAltitude = 0.0; +var orbitCenter = { x: 0, y: 0, z: 0 }; +var orbitPosition = { x: 0, y: 0, z: 0 }; +var orbitRadius = 0.0; +var extrudeDirection = { x: 0, y: 0, z: 0 }; +var extrudeScale = 0.0; var lastVoxelPosition = { x: 0, y: 0, z: 0 }; var lastVoxelColor = { red: 0, green: 0, blue: 0 }; var lastVoxelScale = 0; var dragStart = { x: 0, y: 0 }; +var mouseX = 0; +var mouseY = 0; + + + // Create a table of the different colors you can choose var colors = new Array(); colors[0] = { red: 237, green: 175, blue: 0 }; @@ -37,31 +65,70 @@ colors[4] = { red: 193, green: 99, blue: 122 }; colors[5] = { red: 255, green: 54, blue: 69 }; colors[6] = { red: 124, green: 36, blue: 36 }; colors[7] = { red: 63, green: 35, blue: 19 }; -var numColors = 6; -var whichColor = 0; +var numColors = 8; +var whichColor = -1; // Starting color is 'Copy' mode // Create sounds for adding, deleting, recoloring voxels -var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst1.raw"); -var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Bubbles/bubbles1.raw"); -var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Electronic/ElectronicBurst6.raw"); +var addSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+create.raw"); +var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete.raw"); +var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit.raw"); +var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); var audioOptions = new AudioInjectionOptions();
 +audioOptions.volume = 0.5; + +function setAudioPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + audioOptions.position = Vec3.sum(camera, forwardVector); +} + +function getNewVoxelPosition() { + var camera = Camera.getPosition(); + var forwardVector = Quat.getFront(MyAvatar.orientation); + var newPosition = Vec3.sum(camera, Vec3.multiply(forwardVector, NEW_VOXEL_DISTANCE_FROM_CAMERA)); + return newPosition; +} + +function fixEulerAngles(eulers) { + var rVal = { x: 0, y: 0, z: eulers.z }; + if (eulers.x >= 90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } else if (eulers.x <= -90.0) { + rVal.x = 180.0 - eulers.x; + rVal.y = eulers.y - 180.0; + } + return rVal; +} function mousePressEvent(event) { + mouseX = event.x; + mouseY = event.y; var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Voxels.findRayIntersection(pickRay); - audioOptions.volume = 1.0; - audioOptions.position = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z }; - + audioOptions.position = Vec3.sum(pickRay.origin, pickRay.direction); if (intersection.intersects) { - if (key_alt) { + if (event.isAlt) { + // start orbit camera! + var cameraPosition = Camera.getPosition(); + oldMode = Camera.getMode(); + Camera.setMode("independent"); + isOrbiting = true; + Camera.keepLookingAt(intersection.intersection); + // get position for initial azimuth, elevation + orbitCenter = intersection.intersection; + var orbitVector = Vec3.subtract(cameraPosition, orbitCenter); + orbitRadius = vLength(orbitVector); + orbitAzimuth = Math.atan2(orbitVector.z, orbitVector.x); + orbitAltitude = Math.asin(orbitVector.y / Vec3.length(orbitVector)); + + } else if (event.isRightButton || event.isControl) { // Delete voxel Voxels.eraseVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, intersection.voxel.s); Audio.playSound(deleteSound, audioOptions); - } else if (key_shift) { + } else if (event.isShifted) { // Recolor Voxel - whichColor++; - if (whichColor == numColors) whichColor = 0; Voxels.setVoxel(intersection.voxel.x, intersection.voxel.y, intersection.voxel.z, @@ -70,7 +137,9 @@ function mousePressEvent(event) { Audio.playSound(changeColorSound, audioOptions); } else { // Add voxel on face - var newVoxel = { + if (whichColor == -1) { + // Copy mode - use clicked voxel color + var newVoxel = { x: intersection.voxel.x, y: intersection.voxel.y, z: intersection.voxel.z, @@ -78,6 +147,16 @@ function mousePressEvent(event) { red: intersection.voxel.red, green: intersection.voxel.green, blue: intersection.voxel.blue }; + } else { + var newVoxel = { + x: intersection.voxel.x, + y: intersection.voxel.y, + z: intersection.voxel.z, + s: intersection.voxel.s, + red: colors[whichColor].red, + green: colors[whichColor].green, + blue: colors[whichColor].blue }; + } if (intersection.face == "MIN_X_FACE") { newVoxel.x -= newVoxel.s; @@ -108,55 +187,113 @@ function mousePressEvent(event) { function keyPressEvent(event) { key_alt = event.isAlt; key_shift = event.isShifted; + var nVal = parseInt(event.text); + if (event.text == "0") { + print("Color = Copy"); + whichColor = -1; + Audio.playSound(clickSound, audioOptions); + } else if ((nVal > 0) && (nVal <= numColors)) { + whichColor = nVal - 1; + print("Color = " + (whichColor + 1)); + Audio.playSound(clickSound, audioOptions); + } else if (event.text == "9") { + // Create a brand new 1 meter voxel in front of your avatar + var color = whichColor; + if (color == -1) color = 0; + var newPosition = getNewVoxelPosition(); + var newVoxel = { + x: newPosition.x, + y: newPosition.y , + z: newPosition.z, + s: NEW_VOXEL_SIZE, + red: colors[color].red, + green: colors[color].green, + blue: colors[color].blue }; + Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); + setAudioPosition(); + Audio.playSound(addSound, audioOptions); + } else if (event.text == " ") { + // Reset my orientation! + var orientation = { x:0, y:0, z:0, w:1 }; + Camera.setOrientation(orientation); + MyAvatar.orientation = orientation; + } } + function keyReleaseEvent(event) { key_alt = false; key_shift = false; } function mouseMoveEvent(event) { + if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var origEulers = Quat.safeEulerAngles(cameraOrientation); + var newEulers = fixEulerAngles(Quat.safeEulerAngles(cameraOrientation)); + var dx = event.x - mouseX; + var dy = event.y - mouseY; + orbitAzimuth += dx / ORBIT_RATE_AZIMUTH; + orbitAltitude += dy / ORBIT_RATE_ALTITUDE; + var orbitVector = { x:(Math.cos(orbitAltitude) * Math.cos(orbitAzimuth)) * orbitRadius, + y:Math.sin(orbitAltitude) * orbitRadius, + z:(Math.cos(orbitAltitude) * Math.sin(orbitAzimuth)) * orbitRadius }; + orbitPosition = Vec3.sum(orbitCenter, orbitVector); + Camera.setPosition(orbitPosition); + mouseX = event.x; + mouseY = event.y; + } if (isAdding) { - var pickRay = Camera.computePickRay(event.x, event.y); - var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, + // Watch the drag direction to tell which way to 'extrude' this voxel + if (!isExtruding) { + var pickRay = Camera.computePickRay(event.x, event.y); + var lastVoxelDistance = { x: pickRay.origin.x - lastVoxelPosition.x, y: pickRay.origin.y - lastVoxelPosition.y, z: pickRay.origin.z - lastVoxelPosition.z }; - var distance = vLength(lastVoxelDistance); - var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; - mouseSpot.x += pickRay.origin.x; - mouseSpot.y += pickRay.origin.y; - mouseSpot.z += pickRay.origin.z; - var dx = mouseSpot.x - lastVoxelPosition.x; - var dy = mouseSpot.y - lastVoxelPosition.y; - var dz = mouseSpot.z - lastVoxelPosition.z; - if (dx > lastVoxelScale) { - lastVoxelPosition.x += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dx < -lastVoxelScale) { - lastVoxelPosition.x -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy > lastVoxelScale) { - lastVoxelPosition.y += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dy < -lastVoxelScale) { - lastVoxelPosition.y -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz > lastVoxelScale) { - lastVoxelPosition.z += lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); - } else if (dz < -lastVoxelScale) { - lastVoxelPosition.z -= lastVoxelScale; - Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, - lastVoxelScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + var distance = vLength(lastVoxelDistance); + var mouseSpot = { x: pickRay.direction.x * distance, y: pickRay.direction.y * distance, z: pickRay.direction.z * distance }; + mouseSpot.x += pickRay.origin.x; + mouseSpot.y += pickRay.origin.y; + mouseSpot.z += pickRay.origin.z; + var dx = mouseSpot.x - lastVoxelPosition.x; + var dy = mouseSpot.y - lastVoxelPosition.y; + var dz = mouseSpot.z - lastVoxelPosition.z; + extrudeScale = lastVoxelScale; + extrudeDirection = { x: 0, y: 0, z: 0 }; + isExtruding = true; + if (dx > lastVoxelScale) extrudeDirection.x = extrudeScale; + else if (dx < -lastVoxelScale) extrudeDirection.x = -extrudeScale; + else if (dy > lastVoxelScale) extrudeDirection.y = extrudeScale; + else if (dy < -lastVoxelScale) extrudeDirection.y = -extrudeScale; + else if (dz > lastVoxelScale) extrudeDirection.z = extrudeScale; + else if (dz < -lastVoxelScale) extrudeDirection.z = -extrudeScale; + else isExtruding = false; + } else { + // We have got an extrusion direction, now look for mouse move beyond threshold to add new voxel + var dx = event.x - mouseX; + var dy = event.y - mouseY; + if (Math.sqrt(dx*dx + dy*dy) > PIXELS_PER_EXTRUDE_VOXEL) { + lastVoxelPosition = Vec3.sum(lastVoxelPosition, extrudeDirection); + Voxels.setVoxel(lastVoxelPosition.x, lastVoxelPosition.y, lastVoxelPosition.z, + extrudeScale, lastVoxelColor.red, lastVoxelColor.green, lastVoxelColor.blue); + mouseX = event.x; + mouseY = event.y; + } } } } function mouseReleaseEvent(event) { + if (isOrbiting) { + var cameraOrientation = Camera.getOrientation(); + var eulers = Quat.safeEulerAngles(cameraOrientation); + MyAvatar.position = Camera.getPosition(); + MyAvatar.orientation = cameraOrientation; + Camera.stopLooking(); + Camera.setMode(oldMode); + Camera.setOrientation(cameraOrientation); + } isAdding = false; + isOrbiting = false; + isExtruding = false; } Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/hydraMove.js b/examples/hydraMove.js new file mode 100644 index 0000000000..6ce0ad884e --- /dev/null +++ b/examples/hydraMove.js @@ -0,0 +1,210 @@ +// +// hydraMove.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/10/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Controller and MyAvatar classes to implement +// avatar flying through the hydra/controller joysticks +// +// + +var damping = 0.9; +var position = { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z }; +var joysticksCaptured = false; +var THRUST_CONTROLLER = 0; +var VIEW_CONTROLLER = 1; +var INITIAL_THRUST_MULTPLIER = 1.0; +var THRUST_INCREASE_RATE = 1.05; +var MAX_THRUST_MULTIPLIER = 75.0; +var thrustMultiplier = INITIAL_THRUST_MULTPLIER; +var grabDelta = { x: 0, y: 0, z: 0}; +var grabDeltaVelocity = { x: 0, y: 0, z: 0}; +var grabStartRotation = { x: 0, y: 0, z: 0, w: 1}; +var grabCurrentRotation = { x: 0, y: 0, z: 0, w: 1}; +var grabbingWithRightHand = false; +var wasGrabbingWithRightHand = false; +var grabbingWithLeftHand = false; +var wasGrabbingWithLeftHand = false; +var EPSILON = 0.000001; +var velocity = { x: 0, y: 0, z: 0}; +var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call +var THRUST_MAG_UP = 800.0; +var THRUST_MAG_DOWN = 300.0; +var THRUST_MAG_FWD = 500.0; +var THRUST_MAG_BACK = 300.0; +var THRUST_MAG_LATERAL = 250.0; +var THRUST_JUMP = 120.0; + +var YAW_MAG = 500.0; +var PITCH_MAG = 100.0; +var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; +var JOYSTICK_YAW_MAG = YAW_MAG; +var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5; + + +var LEFT_PALM = 0; +var LEFT_BUTTON_4 = 4; +var RIGHT_PALM = 2; +var RIGHT_BUTTON_4 = 10; + +// Used by handleGrabBehavior() for managing the grab position changes +function getAndResetGrabDelta() { + var HAND_GRAB_SCALE_DISTANCE = 2.0; + var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE)); + grabDelta = { x: 0, y: 0, z: 0}; + var avatarRotation = MyAvatar.orientation; + var result = Vec3.multiplyQbyV(avatarRotation, Vec3.multiply(delta, -1)); + return result; +} + +// Used by handleGrabBehavior() for managing the grab velocity feature +function getAndResetGrabDeltaVelocity() { + var HAND_GRAB_SCALE_VELOCITY = 50.0; + var delta = Vec3.multiply(grabDeltaVelocity, (MyAvatar.scale * HAND_GRAB_SCALE_VELOCITY)); + grabDeltaVelocity = { x: 0, y: 0, z: 0}; + var avatarRotation = MyAvatar.orientation; + var result = Quat.multiply(avatarRotation, Vec3.multiply(delta, -1)); + return result; +} + +// Used by handleGrabBehavior() for managing the grab rotation feature +function getAndResetGrabRotation() { + var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation)); + grabStartRotation = grabCurrentRotation; + return quatDiff; +} + +// handles all the grab related behavior: position (crawl), velocity (flick), and rotate (twist) +function handleGrabBehavior() { + // check for and handle grab behaviors + grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4); + grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4); + stoppedGrabbingWithLeftHand = false; + stoppedGrabbingWithRightHand = false; + + if (grabbingWithRightHand && !wasGrabbingWithRightHand) { + // Just starting grab, capture starting rotation + grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + if (grabbingWithRightHand) { + grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime)); + grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM); + } + if (!grabbingWithRightHand && wasGrabbingWithRightHand) { + // Just ending grab, capture velocity + grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM); + stoppedGrabbingWithRightHand = true; + } + + if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) { + // Just starting grab, capture starting rotation + grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM); + } + + if (grabbingWithLeftHand) { + grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(LEFT_PALM), deltaTime)); + grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM); + } + if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) { + // Just ending grab, capture velocity + grabDeltaVelocity = Controller.getSpatialControlVelocity(LEFT_PALM); + stoppedGrabbingWithLeftHand = true; + } + + grabbing = grabbingWithRightHand || grabbingWithLeftHand; + stoppedGrabbing = stoppedGrabbingWithRightHand || stoppedGrabbingWithLeftHand; + + if (grabbing) { + + // move position + var moveFromGrab = getAndResetGrabDelta(); + if (Vec3.length(moveFromGrab) > EPSILON) { + MyAvatar.position = Vec3.sum(MyAvatar.position, moveFromGrab); + velocity = { x: 0, y: 0, z: 0}; + } + + // add some rotation... + var deltaRotation = getAndResetGrabRotation(); + var GRAB_CONTROLLER_TURN_SCALING = 0.5; + var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING); + + // Adjust body yaw by yaw from controller + var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation); + MyAvatar.orientation = orientation; + + // Adjust head pitch from controller + MyAvatar.headPitch = MyAvatar.headPitch - euler.x; + } + + // add some velocity... + if (stoppedGrabbing) { + velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity()); + } + + // handle residual velocity + if(Vec3.length(velocity) > EPSILON) { + MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(velocity, deltaTime)); + // damp velocity + velocity = Vec3.multiply(velocity, damping); + } + + + wasGrabbingWithRightHand = grabbingWithRightHand; + wasGrabbingWithLeftHand = grabbingWithLeftHand; +} + +// Main update function that handles flying and grabbing behaviort +function flyWithHydra() { + var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER); + + if (thrustJoystickPosition.x != 0 || thrustJoystickPosition.y != 0) { + if (thrustMultiplier < MAX_THRUST_MULTIPLIER) { + thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE); + } + var currentOrientation = MyAvatar.orientation; + + var front = Quat.getFront(currentOrientation); + var right = Quat.getRight(currentOrientation); + var up = Quat.getUp(currentOrientation); + + var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS * + thrustJoystickPosition.y * thrustMultiplier * deltaTime); + MyAvatar.addThrust(thrustFront); + var thrustRight = Vec3.multiply(right, MyAvatar.scale * THRUST_MAG_HAND_JETS * + thrustJoystickPosition.x * thrustMultiplier * deltaTime); + MyAvatar.addThrust(thrustRight); + } else { + thrustMultiplier = INITIAL_THRUST_MULTPLIER; + } + + // View Controller + var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER); + if (viewJoystickPosition.x != 0 || viewJoystickPosition.y != 0) { + + // change the body yaw based on our x controller + var orientation = MyAvatar.orientation; + var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0); + MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); + + // change the headPitch based on our x controller + //pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime; + var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime); + MyAvatar.headPitch = newPitch; + } + handleGrabBehavior(); +} + +Script.willSendVisualDataCallback.connect(flyWithHydra); +Controller.captureJoystick(THRUST_CONTROLLER); +Controller.captureJoystick(VIEW_CONTROLLER); + +// Map keyPress and mouse move events to our callbacks +function scriptEnding() { + // re-enabled the standard application for touch events + Controller.releaseJoystick(THRUST_CONTROLLER); + Controller.releaseJoystick(VIEW_CONTROLLER); +} +Script.scriptEnding.connect(scriptEnding); + diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 160d6b7c2c..f51360cca1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2146,15 +2146,6 @@ void Application::updateThreads(float deltaTime) { } } -void Application::updateParticles(float deltaTime) { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::updateParticles()"); - - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.simulate(deltaTime); - } -} - void Application::updateMetavoxels(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); @@ -2276,7 +2267,6 @@ void Application::update(float deltaTime) { updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... - updateParticles(deltaTime); // Simulate particle cloud movements updateMetavoxels(deltaTime); // update metavoxels updateCamera(deltaTime); // handle various camera tweaks like off axis projection updateDialogs(deltaTime); // update various stats dialogs if present @@ -2711,10 +2701,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { // disable specular lighting for ground and voxels glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); - // Draw Cloud Particles - if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { - _cloud.render(); - } // Draw voxels if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), @@ -4042,7 +4028,7 @@ void Application::loadScript(const QString& fileNameString) { scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); // hook our avatar object into this script engine - scriptEngine->setAvatarData( static_cast(_myAvatar), "MyAvatar"); + scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features CameraScriptableObject* cameraScriptable = new CameraScriptableObject(&_myCamera, &_viewFrustum); scriptEngine->registerGlobalObject("Camera", cameraScriptable); diff --git a/interface/src/Application.h b/interface/src/Application.h index ff6e08758b..c5aafc4e9d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -32,7 +32,6 @@ #include "BandwidthMeter.h" #include "Camera.h" -#include "Cloud.h" #include "DatagramProcessor.h" #include "Environment.h" #include "GLCanvas.h" @@ -284,7 +283,6 @@ private: void updateSixense(float deltaTime); void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); - void updateParticles(float deltaTime); void updateMetavoxels(float deltaTime); void updateCamera(float deltaTime); void updateDialogs(float deltaTime); @@ -351,8 +349,6 @@ private: Stars _stars; - Cloud _cloud; - VoxelSystem _voxels; VoxelTree _clipboard; // if I copy/paste VoxelImporter* _voxelImporter; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6eee4453d4..0cf67be2bf 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -37,6 +37,8 @@ static const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_LENGTH_MSECS * NUM_AUDI static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; +static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; + // Mute icon configration static const int ICON_SIZE = 24; static const int ICON_LEFT = 0; @@ -65,7 +67,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p _measuredJitter(0), _jitterBufferSamples(initialJitterBufferSamples), _lastInputLoudness(0), - _averageInputLoudness(0), + _noiseGateMeasuredFloor(0), + _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), _noiseGateFramesToClose(0), @@ -82,6 +85,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* p { // clear the array of locally injected samples memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + // Create the noise sample array + _noiseSampleFrames = new float[NUMBER_OF_NOISE_SAMPLE_FRAMES]; } void Audio::init(QGLWidget *parent) { @@ -351,26 +356,66 @@ void Audio::handleAudioInput() { NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, _inputFormat, _desiredInputFormat); + // + // Impose Noise Gate + // + // The Noise Gate is used to reject constant background noise by measuring the noise + // floor observed at the microphone and then opening the 'gate' to allow microphone + // signals to be transmitted when the microphone samples average level exceeds a multiple + // of the noise floor. + // + // NOISE_GATE_HEIGHT: How loud you have to speak relative to noise background to open the gate. + // Make this value lower for more sensitivity and less rejection of noise. + // NOISE_GATE_WIDTH: The number of samples in an audio frame for which the height must be exceeded + // to open the gate. + // NOISE_GATE_CLOSE_FRAME_DELAY: Once the noise is below the gate height for the frame, how many frames + // will we wait before closing the gate. + // NOISE_GATE_FRAMES_TO_AVERAGE: How many audio frames should we average together to compute noise floor. + // More means better rejection but also can reject continuous things like singing. + // NUMBER_OF_NOISE_SAMPLE_FRAMES: How often should we re-evaluate the noise floor? + + float loudness = 0; float thisSample = 0; int samplesOverNoiseGate = 0; - const float NOISE_GATE_HEIGHT = 3.f; + const float NOISE_GATE_HEIGHT = 7.f; const int NOISE_GATE_WIDTH = 5; - const int NOISE_GATE_CLOSE_FRAME_DELAY = 30; + const int NOISE_GATE_CLOSE_FRAME_DELAY = 5; + const int NOISE_GATE_FRAMES_TO_AVERAGE = 5; for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { thisSample = fabsf(monoAudioSamples[i]); loudness += thisSample; // Noise Reduction: Count peaks above the average loudness - if (thisSample > (_averageInputLoudness * NOISE_GATE_HEIGHT)) { + if (thisSample > (_noiseGateMeasuredFloor * NOISE_GATE_HEIGHT)) { samplesOverNoiseGate++; } } _lastInputLoudness = loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; - const float LOUDNESS_AVERAGING_FRAMES = 1000.f; // This will be about 10 seconds - _averageInputLoudness = (1.f - 1.f / LOUDNESS_AVERAGING_FRAMES) * _averageInputLoudness + (1.f / LOUDNESS_AVERAGING_FRAMES) * _lastInputLoudness; + float averageOfAllSampleFrames = 0.f; + _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; + if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { + float smallestSample = FLT_MAX; + for (int i = 0; i <= NUMBER_OF_NOISE_SAMPLE_FRAMES - NOISE_GATE_FRAMES_TO_AVERAGE; i+= NOISE_GATE_FRAMES_TO_AVERAGE) { + float thisAverage = 0.0f; + for (int j = i; j < i + NOISE_GATE_FRAMES_TO_AVERAGE; j++) { + thisAverage += _noiseSampleFrames[j]; + averageOfAllSampleFrames += _noiseSampleFrames[j]; + } + thisAverage /= NOISE_GATE_FRAMES_TO_AVERAGE; + + if (thisAverage < smallestSample) { + smallestSample = thisAverage; + } + } + averageOfAllSampleFrames /= NUMBER_OF_NOISE_SAMPLE_FRAMES; + _noiseGateMeasuredFloor = smallestSample; + _noiseGateSampleCounter = 0; + //qDebug("smallest sample = %.1f, avg of all = %.1f", _noiseGateMeasuredFloor, averageOfAllSampleFrames); + } + if (_noiseGateEnabled) { if (samplesOverNoiseGate > NOISE_GATE_WIDTH) { _noiseGateOpen = true; @@ -487,7 +532,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isStarved() && _audioOutput->bytesFree() == _audioOutput->bufferSize()) { // we don't have any audio data left in the output buffer // we just starved - qDebug() << "Audio output just starved."; + //qDebug() << "Audio output just starved."; _ringBuffer.setIsStarved(true); _numFramesDisplayStarve = 10; } @@ -505,7 +550,7 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { if (!_ringBuffer.isNotStarvedOrHasMinimumSamples(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2))) { // starved and we don't have enough to start, keep waiting - qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; + //qDebug() << "Buffer is starved and doesn't have enough samples to start. Held back."; } else { // We are either already playing back, or we have enough audio to start playing back. _ringBuffer.setIsStarved(false); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 88e2731006..34a3daad30 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -45,7 +45,7 @@ public: void render(int screenWidth, int screenHeight); - float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _averageInputLoudness, 0.f); } + float getLastInputLoudness() const { return glm::max(_lastInputLoudness - _noiseGateMeasuredFloor, 0.f); } void setNoiseGateEnabled(bool noiseGateEnabled) { _noiseGateEnabled = noiseGateEnabled; } @@ -109,7 +109,9 @@ private: float _measuredJitter; int16_t _jitterBufferSamples; float _lastInputLoudness; - float _averageInputLoudness; + float _noiseGateMeasuredFloor; + float* _noiseSampleFrames; + int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; int _noiseGateFramesToClose; diff --git a/interface/src/Cloud.cpp b/interface/src/Cloud.cpp deleted file mode 100644 index a89ee04810..0000000000 --- a/interface/src/Cloud.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Cloud.cpp -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include "Cloud.h" -#include "Util.h" -#include "Field.h" - -const int NUM_PARTICLES = 100000; -const float FIELD_COUPLE = 0.001f; -const bool RENDER_FIELD = false; - -Cloud::Cloud() { - glm::vec3 box = glm::vec3(PARTICLE_WORLD_SIZE); - _bounds = box; - _count = NUM_PARTICLES; - _particles = new Particle[_count]; - _field = new Field(PARTICLE_WORLD_SIZE, FIELD_COUPLE); - - for (unsigned int i = 0; i < _count; i++) { - _particles[i].position = randVector() * box; - const float INIT_VEL_SCALE = 0.03f; - _particles[i].velocity = randVector() * ((float)PARTICLE_WORLD_SIZE * INIT_VEL_SCALE); - _particles[i].color = randVector(); - } -} - -void Cloud::render() { - if (RENDER_FIELD) { - _field->render(); - } - - glPointSize(3.0f); - glDisable(GL_TEXTURE_2D); - glEnable(GL_POINT_SMOOTH); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glVertexPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].position); - glColorPointer(3, GL_FLOAT, 3 * sizeof(glm::vec3), &_particles[0].color); - glDrawArrays(GL_POINTS, 0, NUM_PARTICLES); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - -} - -void Cloud::simulate (float deltaTime) { - unsigned int i; - _field->simulate(deltaTime); - for (i = 0; i < _count; ++i) { - - // Update position - _particles[i].position += _particles[i].velocity * deltaTime; - - // Decay Velocity (Drag) - const float CONSTANT_DAMPING = 0.15f; - _particles[i].velocity *= (1.f - CONSTANT_DAMPING * deltaTime); - - // Interact with Field - _field->interact(deltaTime, _particles[i].position, _particles[i].velocity); - - // Update color to velocity - _particles[i].color = (glm::normalize(_particles[i].velocity) * 0.5f) + 0.5f; - - // Bounce at bounds - if ((_particles[i].position.x > _bounds.x) || (_particles[i].position.x < 0.f)) { - _particles[i].position.x = glm::clamp(_particles[i].position.x, 0.f, _bounds.x); - _particles[i].velocity.x *= -1.f; - } - if ((_particles[i].position.y > _bounds.y) || (_particles[i].position.y < 0.f)) { - _particles[i].position.y = glm::clamp(_particles[i].position.y, 0.f, _bounds.y); - _particles[i].velocity.y *= -1.f; - } - if ((_particles[i].position.z > _bounds.z) || (_particles[i].position.z < 0.f)) { - _particles[i].position.z = glm::clamp(_particles[i].position.z, 0.f, _bounds.z); - _particles[i].velocity.z *= -1.f; - } - } - } diff --git a/interface/src/Cloud.h b/interface/src/Cloud.h deleted file mode 100644 index fcf414b62e..0000000000 --- a/interface/src/Cloud.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Cloud.h -// interface -// -// Created by Philip Rosedale on 11/17/12. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__Cloud__ -#define __interface__Cloud__ - -#include "Field.h" - -#define PARTICLE_WORLD_SIZE 256.0 - -class Cloud { -public: - Cloud(); - void simulate(float deltaTime); - void render(); - -private: - struct Particle { - glm::vec3 position, velocity, color; - }* _particles; - - unsigned int _count; - glm::vec3 _bounds; - Field* _field; -}; - -#endif diff --git a/interface/src/ControllerScriptingInterface.cpp b/interface/src/ControllerScriptingInterface.cpp index 8716116877..b3d6170bff 100644 --- a/interface/src/ControllerScriptingInterface.cpp +++ b/interface/src/ControllerScriptingInterface.cpp @@ -172,6 +172,21 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlInd return glm::vec3(0); // bad index } +glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int controlIndex) const { + int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; + int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; + const PalmData* palmData = getActivePalm(palmIndex); + if (palmData) { + switch (controlOfPalm) { + case PALM_SPATIALCONTROL: + return palmData->getRawRotation(); + case TIP_SPATIALCONTROL: + return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation + } + } + return glm::quat(); // bad index +} + glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const { int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; diff --git a/interface/src/ControllerScriptingInterface.h b/interface/src/ControllerScriptingInterface.h index e9fbd2d6d3..f0a50559f9 100644 --- a/interface/src/ControllerScriptingInterface.h +++ b/interface/src/ControllerScriptingInterface.h @@ -58,7 +58,7 @@ public slots: virtual glm::vec3 getSpatialControlPosition(int controlIndex) const; virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const; virtual glm::vec3 getSpatialControlNormal(int controlIndex) const; - + virtual glm::quat getSpatialControlRawRotation(int controlIndex) const; virtual void captureKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7eb5807c6f..4a3733f760 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -161,7 +161,7 @@ Menu::Menu() : #endif addDisabledActionAndSeparator(editMenu, "Physics"); - addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, true); + addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); @@ -238,9 +238,9 @@ Menu::Menu() : SLOT(setFullscreen(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, appInstance,SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H,false, - appInstance,SLOT(cameraMenuChanged())); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, + appInstance, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false, @@ -266,14 +266,8 @@ Menu::Menu() : appInstance->getAvatar(), SLOT(resetSize())); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::OffAxisProjection, - 0, - true); - addCheckableActionToQMenuAndActionHash(viewMenu, - MenuOption::TurnWithHead, - 0, - true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); @@ -298,7 +292,6 @@ Menu::Menu() : appInstance->getGlowEffect(), SLOT(cycleRenderMode())); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, false); @@ -339,14 +332,14 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FaceshiftTCP, 0, false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); @@ -356,7 +349,7 @@ Menu::Menu() : true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); - addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayLeapHands, 0, true); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::VoxelDrumming, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 742b9fc66f..19e9fbf49f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -183,7 +183,7 @@ namespace MenuOption { const QString DisableDeltaSending = "Disable Delta Sending"; const QString DisableLowRes = "Disable Lower Resolution While Moving"; const QString DisplayFrustum = "Display Frustum"; - const QString DisplayLeapHands = "Display Leap Hands"; + const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; const QString FilterSixense = "Smooth Sixense Movement"; const QString DontRenderVoxels = "Don't call _voxels.render()"; @@ -223,7 +223,6 @@ namespace MenuOption { const QString KillLocalVoxels = "Kill Local Voxels"; const QString GoHome = "Go Home"; const QString Gravity = "Use Gravity"; - const QString ParticleCloud = "Particle Cloud"; const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 5749da5f14..af66c08bf4 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -32,12 +32,7 @@ Hand::Hand(Avatar* owningAvatar) : _ballColor(0.0, 0.0, 0.4), _collisionCenter(0,0,0), _collisionAge(0), - _collisionDuration(0), - _pitchUpdate(0), - _grabDelta(0, 0, 0), - _grabDeltaVelocity(0, 0, 0), - _grabStartRotation(0, 0, 0, 1), - _grabCurrentRotation(0, 0, 0, 1) + _collisionDuration(0) { } @@ -54,28 +49,6 @@ void Hand::init() { void Hand::reset() { } -glm::vec3 Hand::getAndResetGrabDelta() { - const float HAND_GRAB_SCALE_DISTANCE = 2.f; - glm::vec3 delta = _grabDelta * _owningAvatar->getScale() * HAND_GRAB_SCALE_DISTANCE; - _grabDelta = glm::vec3(0,0,0); - glm::quat avatarRotation = _owningAvatar->getOrientation(); - return avatarRotation * -delta; -} - -glm::vec3 Hand::getAndResetGrabDeltaVelocity() { - const float HAND_GRAB_SCALE_VELOCITY = 5.f; - glm::vec3 delta = _grabDeltaVelocity * _owningAvatar->getScale() * HAND_GRAB_SCALE_VELOCITY; - _grabDeltaVelocity = glm::vec3(0,0,0); - glm::quat avatarRotation = _owningAvatar->getOrientation(); - return avatarRotation * -delta; - -} -glm::quat Hand::getAndResetGrabRotation() { - glm::quat diff = _grabCurrentRotation * glm::inverse(_grabStartRotation); - _grabStartRotation = _grabCurrentRotation; - return diff; -} - void Hand::simulate(float deltaTime, bool isMine) { if (_collisionAge > 0.f) { @@ -98,19 +71,6 @@ void Hand::simulate(float deltaTime, bool isMine) { _buckyBalls.grab(palm, fingerTipPosition, _owningAvatar->getOrientation(), deltaTime); - if (palm.getControllerButtons() & BUTTON_4) { - _grabDelta += palm.getRawVelocity() * deltaTime; - _grabCurrentRotation = palm.getRawRotation(); - } - if ((palm.getLastControllerButtons() & BUTTON_4) && !(palm.getControllerButtons() & BUTTON_4)) { - // Just ending grab, capture velocity - _grabDeltaVelocity = palm.getRawVelocity(); - } - if (!(palm.getLastControllerButtons() & BUTTON_4) && (palm.getControllerButtons() & BUTTON_4)) { - // Just starting grab, capture starting rotation - _grabStartRotation = palm.getRawRotation(); - } - if (palm.getControllerButtons() & BUTTON_1) { if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) { QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value(); @@ -356,7 +316,7 @@ void Hand::render(bool isMine) { } } - if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) { renderLeapHands(isMine); } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 9413d024c3..5a423630b4 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -58,15 +58,6 @@ public: const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} - // Pitch from controller input to view - const float getPitchUpdate() const { return _pitchUpdate; } - void setPitchUpdate(float pitchUpdate) { _pitchUpdate = pitchUpdate; } - - // Get the drag distance to move - glm::vec3 getAndResetGrabDelta(); - glm::vec3 getAndResetGrabDeltaVelocity(); - glm::quat getAndResetGrabRotation(); - void collideAgainstAvatar(Avatar* avatar, bool isMyHand); void collideAgainstOurself(); @@ -102,13 +93,6 @@ private: void calculateGeometry(); void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime); - - float _pitchUpdate; - - glm::vec3 _grabDelta; - glm::vec3 _grabDeltaVelocity; - glm::quat _grabStartRotation; - glm::quat _grabCurrentRotation; }; #endif diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8a4d734072..85c0c2b35a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -310,21 +310,6 @@ void MyAvatar::simulate(float deltaTime) { updateChatCircle(deltaTime); - // Get any position, velocity, or rotation update from Grab Drag controller - glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta(); - if (glm::length(moveFromGrab) > EPSILON) { - _position += moveFromGrab; - _velocity = glm::vec3(0, 0, 0); - } - _velocity += _hand.getAndResetGrabDeltaVelocity(); - glm::quat deltaRotation = _hand.getAndResetGrabRotation(); - const float GRAB_CONTROLLER_TURN_SCALING = 0.5f; - glm::vec3 euler = safeEulerAngles(deltaRotation) * GRAB_CONTROLLER_TURN_SCALING; - // Adjust body yaw by yaw from controller - setOrientation(glm::angleAxis(-euler.y, glm::vec3(0, 1, 0)) * getOrientation()); - // Adjust head pitch from controller - getHead().setPitch(getHead().getPitch() - euler.x); - _position += _velocity * deltaTime; // update avatar skeleton and simulate hand and head @@ -791,38 +776,6 @@ void MyAvatar::updateThrust(float deltaTime) { up; } } - // Add thrust and rotation from hand controllers - const float THRUST_MAG_HAND_JETS = THRUST_MAG_FWD; - const float JOYSTICK_YAW_MAG = YAW_MAG; - const float JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5f; - const int THRUST_CONTROLLER = 0; - const int VIEW_CONTROLLER = 1; - for (size_t i = 0; i < getHand().getPalms().size(); ++i) { - PalmData& palm = getHand().getPalms()[i]; - - // If the script hasn't captured this joystick, then let the default behavior work - if (!Application::getInstance()->getControllerScriptingInterface()->isJoystickCaptured(palm.getSixenseID())) { - if (palm.isActive() && (palm.getSixenseID() == THRUST_CONTROLLER)) { - if (palm.getJoystickY() != 0.f) { - FingerData& finger = palm.getFingers()[0]; - if (finger.isActive()) { - } - _thrust += front * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickY() * _thrustMultiplier * deltaTime; - } - if (palm.getJoystickX() != 0.f) { - _thrust += right * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickX() * _thrustMultiplier * deltaTime; - } - } else if (palm.isActive() && (palm.getSixenseID() == VIEW_CONTROLLER)) { - if (palm.getJoystickX() != 0.f) { - _bodyYawDelta -= palm.getJoystickX() * JOYSTICK_YAW_MAG * deltaTime; - } - if (palm.getJoystickY() != 0.f) { - getHand().setPitchUpdate(getHand().getPitchUpdate() + - (palm.getJoystickY() * JOYSTICK_PITCH_MAG * deltaTime)); - } - } - } - } // Update speed brake status const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0130cc9ca2..d8cb4c05aa 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -45,7 +45,6 @@ public: // setters void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; } - void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } void setLeanScale(float scale) { _leanScale = scale; } void setGravity(glm::vec3 gravity); @@ -78,9 +77,6 @@ public: static void sendKillAvatar(); - // Set/Get update the thrust that will move the avatar around - void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; - glm::vec3 getThrust() { return _thrust; }; void orbit(const glm::vec3& position, int deltaX, int deltaY); @@ -94,9 +90,13 @@ public slots: void increaseSize(); void decreaseSize(); void resetSize(); - void sendIdentityPacket(); + // Set/Get update the thrust that will move the avatar around + void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; + glm::vec3 getThrust() { return _thrust; }; + void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } + private: bool _mousePressed; float _bodyPitchDelta; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 46d92c0f2e..08604a95f1 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -67,6 +67,7 @@ class AvatarData : public NodeData { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) + Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale) Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw) Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) diff --git a/libraries/script-engine/src/AbstractControllerScriptingInterface.h b/libraries/script-engine/src/AbstractControllerScriptingInterface.h index 4fad5f6edc..d9878d0b71 100644 --- a/libraries/script-engine/src/AbstractControllerScriptingInterface.h +++ b/libraries/script-engine/src/AbstractControllerScriptingInterface.h @@ -12,6 +12,7 @@ #include #include +#include #include "EventTypes.h" @@ -37,6 +38,7 @@ public slots: virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0; virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0; virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0; + virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0; virtual void captureKeyEvents(const KeyEvent& event) = 0; virtual void releaseKeyEvents(const KeyEvent& event) = 0; diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index a197d59aeb..2f1c39f9e3 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -9,7 +9,10 @@ // // +#include + #include +#include #include "Quat.h" glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { @@ -24,6 +27,11 @@ glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) { return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll))); } +glm::quat Quat::inverse(const glm::quat& q) { + return glm::inverse(q); +} + + glm::vec3 Quat::getFront(const glm::quat& orientation) { return orientation * IDENTITY_FRONT; } @@ -35,3 +43,12 @@ glm::vec3 Quat::getRight(const glm::quat& orientation) { glm::vec3 Quat::getUp(const glm::quat& orientation) { return orientation * IDENTITY_UP; } + +glm::vec3 Quat::safeEulerAngles(const glm::quat& orientation) { + return ::safeEulerAngles(orientation); +} + +glm::quat Quat::angleAxis(float angle, const glm::vec3& v) { + return glm::angleAxis(angle, v); +} + diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 72fec6d6dc..867069d6d6 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -23,11 +23,12 @@ public slots: glm::quat multiply(const glm::quat& q1, const glm::quat& q2); glm::quat fromVec3(const glm::vec3& vec3); glm::quat fromPitchYawRoll(float pitch, float yaw, float roll); + glm::quat inverse(const glm::quat& q); glm::vec3 getFront(const glm::quat& orientation); glm::vec3 getRight(const glm::quat& orientation); glm::vec3 getUp(const glm::quat& orientation); + glm::vec3 safeEulerAngles(const glm::quat& orientation); + glm::quat angleAxis(float angle, const glm::vec3& v); }; - - #endif /* defined(__hifi__Quat__) */ diff --git a/libraries/script-engine/src/Vec3.cpp b/libraries/script-engine/src/Vec3.cpp index 87b1b510a4..1ed3ae6915 100644 --- a/libraries/script-engine/src/Vec3.cpp +++ b/libraries/script-engine/src/Vec3.cpp @@ -19,6 +19,16 @@ glm::vec3 Vec3::multiply(const glm::vec3& v1, float f) { return v1 * f; } +glm::vec3 Vec3::multiplyQbyV(const glm::quat& q, const glm::vec3& v) { + return q * v; +} + glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; } +glm::vec3 Vec3::subtract(const glm::vec3& v1, const glm::vec3& v2) { + return v1 - v2; +} +float Vec3::length(const glm::vec3& v) { + return glm::length(v); +} diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h index 1cc44f3061..20ad3f7eaa 100644 --- a/libraries/script-engine/src/Vec3.h +++ b/libraries/script-engine/src/Vec3.h @@ -23,7 +23,10 @@ class Vec3 : public QObject { public slots: glm::vec3 multiply(const glm::vec3& v1, const glm::vec3& v2); glm::vec3 multiply(const glm::vec3& v1, float f); + glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v); glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2); + float length(const glm::vec3& v); };