// // mouseLook.js // examples // // Created by Sam Gondelman on 6/16/15 // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // var lastX = Reticle.getPosition().x; var lastY = Reticle.getPosition().y; var yawFromMouse = 0; var pitchFromMouse = 0; var yawSpeed = 0; var pitchSpeed = 0; var DEFAULT_PARAMETERS = { MOUSE_YAW_SCALE: -0.125, MOUSE_PITCH_SCALE: -0.125, MOUSE_SENSITIVITY: 0.5, // Damping frequency, adjust to change mouse look behavior W: 10, } var movementParameters = DEFAULT_PARAMETERS; var mouseLook = (function () { var BUTTON_WIDTH = 50, BUTTON_HEIGHT = 50, BUTTON_ALPHA = 0.9, BUTTON_MARGIN = 8, active = false, keyboardID = 0; function onKeyPressEvent(event) { if (event.text == 'm') { active = !active; updateMapping(); } } function findInput(name) { var availableInputs = Controller.getAvailableInputs(keyboardID); for (i = 0; i < availableInputs.length; i++) { if (availableInputs[i].inputName == name) { return availableInputs[i].input; } } // If the input isn't found, it will default to the first available input return availableInputs[0].input; } function findAction(name) { var actions = Controller.getAllActions(); for (var i = 0; i < actions.length; i++) { if (actions[i].actionName == name) { return i; } } // If the action isn't found, it will default to the first available action return 0; } function updateMapping() { if (keyboardID != 0) { if (active) { // Turn mouselook on yawFromMouse = 0; pitchFromMouse = 0; yawSpeed = 0; pitchSpeed = 0; var a = findInput("A").channel; var d = findInput("D").channel; var left = findInput("Left").channel; var right = findInput("Right").channel; var shift = findInput("Shift").channel; for (var i = findAction("YAW_LEFT"); i <= findAction("YAW_RIGHT"); i++) { var inputChannels = Controller.getAllActions()[i].inputChannels; for (var j = 0; j < inputChannels.length; j++) { var inputChannel = inputChannels[j]; // make a, d, left, and right strafe if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.device == 0) { Controller.removeInputChannel(inputChannel); inputChannel.action = findAction("LATERAL_LEFT"); Controller.addInputChannel(inputChannel); } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.device == 0) { Controller.removeInputChannel(inputChannel); inputChannel.action = findAction("LATERAL_RIGHT"); Controller.addInputChannel(inputChannel); } } } for (var i = findAction("LATERAL_LEFT"); i <= findAction("LATERAL_RIGHT"); i++) { var inputChannels = Controller.getAllActions()[i].inputChannels; for (var j = 0; j < inputChannels.length; j++) { var inputChannel = inputChannels[j]; // make shift + a/d/left/right change yaw/pitch if ((inputChannel.input.channel == a || inputChannel.input.channel == left) && inputChannel.modifier.channel == shift) { Controller.removeInputChannel(inputChannel); inputChannel.action = findAction("YAW_LEFT"); Controller.addInputChannel(inputChannel); } else if ((inputChannel.input.channel == d || inputChannel.input.channel == right) && inputChannel.modifier.channel == shift) { Controller.removeInputChannel(inputChannel); inputChannel.action = findAction("YAW_RIGHT"); Controller.addInputChannel(inputChannel); } } } } else { Controller.resetDevice(keyboardID); } } } function onScriptUpdate(dt) { if (active && Window.hasFocus()) { var x = Reticle.getPosition().x; // I'm not sure why this + 0.5 is necessary? var y = Reticle.getPosition().y; + 0.5; yawFromMouse += ((x - lastX) * movementParameters.MOUSE_YAW_SCALE * movementParameters.MOUSE_SENSITIVITY); pitchFromMouse += ((y - lastY) * movementParameters.MOUSE_PITCH_SCALE * movementParameters.MOUSE_SENSITIVITY); pitchFromMouse = Math.max(-180, Math.min(180, pitchFromMouse)); resetCursorPosition(); // Here we use a linear damping model - http://en.wikipedia.org/wiki/Damping#Linear_damping // Because we are using a critically damped model (no oscillation), ΞΆ = 1 and // so we derive the formula: acceleration = -(2 * w0 * v) - (w0^2 * x) var W = movementParameters.W; yawAccel = (W * W * yawFromMouse) - (2 * W * yawSpeed); pitchAccel = (W * W * pitchFromMouse) - (2 * W * pitchSpeed); yawSpeed += yawAccel * dt; var yawMove = yawSpeed * dt; var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees( { x: 0, y: yawMove, z: 0 } )); MyAvatar.orientation = newOrientation; yawFromMouse -= yawMove; pitchSpeed += pitchAccel * dt; var pitchMove = pitchSpeed * dt; var newPitch = MyAvatar.headPitch + pitchMove; MyAvatar.headPitch = newPitch; pitchFromMouse -= pitchMove; } } function resetCursorPosition() { var newX = Window.x + Window.innerWidth / 2.0; var newY = Window.y + Window.innerHeight / 2.0; Reticle.setPosition({ x: newX, y: newY}); lastX = newX; lastY = newY; } function setUp() { keyboardID = Controller.findDevice("Keyboard"); Controller.keyPressEvent.connect(onKeyPressEvent); Menu.menuItemEvent.connect(handleMenuEvent); Script.update.connect(onScriptUpdate); } function setupMenu() { Menu.addMenuItem({ menuName: "View", menuItemName: "Mouselook Mode", shortcutKey: "SHIFT+M", afterItem: "Mirror", isCheckable: true, isChecked: false }); } setupMenu(); function cleanupMenu() { Menu.removeMenuItem("View", "Mouselook Mode"); } function handleMenuEvent(menuItem) { if (menuItem == "Mouselook Mode") { active = !active; updateMapping(); } } function tearDown() { if (keyboardID != 0) { Controller.resetDevice(keyboardID); } cleanupMenu(); } setUp(); Script.scriptEnding.connect(tearDown); }());