This commit is contained in:
Stephen Birarda 2015-06-26 08:49:20 -07:00
commit 81770cfeb2
14 changed files with 1501 additions and 1659 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,89 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="walkStyle.css">
<script>
function emitUpdate() {
EventBridge.emitWebEvent(JSON.stringify({
type: "update",
armsFree: elArmsFree.checked,
makesFootStepSounds: elFootstepSounds.checked,
blenderPreRotations: elBlenderPreRotations.checked
}));
}
function loaded() {
// assign form elements to vars
var powerOn = true;
elPower = document.getElementById("power");
elArmsFree = document.getElementById("arms-free");
elFootstepSounds = document.getElementById("footstep-sounds");
elBlenderPreRotations = document.getElementById("bender-pre-rotations");
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.type == "update") {
if (data.armsFree !== undefined) {
elArmsFree.checked = data.armsFree;
}
if (data.makesFootStepSounds !== undefined) {
elFootstepSounds.checked = data.makesFootStepSounds;
}
if (data.blenderPreRotations !== undefined) {
elBlenderPreRotations.checked = data.blenderPreRotations;
}
}
});
}
elArmsFree.addEventListener("change", emitUpdate);
elFootstepSounds.addEventListener("change", emitUpdate);
elBlenderPreRotations.addEventListener("change", emitUpdate);
elPower.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
type: "powerToggle"
}));
powerOn = !powerOn;
if (powerOn) {
elPower.value = "Turn Animation Off";
} else {
elPower.value = "Turn Animation On";
}
});
// request initial values
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
}
</script>
</head>
<body onload='loaded();'>
<div>
<div id="walk-settings-header">
<input type="button" id="power" value="Turn Animation Off" style="margin-left:30px; margin-top:10px"></button>
</div>
<div class="settings-section">
<label>Arms free</label>
<span>
<input type='checkbox' id="arms-free">
</span>
</div>
<div class="settings-section">
<label>Footstep sounds</label>
<span>
<input type='checkbox' id="footstep-sounds">
</span>
</div>
<div class="settings-section">
<label>Blender pre-rotations</label>
<span>
<input type='checkbox' id="bender-pre-rotations">
</span>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,48 @@
* {
}
body {
margin: 0;
padding: 0;
background-color: rgb(76, 76, 76);
color: rgb(204, 204, 204);
font-family: Arial;
font-size: 9pt;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#walk-settings-header {
padding: 0.5em;
}
.settings-section {
display: block;
margin: 10 10;
height: 22.5pt;
}
.settings-section label {
font-weight: bold;
}
.settings-section span {
float: right;
}
input[type=button] {
cursor: pointer;
background-color: #608e96;
border-color: #608e96;
border-radius: 3.75pt;
padding: 3.75pt 7.5pt;
border: 0;
color: #fff;
font-weight: bold;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
//
// walkConstants.js
// version 1.0
//
// Created by David Wooldridge, June 2015
// Copyright © 2015 High Fidelity, Inc.
//
// Provides constants necessary for the operation of the walk.js script and the walkApi.js script
//
// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// locomotion states
STATIC = 1;
SURFACE_MOTION = 2;
AIR_MOTION = 4;
// directions
UP = 1;
DOWN = 2;
LEFT = 4;
RIGHT = 8;
FORWARDS = 16;
BACKWARDS = 32;
NONE = 64;
// waveshapes
SAWTOOTH = 1;
TRIANGLE = 2;
SQUARE = 4;
// used by walk.js and walkApi.js
MAX_WALK_SPEED = 2.9; // peak, by observation
MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
TOP_SPEED = 300;
ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
TRANSITION_COMPLETE = 1000;
PITCH_MAX = 60; // maximum speed induced pitch
ROLL_MAX = 80; // maximum speed induced leaning / banking
DELTA_YAW_MAX = 1.7; // maximum change in yaw in rad/s
// used by walkApi.js only
MOVE_THRESHOLD = 0.075; // movement dead zone
ACCELERATION_THRESHOLD = 0.2; // detect stop to walking
DECELERATION_THRESHOLD = -6; // detect walking to stop
FAST_DECELERATION_THRESHOLD = -150; // detect flying to stop
BOUNCE_ACCELERATION_THRESHOLD = 25; // used to ignore gravity influence fluctuations after landing
GRAVITY_THRESHOLD = 3.0; // height above surface where gravity is in effect
OVERCOME_GRAVITY_SPEED = 0.5; // reaction sensitivity to jumping under gravity
LANDING_THRESHOLD = 0.35; // metres from a surface below which need to prepare for impact
MAX_TRANSITION_RECURSION = 10; // how many nested transitions are permitted

View file

@ -1,134 +1,78 @@
//
// walkFilters.js
// version 1.1
//
// version 1.002
// Created by David Wooldridge, June 2015
// Copyright © 2014 - 2015 High Fidelity, Inc.
//
// Created by David Wooldridge, Autumn 2014
//
// Provides a variety of filters for use by the walk.js script v1.12
// Provides a variety of filters for use by the walk.js script v1.2+
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// simple averaging (LP) filter for damping / smoothing
AveragingFilter = function(length) {
//this.name = name;
// initialise the array of past values
this.pastValues = [];
for(var i = 0; i < length; i++) {
for (var i = 0; i < length; i++) {
this.pastValues.push(0);
}
// single arg is the nextInputValue
this.process = function() {
if (this.pastValues.length === 0 && arguments[0]) {
return arguments[0];
} else if (arguments[0] !== null) {
// apply quick and simple LP filtering
this.pastValues.push(arguments[0]);
this.pastValues.shift();
var nextOutputValue = 0;
for (var ea in this.pastValues) nextOutputValue += this.pastValues[ea];
for (var value in this.pastValues) nextOutputValue += this.pastValues[value];
return nextOutputValue / this.pastValues.length;
} else {
return 0;
}
};
};
// 1st order Butterworth filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
// provides LP filtering with a more stable frequency / phase response (-3 dB @ 3 Hz)
ButterworthFilter1 = function() {
this.gain = 7.313751515;
this.coeff = 0.7265425280;
// 2nd order 2Hz Butterworth LP filter
ButterworthFilter = function() {
// coefficients calculated at: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
this.gain = 104.9784742;
this.coeffOne = -0.7436551950;
this.coeffTwo = 1.7055521455;
// initialise the arrays
this.xv = [];
this.yv = [];
for(var i = 0; i < 2; i++) {
for (var i = 0; i < 3; i++) {
this.xv.push(0);
this.yv.push(0);
}
// process values
this.process = function(nextInputValue) {
this.xv[0] = this.xv[1];
this.xv[1] = nextInputValue / this.gain;
this.yv[0] = this.yv[1];
this.yv[1] = this.xv[0] + this.xv[1] + this.coeff * this.yv[0];
return this.yv[1];
};
}; // end Butterworth filter constructor
// 2nd order Butterworth LP filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
// provides LP filtering with a more stable frequency / phase response
ButterworthFilter2 = function(cutOff) {
switch(cutOff) {
case 5:
default:
this.gain = 20.20612010;
this.coeffOne = -0.4775922501;
this.coeffTwo = 1.2796324250;
break;
}
// initialise the arrays
this.xv = [];
this.yv = [];
for(var i = 0; i < 3; i++) {
this.xv.push(0);
this.yv.push(0);
}
// process values
this.process = function(nextInputValue) {
this.xv[0] = this.xv[1];
this.xv[1] = this.xv[2];
this.xv[2] = nextInputValue / this.gain;
this.yv[0] = this.yv[1];
this.yv[1] = this.yv[2];
this.yv[2] = (this.xv[0] + this.xv[2]) +
2 * this.xv[1] +
(this.coeffOne * this.yv[0]) +
(this.coeffTwo * this.yv[1]);
return this.yv[2];
};
}; // end Butterworth filter constructor
// Add harmonics to a given sine wave to form square, sawtooth or triangle waves
// Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html
WaveSynth = function(waveShape, numHarmonics, smoothing) {
this.numHarmonics = numHarmonics;
this.waveShape = waveShape;
this.smoothingFilter = new AveragingFilter(smoothing);
// NB: frequency in radians
this.calculate = function(frequency) {
// make some shapes
var harmonics = 0;
var multiplier = 0;
@ -136,20 +80,15 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
if (this.waveShape === TRIANGLE) {
iterations++;
}
for(var n = 1; n < iterations; n++) {
switch(this.waveShape) {
for (var n = 1; n < iterations; n++) {
switch (this.waveShape) {
case SAWTOOTH: {
multiplier = 1 / n;
harmonics += multiplier * Math.sin(n * frequency);
break;
}
case TRIANGLE: {
if (n % 2 === 1) {
var mulitplier = 1 / (n * n);
// multiply (4n-1)th harmonics by -1
@ -162,7 +101,6 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
}
case SQUARE: {
if (n % 2 === 1) {
multiplier = 1 / n;
harmonics += multiplier * Math.sin(n * frequency);
@ -171,34 +109,35 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
}
}
}
// smooth the result and return
return this.smoothingFilter.process(harmonics);
};
};
// Create a motion wave by summing pre-calcualted sinusoidal harmonics
// Create a motion wave by summing pre-calculated harmonics (Fourier synthesis)
HarmonicsFilter = function(magnitudes, phaseAngles) {
this.magnitudes = magnitudes;
this.phaseAngles = phaseAngles;
this.calculate = function(twoPiFT) {
var harmonics = 0;
var numHarmonics = magnitudes.length;
for(var n = 0; n < numHarmonics; n++) {
for (var n = 0; n < numHarmonics; n++) {
harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]);
}
return harmonics;
};
};
// the main filter object
// the main filter object literal
filter = (function() {
const HALF_CYCLE = 180;
// Bezier private variables
var _C1 = {x:0, y:0};
var _C4 = {x:1, y:1};
// Bezier private functions
function _B1(t) { return t * t * t };
function _B2(t) { return 3 * t * t * (1 - t) };
@ -209,63 +148,52 @@ filter = (function() {
// helper methods
degToRad: function(degrees) {
var convertedValue = degrees * Math.PI / 180;
var convertedValue = degrees * Math.PI / HALF_CYCLE;
return convertedValue;
},
radToDeg: function(radians) {
var convertedValue = radians * 180 / Math.PI;
var convertedValue = radians * HALF_CYCLE / Math.PI;
return convertedValue;
},
// these filters need instantiating, as they hold arrays of previous values
createAveragingFilter: function(length) {
// simple averaging (LP) filter for damping / smoothing
createAveragingFilter: function(length) {
var newAveragingFilter = new AveragingFilter(length);
return newAveragingFilter;
},
createButterworthFilter1: function() {
var newButterworthFilter = new ButterworthFilter1();
return newButterworthFilter;
},
createButterworthFilter2: function(cutoff) {
var newButterworthFilter = new ButterworthFilter2(cutoff);
// provides LP filtering with improved frequency / phase response
createButterworthFilter: function() {
var newButterworthFilter = new ButterworthFilter();
return newButterworthFilter;
},
// generates sawtooth, triangle or square waves using harmonics
createWaveSynth: function(waveShape, numHarmonics, smoothing) {
var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing);
return newWaveSynth;
},
// generates arbitrary waveforms using pre-calculated harmonics
createHarmonicsFilter: function(magnitudes, phaseAngles) {
var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles);
return newHarmonicsFilter;
},
// the following filters do not need separate instances, as they hold no previous values
bezier: function(percent, C1, C2, C3, C4) {
// Bezier functions for more natural transitions
// Bezier response curve shaping for more natural transitions
bezier: function(input, C2, C3) {
// based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/
var pos = {x: 0, y: 0};
pos.x = C1.x * _B1(percent) + C2.x * _B2(percent) + C3.x * _B3(percent) + C4.x * _B4(percent);
pos.y = C1.y * _B1(percent) + C2.y * _B2(percent) + C3.y * _B3(percent) + C4.y * _B4(percent);
return pos;
input = 1 - input;
return _C1.y * _B1(input) + C2.y * _B2(input) + C3.y * _B3(input) + _C4.y * _B4(input);
},
// simple clipping filter (clips bottom of wave only)
// simple clipping filter (special case for hips y-axis skeleton offset for walk animation)
clipTrough: function(inputValue, peak, strength) {
var outputValue = inputValue * strength;
if (outputValue < -peak) {
outputValue = -peak;
@ -273,5 +201,4 @@ filter = (function() {
return outputValue;
}
}
})();

View file

@ -1,340 +0,0 @@
//
// walkInterface.js
//
// version 2.0
//
// Created by David Wooldridge, Autumn 2014
//
// Presents the UI for the walk.js script v1.12
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
walkInterface = (function() {
// references to walk.js objects
var _motion = null;
var _walkAssets = null;
// controller UI element positions and dimensions
var _backgroundWidth = 350;
var _backgroundHeight = 700;
var _backgroundX = Window.innerWidth - _backgroundWidth - 58;
var _backgroundY = Window.innerHeight / 2 - _backgroundHeight / 2;
var _bigButtonsY = 348;
// Load up the overlays
var _buttonOverlays = [];
// ui minimised tab
var _controlsMinimisedTab = Overlays.addOverlay("image", {
x: Window.innerWidth - 58,
y: Window.innerHeight - 145,
width: 50, height: 50,
imageURL: pathToAssets + 'overlay-images/minimised-tab.png',
visible: true, alpha: 0.9
});
// ui background
var _controlsBackground = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX,
y: _backgroundY,
width: _backgroundWidth,
height: _backgroundHeight
},
imageURL: pathToAssets + "overlay-images/background.png",
alpha: 1, visible: false
});
// button overlays
var _controlsMinimiseButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth - 62,
y: _backgroundY + 40,
width: 25, height: 25
},
imageURL: pathToAssets + "overlay-images/minimise-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_controlsMinimiseButton);
var _onButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/power-button-selected.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_onButton);
var _offButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/power-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_offButton);
var _femaleButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 60,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/female-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_femaleButton);
var _femaleButtonSelected = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 60,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/female-button-selected.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_femaleButtonSelected);
var _maleButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 120,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/male-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_maleButton);
var _maleButtonSelected = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 120,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/male-button-selected.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_maleButtonSelected);
var _armsFreeButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 180,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/arms-free-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_armsFreeButton);
var _armsFreeButtonSelected = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 180,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/arms-free-button-selected.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_armsFreeButtonSelected);
var _footstepsButton = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 240,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/footstep-sounds-button.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_footstepsButton);
var _footstepsButtonSelected = Overlays.addOverlay("image", {
bounds: {
x: _backgroundX + _backgroundWidth / 2 - 115,
y: _backgroundY + _bigButtonsY + 240,
width: 230, height: 36
},
imageURL: pathToAssets + "overlay-images/footstep-sounds-button-selected.png",
alpha: 1, visible: false
});
_buttonOverlays.push(_footstepsButtonSelected);
function minimiseDialog(minimise) {
Overlays.editOverlay(_controlsBackground, {visible: !minimise});
Overlays.editOverlay(_controlsMinimisedTab, {visible: minimise});
Overlays.editOverlay(_controlsMinimiseButton, {visible: !minimise});
if(_state.powerOn) {
Overlays.editOverlay(_onButton, {visible: !minimise});
Overlays.editOverlay(_offButton, {visible: false});
} else {
Overlays.editOverlay(_onButton, {visible: false});
Overlays.editOverlay(_offButton, {visible: !minimise});
}
if (_motion.avatarGender === FEMALE) {
Overlays.editOverlay(_femaleButtonSelected, {visible: !minimise});
Overlays.editOverlay(_femaleButton, {visible: false});
Overlays.editOverlay(_maleButtonSelected, {visible: false});
Overlays.editOverlay(_maleButton, {visible: !minimise});
} else {
Overlays.editOverlay(_femaleButtonSelected, {visible: false});
Overlays.editOverlay(_femaleButton, {visible: !minimise});
Overlays.editOverlay(_maleButtonSelected, {visible: !minimise});
Overlays.editOverlay(_maleButton, {visible: false});
}
if (_motion.armsFree) {
Overlays.editOverlay(_armsFreeButtonSelected, {visible: !minimise});
Overlays.editOverlay(_armsFreeButton, {visible: false});
} else {
Overlays.editOverlay(_armsFreeButtonSelected, {visible: false});
Overlays.editOverlay(_armsFreeButton, {visible: !minimise});
}
if (_motion.makesFootStepSounds) {
Overlays.editOverlay(_footstepsButtonSelected, {visible: !minimise});
Overlays.editOverlay(_footstepsButton, {visible: false});
} else {
Overlays.editOverlay(_footstepsButtonSelected, {visible: false});
Overlays.editOverlay(_footstepsButton, {visible: !minimise});
}
};
// mouse event handler
function mousePressEvent(event) {
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
switch (clickedOverlay) {
case _controlsMinimiseButton:
minimiseDialog(true);
_state.setInternalState(_state.STANDING);
return;
case _controlsMinimisedTab:
minimiseDialog(false);
_state.setInternalState(_state.STANDING);
return;
case _onButton:
_state.powerOn = false;
Overlays.editOverlay(_offButton, {visible: true});
Overlays.editOverlay(_onButton, {visible: false});
_state.setInternalState(state.STANDING);
return;
case _offButton:
_state.powerOn = true;
Overlays.editOverlay(_offButton, {visible: false});
Overlays.editOverlay(_onButton, {visible: true});
_state.setInternalState(state.STANDING);
return;
case _footstepsButton:
_motion.makesFootStepSounds = true;
Overlays.editOverlay(_footstepsButtonSelected, {visible: true});
Overlays.editOverlay(_footstepsButton, {visible: false});
return;
case _footstepsButtonSelected:
_motion.makesFootStepSounds = false;
Overlays.editOverlay(_footstepsButton, {visible: true});
Overlays.editOverlay(_footstepsButtonSelected, {visible: false});
return;
case _femaleButton:
case _maleButtonSelected:
_motion.setGender(FEMALE);
Overlays.editOverlay(_femaleButtonSelected, {visible: true});
Overlays.editOverlay(_femaleButton, {visible: false});
Overlays.editOverlay(_maleButton, {visible: true});
Overlays.editOverlay(_maleButtonSelected, {visible: false});
return;
case _maleButton:
case _femaleButtonSelected:
_motion.setGender(MALE);
Overlays.editOverlay(_femaleButton, {visible: true});
Overlays.editOverlay(_femaleButtonSelected, {visible: false});
Overlays.editOverlay(_maleButtonSelected, {visible: true});
Overlays.editOverlay(_maleButton, {visible: false});
return;
case _armsFreeButton:
_motion.armsFree = true;
Overlays.editOverlay(_armsFreeButtonSelected, {visible: true});
Overlays.editOverlay(_armsFreeButton, {visible: false});
return;
case _armsFreeButtonSelected:
_motion.armsFree = false;
_motion.poseFingers();
Overlays.editOverlay(_armsFreeButtonSelected, {visible: false});
Overlays.editOverlay(_armsFreeButton, {visible: true});
return;
}
};
Controller.mousePressEvent.connect(mousePressEvent);
// delete overlays on script ending
Script.scriptEnding.connect(function() {
// delete overlays
Overlays.deleteOverlay(_controlsBackground);
Overlays.deleteOverlay(_controlsMinimisedTab);
for (var i in _buttonOverlays) {
Overlays.deleteOverlay(_buttonOverlays[i]);
}
});
// public method
return {
// gather references to objects from the walk.js script
initialise: function(state, motion, walkAssets) {
_state = state;
_motion = motion;
_walkAssets = walkAssets;
}
}; // end public methods (return)
})();

View file

@ -0,0 +1,97 @@
//
// walkSettings.js
// version 0.1
//
// Created by David Wooldridge, June 2015
// Copyright © 2015 High Fidelity, Inc.
//
// Presents settings for walk.js
//
// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
WalkSettings = function() {
var _visible = false;
var _innerWidth = Window.innerWidth;
const MARGIN_RIGHT = 58;
const MARGIN_TOP = 145;
const ICON_SIZE = 50;
const ICON_ALPHA = 0.9;
var minimisedTab = Overlays.addOverlay("image", {
x: _innerWidth - MARGIN_RIGHT, y: Window.innerHeight - MARGIN_TOP,
width: ICON_SIZE, height: ICON_SIZE,
imageURL: pathToAssets + 'overlay-images/ddpa-minimised-ddpa-tab.png',
visible: true, alpha: ICON_ALPHA
});
function mousePressEvent(event) {
if (Overlays.getOverlayAtPoint(event) === minimisedTab) {
_visible = !_visible;
_webWindow.setVisible(_visible);
}
}
Controller.mousePressEvent.connect(mousePressEvent);
Script.update.connect(function(deltaTime) {
if (window.innerWidth !== _innerWidth) {
_innerWidth = window.innerWidth;
Overlays.EditOverlay(minimisedTab, {x: _innerWidth - MARGIN_RIGHT});
}
});
function cleanup() {
Overlays.deleteOverlay(minimisedTab);
}
Script.scriptEnding.connect(cleanup);
var _shift = false;
function keyPressEvent(event) {
if (event.text === "SHIFT") {
_shift = true;
}
if (_shift && (event.text === 'o' || event.text === 'O')) {
_visible = !_visible;
_webWindow.setVisible(_visible);
}
}
function keyReleaseEvent(event) {
if (event.text === "SHIFT") {
_shift = false;
}
}
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);
// web window
const PANEL_WIDTH = 200;
const PANEL_HEIGHT = 180;
var _url = Script.resolvePath('html/walkSettings.html');
var _webWindow = new WebWindow('Walk Settings', _url, PANEL_WIDTH, PANEL_HEIGHT, false);
_webWindow.setVisible(false);
_webWindow.eventBridge.webEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.type == "init") {
// send the current settings to the window
_webWindow.eventBridge.emitScriptEvent(JSON.stringify({
type: "update",
armsFree: avatar.armsFree,
makesFootStepSounds: avatar.makesFootStepSounds,
blenderPreRotations: avatar.blenderPreRotations
}));
} else if (data.type == "powerToggle") {
motion.isLive = !motion.isLive;
} else if (data.type == "update") {
// receive settings from the window
avatar.armsFree = data.armsFree;
avatar.makesFootStepSounds = data.makesFootStepSounds;
avatar.blenderPreRotations = data.blenderPreRotations;
}
});
};
walkSettings = WalkSettings();

File diff suppressed because it is too large Load diff

View file

@ -891,8 +891,11 @@ void Application::paintGL() {
glEnable(GL_LINE_SMOOTH);
Menu::getInstance()->setIsOptionChecked("First Person", _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
Application::getInstance()->cameraMenuChanged();
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(_myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
Application::getInstance()->cameraMenuChanged();
}
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
// Always use the default eye position, not the actual head eye position.
@ -1384,11 +1387,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::Mirror);
} else {
Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror);
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror));
if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
}
cameraMenuChanged();
}
break;
case Qt::Key_P:
Menu::getInstance()->triggerOption(MenuOption::FirstPerson);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson));
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !Menu::getInstance()->isOptionChecked(MenuOption::FirstPerson));
cameraMenuChanged();
break;
case Qt::Key_Slash:
Menu::getInstance()->triggerOption(MenuOption::Stats);
@ -2351,13 +2360,17 @@ void Application::cameraMenuChanged() {
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
_myAvatar->setBoomLength(MyAvatar::ZOOM_MIN);
}
} else {
} else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) {
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) {
_myAvatar->setBoomLength(MyAvatar::ZOOM_DEFAULT);
}
}
} else if (Menu::getInstance()->isOptionChecked(MenuOption::IndependentMode)) {
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
_myCamera.setMode(CAMERA_MODE_INDEPENDENT);
}
}
}
@ -2451,20 +2464,22 @@ void Application::update(float deltaTime) {
// Transfer the user inputs to the driveKeys
_myAvatar->clearDriveKeys();
if (!_controllerScriptingInterface.areActionsCaptured()) {
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
if (!_controllerScriptingInterface.areActionsCaptured()) {
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
}
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
}
_myAvatar->setDriveKeys(BOOM_IN, _userInputMapper.getActionState(UserInputMapper::BOOM_IN));
_myAvatar->setDriveKeys(BOOM_OUT, _userInputMapper.getActionState(UserInputMapper::BOOM_OUT));
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...

View file

@ -444,6 +444,8 @@ public slots:
void notifyPacketVersionMismatch();
void domainConnectionDenied(const QString& reason);
void cameraMenuChanged();
private slots:
void clearDomainOctreeDetails();
@ -460,7 +462,7 @@ private slots:
void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode);
void setEnableVRMode(bool enableVRMode);
void cameraMenuChanged();
void rotationModeChanged();
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);

View file

@ -87,24 +87,26 @@ PickRay Camera::computePickRay(float x, float y) {
void Camera::setModeString(const QString& mode) {
CameraMode targetMode = stringToMode(mode);
switch (targetMode) {
case CAMERA_MODE_FIRST_PERSON:
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
break;
case CAMERA_MODE_THIRD_PERSON:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
break;
case CAMERA_MODE_MIRROR:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
break;
case CAMERA_MODE_INDEPENDENT:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true);
break;
default:
break;
}
qApp->cameraMenuChanged();
if (_mode != targetMode) {
setMode(targetMode);
}

View file

@ -268,9 +268,22 @@ Menu::Menu() {
qApp,
SLOT(setFullscreen(bool)));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
0, // QML Qt::Key_P,
true, qApp, SLOT(cameraMenuChanged()));
MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode");
QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu);
cameraModeGroup->setExclusive(true);
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::FirstPerson, 0, // QML Qt:: Key_P
false, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::ThirdPerson, 0,
true, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::IndependentMode, 0,
false, qApp, SLOT(cameraMenuChanged())));
cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(cameraModeMenu,
MenuOption::FullscreenMirror, 0, // QML Qt::Key_H,
false, qApp, SLOT(cameraMenuChanged())));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
0, //QML Qt::SHIFT | Qt::Key_H,
true);

View file

@ -158,6 +158,7 @@ namespace MenuOption {
const QString CascadedShadows = "Cascaded";
const QString CachesSize = "RAM Caches Size";
const QString CalibrateCamera = "Calibrate Camera";
const QString CenterPlayerInView = "Center Player In View";
const QString Chat = "Chat...";
const QString Collisions = "Collisions";
const QString Console = "Console...";
@ -199,11 +200,10 @@ namespace MenuOption {
const QString FrameTimer = "Show Timer";
const QString Fullscreen = "Fullscreen";
const QString FullscreenMirror = "Fullscreen Mirror";
const QString CenterPlayerInView = "Center Player In View";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString NamesAboveHeads = "Names Above Heads";
const QString HMDTools = "HMD Tools";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
const QString LeapMotionOnHMD = "Leap Motion on HMD";
const QString LoadScript = "Open and Run Script File...";
@ -217,6 +217,7 @@ namespace MenuOption {
const QString MuteAudio = "Mute Microphone";
const QString MuteEnvironment = "Mute Environment";
const QString MuteFaceTracking = "Mute Face Tracking";
const QString NamesAboveHeads = "Names Above Heads";
const QString NoFaceTracking = "None";
const QString OctreeStats = "Entity Statistics";
const QString OnlyDisplayTopTen = "Only Display Top Ten";
@ -277,6 +278,7 @@ namespace MenuOption {
const QString StopAllScripts = "Stop All Scripts";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString TestPing = "Test Ping";
const QString ThirdPerson = "Third Person";
const QString ToolWindow = "Tool Window";
const QString TransmitterDrive = "Transmitter Drive";
const QString TurnWithHead = "Turn using Head";