mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 17:01:18 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
b1c361b324
17 changed files with 1598 additions and 1682 deletions
|
@ -977,7 +977,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="sub-section-header">
|
<div class="section-header">
|
||||||
<label>Hyperlink</label>
|
<label>Hyperlink</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
4
examples/html/jquery-2.1.4.min.js
vendored
4
examples/html/jquery-2.1.4.min.js
vendored
File diff suppressed because one or more lines are too long
89
examples/html/walkSettings.html
Normal file
89
examples/html/walkSettings.html
Normal 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>
|
48
examples/html/walkStyle.css
Normal file
48
examples/html/walkStyle.css
Normal 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
54
examples/libraries/walkConstants.js
Normal file
54
examples/libraries/walkConstants.js
Normal 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
|
|
@ -1,134 +1,78 @@
|
||||||
//
|
//
|
||||||
// walkFilters.js
|
// 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.2+
|
||||||
//
|
|
||||||
// Provides a variety of filters for use by the walk.js script v1.12
|
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// 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) {
|
AveragingFilter = function(length) {
|
||||||
|
// initialise the array of past values
|
||||||
//this.name = name;
|
|
||||||
this.pastValues = [];
|
this.pastValues = [];
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
for(var i = 0; i < length; i++) {
|
|
||||||
this.pastValues.push(0);
|
this.pastValues.push(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// single arg is the nextInputValue
|
// single arg is the nextInputValue
|
||||||
this.process = function() {
|
this.process = function() {
|
||||||
|
|
||||||
if (this.pastValues.length === 0 && arguments[0]) {
|
if (this.pastValues.length === 0 && arguments[0]) {
|
||||||
|
|
||||||
return arguments[0];
|
return arguments[0];
|
||||||
|
|
||||||
} else if (arguments[0] !== null) {
|
} else if (arguments[0] !== null) {
|
||||||
|
|
||||||
// apply quick and simple LP filtering
|
|
||||||
this.pastValues.push(arguments[0]);
|
this.pastValues.push(arguments[0]);
|
||||||
this.pastValues.shift();
|
this.pastValues.shift();
|
||||||
var nextOutputValue = 0;
|
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;
|
return nextOutputValue / this.pastValues.length;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 2nd order 2Hz Butterworth LP filter
|
||||||
// 1st order Butterworth filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
|
ButterworthFilter = function() {
|
||||||
// provides LP filtering with a more stable frequency / phase response (-3 dB @ 3 Hz)
|
// coefficients calculated at: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
|
||||||
ButterworthFilter1 = function() {
|
this.gain = 104.9784742;
|
||||||
|
this.coeffOne = -0.7436551950;
|
||||||
this.gain = 7.313751515;
|
this.coeffTwo = 1.7055521455;
|
||||||
this.coeff = 0.7265425280;
|
|
||||||
|
|
||||||
// initialise the arrays
|
// initialise the arrays
|
||||||
this.xv = [];
|
this.xv = [];
|
||||||
this.yv = [];
|
this.yv = [];
|
||||||
|
for (var i = 0; i < 3; i++) {
|
||||||
for(var i = 0; i < 2; i++) {
|
|
||||||
|
|
||||||
this.xv.push(0);
|
this.xv.push(0);
|
||||||
this.yv.push(0);
|
this.yv.push(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process values
|
// process values
|
||||||
this.process = function(nextInputValue) {
|
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[0] = this.xv[1];
|
||||||
this.xv[1] = this.xv[2];
|
this.xv[1] = this.xv[2];
|
||||||
this.xv[2] = nextInputValue / this.gain;
|
this.xv[2] = nextInputValue / this.gain;
|
||||||
|
|
||||||
this.yv[0] = this.yv[1];
|
this.yv[0] = this.yv[1];
|
||||||
this.yv[1] = this.yv[2];
|
this.yv[1] = this.yv[2];
|
||||||
this.yv[2] = (this.xv[0] + this.xv[2]) +
|
this.yv[2] = (this.xv[0] + this.xv[2]) +
|
||||||
2 * this.xv[1] +
|
2 * this.xv[1] +
|
||||||
(this.coeffOne * this.yv[0]) +
|
(this.coeffOne * this.yv[0]) +
|
||||||
(this.coeffTwo * this.yv[1]);
|
(this.coeffTwo * this.yv[1]);
|
||||||
|
|
||||||
return this.yv[2];
|
return this.yv[2];
|
||||||
};
|
};
|
||||||
}; // end Butterworth filter constructor
|
}; // end Butterworth filter constructor
|
||||||
|
|
||||||
|
|
||||||
// Add harmonics to a given sine wave to form square, sawtooth or triangle waves
|
// 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
|
// Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html
|
||||||
WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
||||||
|
|
||||||
this.numHarmonics = numHarmonics;
|
this.numHarmonics = numHarmonics;
|
||||||
this.waveShape = waveShape;
|
this.waveShape = waveShape;
|
||||||
this.smoothingFilter = new AveragingFilter(smoothing);
|
this.smoothingFilter = new AveragingFilter(smoothing);
|
||||||
|
|
||||||
// NB: frequency in radians
|
// NB: frequency in radians
|
||||||
this.calculate = function(frequency) {
|
this.calculate = function(frequency) {
|
||||||
|
|
||||||
// make some shapes
|
// make some shapes
|
||||||
var harmonics = 0;
|
var harmonics = 0;
|
||||||
var multiplier = 0;
|
var multiplier = 0;
|
||||||
|
@ -136,20 +80,15 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
||||||
if (this.waveShape === TRIANGLE) {
|
if (this.waveShape === TRIANGLE) {
|
||||||
iterations++;
|
iterations++;
|
||||||
}
|
}
|
||||||
|
for (var n = 1; n < iterations; n++) {
|
||||||
for(var n = 1; n < iterations; n++) {
|
switch (this.waveShape) {
|
||||||
|
|
||||||
switch(this.waveShape) {
|
|
||||||
|
|
||||||
case SAWTOOTH: {
|
case SAWTOOTH: {
|
||||||
|
|
||||||
multiplier = 1 / n;
|
multiplier = 1 / n;
|
||||||
harmonics += multiplier * Math.sin(n * frequency);
|
harmonics += multiplier * Math.sin(n * frequency);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TRIANGLE: {
|
case TRIANGLE: {
|
||||||
|
|
||||||
if (n % 2 === 1) {
|
if (n % 2 === 1) {
|
||||||
var mulitplier = 1 / (n * n);
|
var mulitplier = 1 / (n * n);
|
||||||
// multiply (4n-1)th harmonics by -1
|
// multiply (4n-1)th harmonics by -1
|
||||||
|
@ -162,7 +101,6 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case SQUARE: {
|
case SQUARE: {
|
||||||
|
|
||||||
if (n % 2 === 1) {
|
if (n % 2 === 1) {
|
||||||
multiplier = 1 / n;
|
multiplier = 1 / n;
|
||||||
harmonics += multiplier * Math.sin(n * frequency);
|
harmonics += multiplier * Math.sin(n * frequency);
|
||||||
|
@ -171,34 +109,35 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// smooth the result and return
|
// smooth the result and return
|
||||||
return this.smoothingFilter.process(harmonics);
|
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) {
|
HarmonicsFilter = function(magnitudes, phaseAngles) {
|
||||||
|
|
||||||
this.magnitudes = magnitudes;
|
this.magnitudes = magnitudes;
|
||||||
this.phaseAngles = phaseAngles;
|
this.phaseAngles = phaseAngles;
|
||||||
|
|
||||||
this.calculate = function(twoPiFT) {
|
this.calculate = function(twoPiFT) {
|
||||||
|
|
||||||
var harmonics = 0;
|
var harmonics = 0;
|
||||||
var numHarmonics = magnitudes.length;
|
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]);
|
harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]);
|
||||||
}
|
}
|
||||||
return harmonics;
|
return harmonics;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// the main filter object literal
|
||||||
// the main filter object
|
|
||||||
filter = (function() {
|
filter = (function() {
|
||||||
|
|
||||||
|
const HALF_CYCLE = 180;
|
||||||
|
|
||||||
|
// Bezier private variables
|
||||||
|
var _C1 = {x:0, y:0};
|
||||||
|
var _C4 = {x:1, y:1};
|
||||||
|
|
||||||
// Bezier private functions
|
// Bezier private functions
|
||||||
function _B1(t) { return t * t * t };
|
function _B1(t) { return t * t * t };
|
||||||
function _B2(t) { return 3 * t * t * (1 - t) };
|
function _B2(t) { return 3 * t * t * (1 - t) };
|
||||||
|
@ -209,63 +148,52 @@ filter = (function() {
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
degToRad: function(degrees) {
|
degToRad: function(degrees) {
|
||||||
|
var convertedValue = degrees * Math.PI / HALF_CYCLE;
|
||||||
var convertedValue = degrees * Math.PI / 180;
|
|
||||||
return convertedValue;
|
return convertedValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
radToDeg: function(radians) {
|
radToDeg: function(radians) {
|
||||||
|
var convertedValue = radians * HALF_CYCLE / Math.PI;
|
||||||
var convertedValue = radians * 180 / Math.PI;
|
|
||||||
return convertedValue;
|
return convertedValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
// these filters need instantiating, as they hold arrays of previous values
|
// 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);
|
var newAveragingFilter = new AveragingFilter(length);
|
||||||
return newAveragingFilter;
|
return newAveragingFilter;
|
||||||
},
|
},
|
||||||
|
|
||||||
createButterworthFilter1: function() {
|
// provides LP filtering with improved frequency / phase response
|
||||||
|
createButterworthFilter: function() {
|
||||||
var newButterworthFilter = new ButterworthFilter1();
|
var newButterworthFilter = new ButterworthFilter();
|
||||||
return newButterworthFilter;
|
|
||||||
},
|
|
||||||
|
|
||||||
createButterworthFilter2: function(cutoff) {
|
|
||||||
|
|
||||||
var newButterworthFilter = new ButterworthFilter2(cutoff);
|
|
||||||
return newButterworthFilter;
|
return newButterworthFilter;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// generates sawtooth, triangle or square waves using harmonics
|
||||||
createWaveSynth: function(waveShape, numHarmonics, smoothing) {
|
createWaveSynth: function(waveShape, numHarmonics, smoothing) {
|
||||||
|
|
||||||
var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing);
|
var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing);
|
||||||
return newWaveSynth;
|
return newWaveSynth;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// generates arbitrary waveforms using pre-calculated harmonics
|
||||||
createHarmonicsFilter: function(magnitudes, phaseAngles) {
|
createHarmonicsFilter: function(magnitudes, phaseAngles) {
|
||||||
|
|
||||||
var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles);
|
var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles);
|
||||||
return newHarmonicsFilter;
|
return newHarmonicsFilter;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
// the following filters do not need separate instances, as they hold no previous values
|
// 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/
|
// based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/
|
||||||
var pos = {x: 0, y: 0};
|
input = 1 - input;
|
||||||
pos.x = C1.x * _B1(percent) + C2.x * _B2(percent) + C3.x * _B3(percent) + C4.x * _B4(percent);
|
return _C1.y * _B1(input) + C2.y * _B2(input) + C3.y * _B3(input) + _C4.y * _B4(input);
|
||||||
pos.y = C1.y * _B1(percent) + C2.y * _B2(percent) + C3.y * _B3(percent) + C4.y * _B4(percent);
|
|
||||||
return pos;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 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) {
|
clipTrough: function(inputValue, peak, strength) {
|
||||||
|
|
||||||
var outputValue = inputValue * strength;
|
var outputValue = inputValue * strength;
|
||||||
if (outputValue < -peak) {
|
if (outputValue < -peak) {
|
||||||
outputValue = -peak;
|
outputValue = -peak;
|
||||||
|
@ -273,5 +201,4 @@ filter = (function() {
|
||||||
return outputValue;
|
return outputValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
})();
|
})();
|
|
@ -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)
|
|
||||||
|
|
||||||
})();
|
|
97
examples/libraries/walkSettings.js
Normal file
97
examples/libraries/walkSettings.js
Normal 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();
|
1064
examples/walk.js
1064
examples/walk.js
File diff suppressed because it is too large
Load diff
|
@ -891,8 +891,11 @@ void Application::paintGL() {
|
||||||
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
|
||||||
Menu::getInstance()->setIsOptionChecked("First Person", _myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
Application::getInstance()->cameraMenuChanged();
|
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) {
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||||
// Always use the default eye position, not the actual head eye position.
|
// Always use the default eye position, not the actual head eye position.
|
||||||
|
@ -1384,11 +1387,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
if (isShifted) {
|
if (isShifted) {
|
||||||
Menu::getInstance()->triggerOption(MenuOption::Mirror);
|
Menu::getInstance()->triggerOption(MenuOption::Mirror);
|
||||||
} else {
|
} 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;
|
break;
|
||||||
case Qt::Key_P:
|
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;
|
break;
|
||||||
case Qt::Key_Slash:
|
case Qt::Key_Slash:
|
||||||
Menu::getInstance()->triggerOption(MenuOption::Stats);
|
Menu::getInstance()->triggerOption(MenuOption::Stats);
|
||||||
|
@ -2351,13 +2360,17 @@ void Application::cameraMenuChanged() {
|
||||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||||
_myAvatar->setBoomLength(MyAvatar::ZOOM_MIN);
|
_myAvatar->setBoomLength(MyAvatar::ZOOM_MIN);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (Menu::getInstance()->isOptionChecked(MenuOption::ThirdPerson)) {
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
||||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||||
if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) {
|
if (_myAvatar->getBoomLength() == MyAvatar::ZOOM_MIN) {
|
||||||
_myAvatar->setBoomLength(MyAvatar::ZOOM_DEFAULT);
|
_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
|
// Transfer the user inputs to the driveKeys
|
||||||
_myAvatar->clearDriveKeys();
|
_myAvatar->clearDriveKeys();
|
||||||
if (!_controllerScriptingInterface.areActionsCaptured()) {
|
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
||||||
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
|
if (!_controllerScriptingInterface.areActionsCaptured()) {
|
||||||
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
|
_myAvatar->setDriveKeys(FWD, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_FORWARD));
|
||||||
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
|
_myAvatar->setDriveKeys(BACK, _userInputMapper.getActionState(UserInputMapper::LONGITUDINAL_BACKWARD));
|
||||||
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
|
_myAvatar->setDriveKeys(UP, _userInputMapper.getActionState(UserInputMapper::VERTICAL_UP));
|
||||||
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
|
_myAvatar->setDriveKeys(DOWN, _userInputMapper.getActionState(UserInputMapper::VERTICAL_DOWN));
|
||||||
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
|
_myAvatar->setDriveKeys(LEFT, _userInputMapper.getActionState(UserInputMapper::LATERAL_LEFT));
|
||||||
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
|
_myAvatar->setDriveKeys(RIGHT, _userInputMapper.getActionState(UserInputMapper::LATERAL_RIGHT));
|
||||||
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
|
_myAvatar->setDriveKeys(ROT_UP, _userInputMapper.getActionState(UserInputMapper::PITCH_UP));
|
||||||
_myAvatar->setDriveKeys(ROT_LEFT, _userInputMapper.getActionState(UserInputMapper::YAW_LEFT));
|
_myAvatar->setDriveKeys(ROT_DOWN, _userInputMapper.getActionState(UserInputMapper::PITCH_DOWN));
|
||||||
_myAvatar->setDriveKeys(ROT_RIGHT, _userInputMapper.getActionState(UserInputMapper::YAW_RIGHT));
|
_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...
|
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||||
|
|
||||||
|
@ -2481,24 +2496,45 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
_entitySimulation.lock();
|
_entitySimulation.lock();
|
||||||
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete());
|
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToDelete());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
|
_entitySimulation.lock();
|
||||||
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
|
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
|
_entitySimulation.lock();
|
||||||
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
|
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
|
||||||
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entitySimulation.lock();
|
||||||
_entitySimulation.applyActionChanges();
|
_entitySimulation.applyActionChanges();
|
||||||
_entitySimulation.unlock();
|
_entitySimulation.unlock();
|
||||||
|
|
||||||
|
|
||||||
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
|
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
|
||||||
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
|
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
|
||||||
_physicsEngine.addObjects(avatarManager->getObjectsToAdd());
|
_physicsEngine.addObjects(avatarManager->getObjectsToAdd());
|
||||||
_physicsEngine.changeObjects(avatarManager->getObjectsToChange());
|
_physicsEngine.changeObjects(avatarManager->getObjectsToChange());
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
_physicsEngine.stepSimulation();
|
_physicsEngine.stepSimulation();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
if (_physicsEngine.hasOutgoingChanges()) {
|
if (_physicsEngine.hasOutgoingChanges()) {
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
_entitySimulation.lock();
|
_entitySimulation.lock();
|
||||||
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
|
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
|
||||||
_entitySimulation.unlock();
|
_entitySimulation.unlock();
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
|
_entities.getTree()->lockForWrite();
|
||||||
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
|
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
|
||||||
|
_entities.getTree()->unlock();
|
||||||
|
|
||||||
auto collisionEvents = _physicsEngine.getCollisionEvents();
|
auto collisionEvents = _physicsEngine.getCollisionEvents();
|
||||||
avatarManager->handleCollisionEvents(collisionEvents);
|
avatarManager->handleCollisionEvents(collisionEvents);
|
||||||
|
|
||||||
|
|
|
@ -444,6 +444,8 @@ public slots:
|
||||||
void notifyPacketVersionMismatch();
|
void notifyPacketVersionMismatch();
|
||||||
|
|
||||||
void domainConnectionDenied(const QString& reason);
|
void domainConnectionDenied(const QString& reason);
|
||||||
|
|
||||||
|
void cameraMenuChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void clearDomainOctreeDetails();
|
void clearDomainOctreeDetails();
|
||||||
|
@ -460,7 +462,7 @@ private slots:
|
||||||
void setFullscreen(bool fullscreen);
|
void setFullscreen(bool fullscreen);
|
||||||
void setEnable3DTVMode(bool enable3DTVMode);
|
void setEnable3DTVMode(bool enable3DTVMode);
|
||||||
void setEnableVRMode(bool enableVRMode);
|
void setEnableVRMode(bool enableVRMode);
|
||||||
void cameraMenuChanged();
|
|
||||||
void rotationModeChanged();
|
void rotationModeChanged();
|
||||||
|
|
||||||
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
|
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
|
||||||
|
|
|
@ -87,24 +87,26 @@ PickRay Camera::computePickRay(float x, float y) {
|
||||||
|
|
||||||
void Camera::setModeString(const QString& mode) {
|
void Camera::setModeString(const QString& mode) {
|
||||||
CameraMode targetMode = stringToMode(mode);
|
CameraMode targetMode = stringToMode(mode);
|
||||||
|
|
||||||
switch (targetMode) {
|
switch (targetMode) {
|
||||||
|
case CAMERA_MODE_FIRST_PERSON:
|
||||||
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
|
||||||
|
break;
|
||||||
case CAMERA_MODE_THIRD_PERSON:
|
case CAMERA_MODE_THIRD_PERSON:
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);
|
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true);
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
|
|
||||||
break;
|
break;
|
||||||
case CAMERA_MODE_MIRROR:
|
case CAMERA_MODE_MIRROR:
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true);
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true);
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
|
|
||||||
break;
|
break;
|
||||||
case CAMERA_MODE_INDEPENDENT:
|
case CAMERA_MODE_INDEPENDENT:
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, false);
|
Menu::getInstance()->setIsOptionChecked(MenuOption::IndependentMode, true);
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qApp->cameraMenuChanged();
|
||||||
|
|
||||||
if (_mode != targetMode) {
|
if (_mode != targetMode) {
|
||||||
setMode(targetMode);
|
setMode(targetMode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,9 +268,22 @@ Menu::Menu() {
|
||||||
qApp,
|
qApp,
|
||||||
SLOT(setFullscreen(bool)));
|
SLOT(setFullscreen(bool)));
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
|
MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode");
|
||||||
0, // QML Qt::Key_P,
|
QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu);
|
||||||
true, qApp, SLOT(cameraMenuChanged()));
|
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,
|
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
|
||||||
0, //QML Qt::SHIFT | Qt::Key_H,
|
0, //QML Qt::SHIFT | Qt::Key_H,
|
||||||
true);
|
true);
|
||||||
|
|
|
@ -158,6 +158,7 @@ namespace MenuOption {
|
||||||
const QString CascadedShadows = "Cascaded";
|
const QString CascadedShadows = "Cascaded";
|
||||||
const QString CachesSize = "RAM Caches Size";
|
const QString CachesSize = "RAM Caches Size";
|
||||||
const QString CalibrateCamera = "Calibrate Camera";
|
const QString CalibrateCamera = "Calibrate Camera";
|
||||||
|
const QString CenterPlayerInView = "Center Player In View";
|
||||||
const QString Chat = "Chat...";
|
const QString Chat = "Chat...";
|
||||||
const QString Collisions = "Collisions";
|
const QString Collisions = "Collisions";
|
||||||
const QString Console = "Console...";
|
const QString Console = "Console...";
|
||||||
|
@ -199,11 +200,10 @@ namespace MenuOption {
|
||||||
const QString FrameTimer = "Show Timer";
|
const QString FrameTimer = "Show Timer";
|
||||||
const QString Fullscreen = "Fullscreen";
|
const QString Fullscreen = "Fullscreen";
|
||||||
const QString FullscreenMirror = "Fullscreen Mirror";
|
const QString FullscreenMirror = "Fullscreen Mirror";
|
||||||
const QString CenterPlayerInView = "Center Player In View";
|
|
||||||
const QString GlowWhenSpeaking = "Glow When Speaking";
|
const QString GlowWhenSpeaking = "Glow When Speaking";
|
||||||
const QString NamesAboveHeads = "Names Above Heads";
|
|
||||||
const QString HMDTools = "HMD Tools";
|
const QString HMDTools = "HMD Tools";
|
||||||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||||
|
const QString IndependentMode = "Independent Mode";
|
||||||
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
|
const QString KeyboardMotorControl = "Enable Keyboard Motor Control";
|
||||||
const QString LeapMotionOnHMD = "Leap Motion on HMD";
|
const QString LeapMotionOnHMD = "Leap Motion on HMD";
|
||||||
const QString LoadScript = "Open and Run Script File...";
|
const QString LoadScript = "Open and Run Script File...";
|
||||||
|
@ -217,6 +217,7 @@ namespace MenuOption {
|
||||||
const QString MuteAudio = "Mute Microphone";
|
const QString MuteAudio = "Mute Microphone";
|
||||||
const QString MuteEnvironment = "Mute Environment";
|
const QString MuteEnvironment = "Mute Environment";
|
||||||
const QString MuteFaceTracking = "Mute Face Tracking";
|
const QString MuteFaceTracking = "Mute Face Tracking";
|
||||||
|
const QString NamesAboveHeads = "Names Above Heads";
|
||||||
const QString NoFaceTracking = "None";
|
const QString NoFaceTracking = "None";
|
||||||
const QString OctreeStats = "Entity Statistics";
|
const QString OctreeStats = "Entity Statistics";
|
||||||
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
const QString OnlyDisplayTopTen = "Only Display Top Ten";
|
||||||
|
@ -277,6 +278,7 @@ namespace MenuOption {
|
||||||
const QString StopAllScripts = "Stop All Scripts";
|
const QString StopAllScripts = "Stop All Scripts";
|
||||||
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
|
const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
|
||||||
const QString TestPing = "Test Ping";
|
const QString TestPing = "Test Ping";
|
||||||
|
const QString ThirdPerson = "Third Person";
|
||||||
const QString ToolWindow = "Tool Window";
|
const QString ToolWindow = "Tool Window";
|
||||||
const QString TransmitterDrive = "Transmitter Drive";
|
const QString TransmitterDrive = "Transmitter Drive";
|
||||||
const QString TurnWithHead = "Turn using Head";
|
const QString TurnWithHead = "Turn using Head";
|
||||||
|
|
|
@ -19,10 +19,42 @@
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
|
static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
|
||||||
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
|
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
bool EntityMotionState::entityTreeIsLocked() const {
|
||||||
|
EntityTreeElement* element = _entity ? _entity->getElement() : nullptr;
|
||||||
|
EntityTree* tree = element ? element->getTree() : nullptr;
|
||||||
|
if (tree) {
|
||||||
|
bool readSuccess = tree->tryLockForRead();
|
||||||
|
if (readSuccess) {
|
||||||
|
tree->unlock();
|
||||||
|
}
|
||||||
|
bool writeSuccess = tree->tryLockForWrite();
|
||||||
|
if (writeSuccess) {
|
||||||
|
tree->unlock();
|
||||||
|
}
|
||||||
|
if (readSuccess && writeSuccess) {
|
||||||
|
return false; // if we can take either kind of lock, there was no tree lock.
|
||||||
|
}
|
||||||
|
return true; // either read or write failed, so there is some lock in place.
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
bool entityTreeIsLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) :
|
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) :
|
||||||
ObjectMotionState(shape),
|
ObjectMotionState(shape),
|
||||||
_entity(entity),
|
_entity(entity),
|
||||||
|
@ -42,6 +74,7 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer
|
||||||
{
|
{
|
||||||
_type = MOTIONSTATE_TYPE_ENTITY;
|
_type = MOTIONSTATE_TYPE_ENTITY;
|
||||||
assert(_entity != nullptr);
|
assert(_entity != nullptr);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
setMass(_entity->computeMass());
|
setMass(_entity->computeMass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +84,7 @@ EntityMotionState::~EntityMotionState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::updateServerPhysicsVariables() {
|
void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
_serverPosition = _entity->getPosition();
|
_serverPosition = _entity->getPosition();
|
||||||
_serverRotation = _entity->getRotation();
|
_serverRotation = _entity->getRotation();
|
||||||
_serverVelocity = _entity->getVelocity();
|
_serverVelocity = _entity->getVelocity();
|
||||||
|
@ -60,6 +94,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
updateServerPhysicsVariables();
|
updateServerPhysicsVariables();
|
||||||
ObjectMotionState::handleEasyChanges(flags);
|
ObjectMotionState::handleEasyChanges(flags);
|
||||||
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
||||||
|
@ -101,6 +136,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return MOTION_TYPE_STATIC;
|
return MOTION_TYPE_STATIC;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
if (_entity->getCollisionsWillMove()) {
|
if (_entity->getCollisionsWillMove()) {
|
||||||
return MOTION_TYPE_DYNAMIC;
|
return MOTION_TYPE_DYNAMIC;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +144,7 @@ MotionType EntityMotionState::computeObjectMotionType() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::isMoving() const {
|
bool EntityMotionState::isMoving() const {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity && _entity->isMoving();
|
return _entity && _entity->isMoving();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +157,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
if (_motionType == MOTION_TYPE_KINEMATIC) {
|
if (_motionType == MOTION_TYPE_KINEMATIC) {
|
||||||
// This is physical kinematic motion which steps strictly by the subframe count
|
// This is physical kinematic motion which steps strictly by the subframe count
|
||||||
// of the physics simulation.
|
// of the physics simulation.
|
||||||
|
@ -140,6 +178,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
if (!_entity) {
|
if (!_entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
measureBodyAcceleration();
|
measureBodyAcceleration();
|
||||||
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
||||||
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
||||||
|
@ -164,9 +203,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID();
|
qCDebug(physics) << "EntityMotionState::setWorldTransform()... changed entity:" << _entity->getEntityItemID();
|
||||||
qCDebug(physics) << " last edited:" << _entity->getLastEdited() << formatUsecTime(now - _entity->getLastEdited()) << "ago";
|
qCDebug(physics) << " last edited:" << _entity->getLastEdited()
|
||||||
qCDebug(physics) << " last simulated:" << _entity->getLastSimulated() << formatUsecTime(now - _entity->getLastSimulated()) << "ago";
|
<< formatUsecTime(now - _entity->getLastEdited()) << "ago";
|
||||||
qCDebug(physics) << " last updated:" << _entity->getLastUpdated() << formatUsecTime(now - _entity->getLastUpdated()) << "ago";
|
qCDebug(physics) << " last simulated:" << _entity->getLastSimulated()
|
||||||
|
<< formatUsecTime(now - _entity->getLastSimulated()) << "ago";
|
||||||
|
qCDebug(physics) << " last updated:" << _entity->getLastUpdated()
|
||||||
|
<< formatUsecTime(now - _entity->getLastUpdated()) << "ago";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,16 +216,18 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
btCollisionShape* EntityMotionState::computeNewShape() {
|
btCollisionShape* EntityMotionState::computeNewShape() {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
_entity->computeShapeInfo(shapeInfo);
|
_entity->computeShapeInfo(shapeInfo);
|
||||||
return getShapeManager()->getShape(shapeInfo);
|
return getShapeManager()->getShape(shapeInfo);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
|
bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
|
||||||
if (!_body || !_entity) {
|
if (!_body || !_entity) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _candidateForOwnership || sessionID == _entity->getSimulatorID();
|
return _candidateForOwnership || sessionID == _entity->getSimulatorID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +244,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
_sentActive = false;
|
_sentActive = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
glm::vec3 wasPosition = _serverPosition;
|
glm::vec3 wasPosition = _serverPosition;
|
||||||
glm::quat wasRotation = _serverRotation;
|
glm::quat wasRotation = _serverRotation;
|
||||||
|
@ -213,7 +257,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
const float INACTIVE_UPDATE_PERIOD = 0.5f;
|
const float INACTIVE_UPDATE_PERIOD = 0.5f;
|
||||||
if (!_sentActive) {
|
if (!_sentActive) {
|
||||||
// we resend the inactive update every INACTIVE_UPDATE_PERIOD
|
// we resend the inactive update every INACTIVE_UPDATE_PERIOD
|
||||||
// until it is removed from the outgoing updates
|
// until it is removed from the outgoing updates
|
||||||
// (which happens when we don't own the simulation and it isn't touching our simulation)
|
// (which happens when we don't own the simulation and it isn't touching our simulation)
|
||||||
return (dt > INACTIVE_UPDATE_PERIOD);
|
return (dt > INACTIVE_UPDATE_PERIOD);
|
||||||
}
|
}
|
||||||
|
@ -231,10 +275,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
_serverPosition += dt * _serverVelocity;
|
_serverPosition += dt * _serverVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else we measure the error between current and extrapolated transform (according to expected behavior
|
// Else we measure the error between current and extrapolated transform (according to expected behavior
|
||||||
// of remote EntitySimulation) and return true if the error is significant.
|
// of remote EntitySimulation) and return true if the error is significant.
|
||||||
|
|
||||||
// NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame
|
// NOTE: math is done in the simulation-frame, which is NOT necessarily the same as the world-frame
|
||||||
// due to _worldOffset.
|
// due to _worldOffset.
|
||||||
// TODO: compensate for _worldOffset offset here
|
// TODO: compensate for _worldOffset offset here
|
||||||
|
|
||||||
|
@ -242,7 +286,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
|
|
||||||
btTransform worldTrans = _body->getWorldTransform();
|
btTransform worldTrans = _body->getWorldTransform();
|
||||||
glm::vec3 position = bulletToGLM(worldTrans.getOrigin());
|
glm::vec3 position = bulletToGLM(worldTrans.getOrigin());
|
||||||
|
|
||||||
float dx2 = glm::distance2(position, _serverPosition);
|
float dx2 = glm::distance2(position, _serverPosition);
|
||||||
|
|
||||||
const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters
|
const float MAX_POSITION_ERROR_SQUARED = 0.000004f; // Sqrt() - corresponds to 2 millimeters
|
||||||
|
@ -258,13 +302,13 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glm::length2(_serverAngularVelocity) > 0.0f) {
|
if (glm::length2(_serverAngularVelocity) > 0.0f) {
|
||||||
// compute rotation error
|
// compute rotation error
|
||||||
float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
|
float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
|
||||||
_serverAngularVelocity *= attenuation;
|
_serverAngularVelocity *= attenuation;
|
||||||
|
|
||||||
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
|
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
|
||||||
// we must integrate with the same algorithm and timestep in order achieve similar results.
|
// we must integrate with the same algorithm and timestep in order achieve similar results.
|
||||||
for (int i = 0; i < numSteps; ++i) {
|
for (int i = 0; i < numSteps; ++i) {
|
||||||
_serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
|
_serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
|
||||||
|
@ -276,7 +320,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
#ifdef WANT_DEBUG
|
#ifdef WANT_DEBUG
|
||||||
if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) {
|
if ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) {
|
||||||
qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ....";
|
qCDebug(physics) << ".... ((fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT)) ....";
|
||||||
|
|
||||||
qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity;
|
qCDebug(physics) << "wasAngularVelocity:" << wasAngularVelocity;
|
||||||
qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity;
|
qCDebug(physics) << "_serverAngularVelocity:" << _serverAngularVelocity;
|
||||||
|
|
||||||
|
@ -293,10 +337,11 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID) {
|
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& sessionID) {
|
||||||
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
|
// NOTE: we expect _entity and _body to be valid in this context, since shouldSendUpdate() is only called
|
||||||
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
// after doesNotNeedToSendUpdate() returns false and that call should return 'true' if _entity or _body are NULL.
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
assert(_body);
|
assert(_body);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
if (!remoteSimulationOutOfSync(simulationStep)) {
|
if (!remoteSimulationOutOfSync(simulationStep)) {
|
||||||
_candidateForOwnership = false;
|
_candidateForOwnership = false;
|
||||||
|
@ -326,6 +371,7 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
|
||||||
|
|
||||||
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const QUuid& sessionID, uint32_t step) {
|
||||||
assert(_entity);
|
assert(_entity);
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
bool active = _body->isActive();
|
bool active = _body->isActive();
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
@ -435,17 +481,18 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
||||||
_lastStep = step;
|
_lastStep = step;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
uint32_t dirtyFlags = 0;
|
uint32_t dirtyFlags = 0;
|
||||||
if (_body && _entity) {
|
if (_body && _entity) {
|
||||||
dirtyFlags = _entity->getDirtyFlags();
|
dirtyFlags = _entity->getDirtyFlags();
|
||||||
_entity->clearDirtyFlags();
|
_entity->clearDirtyFlags();
|
||||||
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
|
// we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings
|
||||||
int bodyFlags = _body->getCollisionFlags();
|
int bodyFlags = _body->getCollisionFlags();
|
||||||
bool isMoving = _entity->isMoving();
|
bool isMoving = _entity->isMoving();
|
||||||
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
|
if (((bodyFlags & btCollisionObject::CF_STATIC_OBJECT) && isMoving) ||
|
||||||
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
|
(bodyFlags & btCollisionObject::CF_KINEMATIC_OBJECT && !isMoving)) {
|
||||||
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dirtyFlags;
|
return dirtyFlags;
|
||||||
|
@ -455,6 +502,7 @@ uint32_t EntityMotionState::getAndClearIncomingDirtyFlags() {
|
||||||
// virtual
|
// virtual
|
||||||
QUuid EntityMotionState::getSimulatorID() const {
|
QUuid EntityMotionState::getSimulatorID() const {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity->getSimulatorID();
|
return _entity->getSimulatorID();
|
||||||
}
|
}
|
||||||
return QUuid();
|
return QUuid();
|
||||||
|
@ -469,12 +517,12 @@ void EntityMotionState::bump() {
|
||||||
void EntityMotionState::resetMeasuredBodyAcceleration() {
|
void EntityMotionState::resetMeasuredBodyAcceleration() {
|
||||||
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
|
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
|
||||||
if (_body) {
|
if (_body) {
|
||||||
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
|
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
|
||||||
} else {
|
} else {
|
||||||
_lastVelocity = glm::vec3(0.0f);
|
_lastVelocity = glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
_measuredAcceleration = glm::vec3(0.0f);
|
_measuredAcceleration = glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::measureBodyAcceleration() {
|
void EntityMotionState::measureBodyAcceleration() {
|
||||||
// try to manually measure the true acceleration of the object
|
// try to manually measure the true acceleration of the object
|
||||||
|
@ -504,7 +552,7 @@ glm::vec3 EntityMotionState::getObjectLinearVelocityChange() const {
|
||||||
return _measuredAcceleration * _measuredDeltaTime;
|
return _measuredAcceleration * _measuredDeltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void EntityMotionState::setMotionType(MotionType motionType) {
|
void EntityMotionState::setMotionType(MotionType motionType) {
|
||||||
ObjectMotionState::setMotionType(motionType);
|
ObjectMotionState::setMotionType(motionType);
|
||||||
resetMeasuredBodyAcceleration();
|
resetMeasuredBodyAcceleration();
|
||||||
|
@ -514,12 +562,13 @@ void EntityMotionState::setMotionType(MotionType motionType) {
|
||||||
// virtual
|
// virtual
|
||||||
QString EntityMotionState::getName() {
|
QString EntityMotionState::getName() {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
|
assert(entityTreeIsLocked());
|
||||||
return _entity->getName();
|
return _entity->getName();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
int16_t EntityMotionState::computeCollisionGroup() {
|
int16_t EntityMotionState::computeCollisionGroup() {
|
||||||
switch (computeObjectMotionType()){
|
switch (computeObjectMotionType()){
|
||||||
case MOTION_TYPE_STATIC:
|
case MOTION_TYPE_STATIC:
|
||||||
|
|
|
@ -83,6 +83,10 @@ public:
|
||||||
friend class PhysicalEntitySimulation;
|
friend class PhysicalEntitySimulation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#ifdef WANT_DEBUG_ENTITY_TREE_LOCKS
|
||||||
|
bool entityTreeIsLocked() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual btCollisionShape* computeNewShape();
|
virtual btCollisionShape* computeNewShape();
|
||||||
virtual void clearObjectBackPointer();
|
virtual void clearObjectBackPointer();
|
||||||
virtual void setMotionType(MotionType motionType);
|
virtual void setMotionType(MotionType motionType);
|
||||||
|
|
Loading…
Reference in a new issue