3
0
Fork 0
mirror of https://github.com/lubosz/overte.git synced 2025-04-27 01:55:31 +02:00

Merge pull request from SamGondelman/mouseLook

mouse look script
This commit is contained in:
Brad Hefta-Gaub 2015-06-18 17:41:20 -07:00
commit 750ce250fa
7 changed files with 229 additions and 2 deletions

View file

@ -18,4 +18,5 @@ Script.load("users.js");
Script.load("grab.js");
Script.load("pointer.js");
Script.load("directory.js");
Script.load("mouseLook.js");
Script.load("dialTone.js");

200
examples/mouseLook.js Normal file
View file

@ -0,0 +1,200 @@
//
// 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 = Window.getCursorPositionX();
var lastY = Window.getCursorPositionY();
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' && event.isMeta) {
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 = Window.getCursorPositionX();
// I'm not sure why this + 0.5 is necessary?
var y = Window.getCursorPositionY() + 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;
Window.setCursorPosition(newX, 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: "META+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);
}());

View file

@ -242,8 +242,6 @@ void KeyboardMouseDevice::assignDefaultInputMapping(UserInputMapper& mapper) {
mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(Qt::Key_PageDown), BUTTON_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(Qt::Key_PageUp), BUTTON_MOVE_SPEED);
mapper.addInputChannel(UserInputMapper::BOOM_IN, makeInput(Qt::Key_Up), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
mapper.addInputChannel(UserInputMapper::BOOM_OUT, makeInput(Qt::Key_Down), makeInput(Qt::Key_Shift), BUTTON_BOOM_SPEED);
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
mapper.addInputChannel(UserInputMapper::LATERAL_RIGHT, makeInput(Qt::Key_Right), makeInput(Qt::RightButton), BUTTON_YAW_SPEED);
mapper.addInputChannel(UserInputMapper::LATERAL_LEFT, makeInput(Qt::Key_Left), makeInput(Qt::Key_Shift), BUTTON_YAW_SPEED);

View file

@ -457,6 +457,14 @@ void ControllerScriptingInterface::resetAllDeviceBindings() {
Application::getUserInputMapper()->resetAllDeviceBindings();
}
void ControllerScriptingInterface::resetDevice(unsigned int device) {
Application::getUserInputMapper()->resetDevice(device);
}
int ControllerScriptingInterface::findDevice(QString name) {
return Application::getUserInputMapper()->findDevice(name);
}
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
AbstractInputController(),
_deviceTrackerId(deviceTrackerId),

View file

@ -91,6 +91,8 @@ public slots:
Q_INVOKABLE virtual bool removeInputChannel(UserInputMapper::InputChannel inputChannel);
Q_INVOKABLE virtual QVector<UserInputMapper::InputPair> getAvailableInputs(unsigned int device);
Q_INVOKABLE virtual void resetAllDeviceBindings();
Q_INVOKABLE virtual void resetDevice(unsigned int device);
Q_INVOKABLE virtual int findDevice(QString name);
virtual bool isPrimaryButtonPressed() const;
virtual glm::vec2 getPrimaryJoystickPosition() const;

View file

@ -41,6 +41,22 @@ void UserInputMapper::resetAllDeviceBindings() {
}
}
void UserInputMapper::resetDevice(uint16 deviceID) {
auto device = _registeredDevices.find(deviceID);
if (device != _registeredDevices.end()) {
device->second->resetDeviceBindings();
}
}
int UserInputMapper::findDevice(QString name) {
for (auto device : _registeredDevices) {
if (device.second->_name.split(" (")[0] == name) {
return device.first;
}
}
return 0;
}
bool UserInputMapper::addInputChannel(Action action, const Input& input, float scale) {
return addInputChannel(action, input, Input(), scale);
}

View file

@ -116,6 +116,8 @@ public:
QString getDeviceName(uint16 deviceID) { return _registeredDevices[deviceID]->_name; }
QVector<InputPair> getAvailableInputs(uint16 deviceID) { return _registeredDevices[deviceID]->getAvailabeInputs(); }
void resetAllDeviceBindings();
void resetDevice(uint16 deviceID);
int findDevice(QString name);
// Actions are the output channels of the Mapper, that's what the InputChannel map to
// For now the Actions are hardcoded, this is bad, but we will fix that in the near future