Merge pull request #6127 from AndrewMeadows/gitattributes

gitattributes take 2
This commit is contained in:
Brad Davis 2015-10-20 15:48:44 -07:00
commit f54fe50c79
15 changed files with 3021 additions and 2994 deletions

27
.gitattributes vendored Normal file
View file

@ -0,0 +1,27 @@
*.cfg text
*.cpp text
*.css text
*.c text
*.frag text
*.fst text
*.h text
*.html text
*.ini text
*.json text
*.js text
*.qml text
*.slf text
*.slh text
*.slv text
*.ts text
*.txt text
*.vert text
# Denote all files that are truly binary and should not be modified.
*.dds binary
*.fbx binary
*.jpg binary
*.png binary
*.svg binary
*.ttf binary
*.wav binary

View file

@ -1,26 +1,26 @@
/** /**
* Copyright (c) 2010 Maxim Vasiliev * Copyright (c) 2010 Maxim Vasiliev
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. * THE SOFTWARE.
* *
* @author Maxim Vasiliev * @author Maxim Vasiliev
* Date: 09.09.2010 * Date: 09.09.2010
* Time: 19:02:33 * Time: 19:02:33
*/ */
(function(e,t){if(typeof define==="function"&&define.amd){define(t)}else{e.form2js=t()}})(this,function(){"use strict";function e(e,r,i,s,o,u){u=u?true:false;if(typeof i=="undefined"||i==null)i=true;if(typeof r=="undefined"||r==null)r=".";if(arguments.length<5)o=false;e=typeof e=="string"?document.getElementById(e):e;var a=[],f,l=0;if(e.constructor==Array||typeof NodeList!="undefined"&&e.constructor==NodeList){while(f=e[l++]){a=a.concat(n(f,s,o,u))}}else{a=n(e,s,o,u)}return t(a,i,r)}function t(e,t,n){var r={},i={},s,o,u,a,f,l,c,h,p,d,v,m,g;for(s=0;s<e.length;s++){f=e[s].value;if(t&&(f===""||f===null))continue;m=e[s].name;g=m.split(n);l=[];c=r;h="";for(o=0;o<g.length;o++){v=g[o].split("][");if(v.length>1){for(u=0;u<v.length;u++){if(u==0){v[u]=v[u]+"]"}else if(u==v.length-1){v[u]="["+v[u]}else{v[u]="["+v[u]+"]"}d=v[u].match(/([a-z_]+)?\[([a-z_][a-z0-9_]+?)\]/i);if(d){for(a=1;a<d.length;a++){if(d[a])l.push(d[a])}}else{l.push(v[u])}}}else l=l.concat(v)}for(o=0;o<l.length;o++){v=l[o];if(v.indexOf("[]")>-1&&o==l.length-1){p=v.substr(0,v.indexOf("["));h+=p;if(!c[p])c[p]=[];c[p].push(f)}else if(v.indexOf("[")>-1){p=v.substr(0,v.indexOf("["));d=v.replace(/(^([a-z_]+)?\[)|(\]$)/gi,"");h+="_"+p+"_"+d;if(!i[h])i[h]={};if(p!=""&&!c[p])c[p]=[];if(o==l.length-1){if(p==""){c.push(f);i[h][d]=c[c.length-1]}else{c[p].push(f);i[h][d]=c[p][c[p].length-1]}}else{if(!i[h][d]){if(/^[0-9a-z_]+\[?/i.test(l[o+1]))c[p].push({});else c[p].push([]);i[h][d]=c[p][c[p].length-1]}}c=i[h][d]}else{h+=v;if(o<l.length-1){if(!c[v])c[v]={};c=c[v]}else{c[v]=f}}}}return r}function n(e,t,n,s){var o=i(e,t,n,s);return o.length>0?o:r(e,t,n,s)}function r(e,t,n,r){var s=[],o=e.firstChild;while(o){s=s.concat(i(o,t,n,r));o=o.nextSibling}return s}function i(e,t,n,i){if(e.disabled&&!i)return[];var u,a,f,l=s(e,n);u=t&&t(e);if(u&&u.name){f=[u]}else if(l!=""&&e.nodeName.match(/INPUT|TEXTAREA/i)){a=o(e,i);if(null===a){f=[]}else{f=[{name:l,value:a}]}}else if(l!=""&&e.nodeName.match(/SELECT/i)){a=o(e,i);f=[{name:l.replace(/\[\]$/,""),value:a}]}else{f=r(e,t,n,i)}return f}function s(e,t){if(e.name&&e.name!="")return e.name;else if(t&&e.id&&e.id!="")return e.id;else return""}function o(e,t){if(e.disabled&&!t)return null;switch(e.nodeName){case"INPUT":case"TEXTAREA":switch(e.type.toLowerCase()){case"radio":if(e.checked&&e.value==="false")return false;case"checkbox":if(e.checked&&e.value==="true")return true;if(!e.checked&&e.value==="true")return false;if(e.checked)return e.value;break;case"button":case"reset":case"submit":case"image":return"";break;default:return e.value;break}break;case"SELECT":return u(e);break;default:break}return null}function u(e){var t=e.multiple,n=[],r,i,s;if(!t)return e.value;for(r=e.getElementsByTagName("option"),i=0,s=r.length;i<s;i++){if(r[i].selected)n.push(r[i].value)}return n}return e}) (function(e,t){if(typeof define==="function"&&define.amd){define(t)}else{e.form2js=t()}})(this,function(){"use strict";function e(e,r,i,s,o,u){u=u?true:false;if(typeof i=="undefined"||i==null)i=true;if(typeof r=="undefined"||r==null)r=".";if(arguments.length<5)o=false;e=typeof e=="string"?document.getElementById(e):e;var a=[],f,l=0;if(e.constructor==Array||typeof NodeList!="undefined"&&e.constructor==NodeList){while(f=e[l++]){a=a.concat(n(f,s,o,u))}}else{a=n(e,s,o,u)}return t(a,i,r)}function t(e,t,n){var r={},i={},s,o,u,a,f,l,c,h,p,d,v,m,g;for(s=0;s<e.length;s++){f=e[s].value;if(t&&(f===""||f===null))continue;m=e[s].name;g=m.split(n);l=[];c=r;h="";for(o=0;o<g.length;o++){v=g[o].split("][");if(v.length>1){for(u=0;u<v.length;u++){if(u==0){v[u]=v[u]+"]"}else if(u==v.length-1){v[u]="["+v[u]}else{v[u]="["+v[u]+"]"}d=v[u].match(/([a-z_]+)?\[([a-z_][a-z0-9_]+?)\]/i);if(d){for(a=1;a<d.length;a++){if(d[a])l.push(d[a])}}else{l.push(v[u])}}}else l=l.concat(v)}for(o=0;o<l.length;o++){v=l[o];if(v.indexOf("[]")>-1&&o==l.length-1){p=v.substr(0,v.indexOf("["));h+=p;if(!c[p])c[p]=[];c[p].push(f)}else if(v.indexOf("[")>-1){p=v.substr(0,v.indexOf("["));d=v.replace(/(^([a-z_]+)?\[)|(\]$)/gi,"");h+="_"+p+"_"+d;if(!i[h])i[h]={};if(p!=""&&!c[p])c[p]=[];if(o==l.length-1){if(p==""){c.push(f);i[h][d]=c[c.length-1]}else{c[p].push(f);i[h][d]=c[p][c[p].length-1]}}else{if(!i[h][d]){if(/^[0-9a-z_]+\[?/i.test(l[o+1]))c[p].push({});else c[p].push([]);i[h][d]=c[p][c[p].length-1]}}c=i[h][d]}else{h+=v;if(o<l.length-1){if(!c[v])c[v]={};c=c[v]}else{c[v]=f}}}}return r}function n(e,t,n,s){var o=i(e,t,n,s);return o.length>0?o:r(e,t,n,s)}function r(e,t,n,r){var s=[],o=e.firstChild;while(o){s=s.concat(i(o,t,n,r));o=o.nextSibling}return s}function i(e,t,n,i){if(e.disabled&&!i)return[];var u,a,f,l=s(e,n);u=t&&t(e);if(u&&u.name){f=[u]}else if(l!=""&&e.nodeName.match(/INPUT|TEXTAREA/i)){a=o(e,i);if(null===a){f=[]}else{f=[{name:l,value:a}]}}else if(l!=""&&e.nodeName.match(/SELECT/i)){a=o(e,i);f=[{name:l.replace(/\[\]$/,""),value:a}]}else{f=r(e,t,n,i)}return f}function s(e,t){if(e.name&&e.name!="")return e.name;else if(t&&e.id&&e.id!="")return e.id;else return""}function o(e,t){if(e.disabled&&!t)return null;switch(e.nodeName){case"INPUT":case"TEXTAREA":switch(e.type.toLowerCase()){case"radio":if(e.checked&&e.value==="false")return false;case"checkbox":if(e.checked&&e.value==="true")return true;if(!e.checked&&e.value==="true")return false;if(e.checked)return e.value;break;case"button":case"reset":case"submit":case"image":return"";break;default:return e.value;break}break;case"SELECT":return u(e);break;default:break}return null}function u(e){var t=e.multiple,n=[],r,i,s;if(!t)return e.value;for(r=e.getElementsByTagName("option"),i=0,s=r.length;i<s;i++){if(r[i].selected)n.push(r[i].value)}return n}return e})

View file

@ -244,4 +244,4 @@ B(this,"mouseOut");!c||a.stickyTracking||c.shared&&!this.noSharedTooltip||c.hide
f=(c.visible=a=c.userOptions.visible=a===u?!h:a)?"show":"hide";t(["group","dataLabelsGroup","markerGroup","tracker"],function(a){if(c[a])c[a][f]()});if(d.hoverSeries===c)c.onMouseOut();e&&d.legend.colorizeItem(c,a);c.isDirty=!0;c.options.stacking&&t(d.series,function(a){a.options.stacking&&a.visible&&(a.isDirty=!0)});t(c.linkedSeries,function(b){b.setVisible(a,!1)});g&&(d.isDirtyBox=!0);!1!==b&&d.redraw();B(c,f)},setTooltipPoints:function(a){var b=[],c,d,e=this.xAxis,f=e&&e.getExtremes(),g=e?e.tooltipLen|| f=(c.visible=a=c.userOptions.visible=a===u?!h:a)?"show":"hide";t(["group","dataLabelsGroup","markerGroup","tracker"],function(a){if(c[a])c[a][f]()});if(d.hoverSeries===c)c.onMouseOut();e&&d.legend.colorizeItem(c,a);c.isDirty=!0;c.options.stacking&&t(d.series,function(a){a.options.stacking&&a.visible&&(a.isDirty=!0)});t(c.linkedSeries,function(b){b.setVisible(a,!1)});g&&(d.isDirtyBox=!0);!1!==b&&d.redraw();B(c,f)},setTooltipPoints:function(a){var b=[],c,d,e=this.xAxis,f=e&&e.getExtremes(),g=e?e.tooltipLen||
e.len:this.chart.plotSizeX,h,k,l=[];if(!1!==this.options.enableMouseTracking&&!this.singularTooltips){a&&(this.tooltipPoints=null);t(this.segments||this.points,function(a){b=b.concat(a)});e&&e.reversed&&(b=b.reverse());this.orderTooltipPoints&&this.orderTooltipPoints(b);a=b.length;for(k=0;k<a;k++)if(e=b[k],c=e.x,c>=f.min&&c<=f.max)for(h=b[k+1],c=d===u?0:d+1,d=b[k+1]?T(x(0,K((e.clientX+(h?h.wrappedClientX||h.clientX:g))/2)),g):g;0<=c&&c<=d;)l[c++]=e;this.tooltipPoints=l}},show:function(){this.setVisible(!0)}, e.len:this.chart.plotSizeX,h,k,l=[];if(!1!==this.options.enableMouseTracking&&!this.singularTooltips){a&&(this.tooltipPoints=null);t(this.segments||this.points,function(a){b=b.concat(a)});e&&e.reversed&&(b=b.reverse());this.orderTooltipPoints&&this.orderTooltipPoints(b);a=b.length;for(k=0;k<a;k++)if(e=b[k],c=e.x,c>=f.min&&c<=f.max)for(h=b[k+1],c=d===u?0:d+1,d=b[k+1]?T(x(0,K((e.clientX+(h?h.wrappedClientX||h.clientX:g))/2)),g):g;0<=c&&c<=d;)l[c++]=e;this.tooltipPoints=l}},show:function(){this.setVisible(!0)},
hide:function(){this.setVisible(!1)},select:function(a){this.selected=a=a===u?!this.selected:a;this.checkbox&&(this.checkbox.checked=a);B(this,a?"select":"unselect")},drawTracker:$a.drawTrackerGraph});v(U,{Axis:ma,Chart:Ea,Color:za,Point:Ca,Tick:xa,Renderer:Ja,Series:fa,SVGElement:O,SVGRenderer:Ja,arrayMin:La,arrayMax:va,charts:Y,dateFormat:Ka,format:ua,pathAnim:ib,getOptions:function(){return M},hasBidiBug:Db,isTouchDevice:wb,numberFormat:ka,seriesTypes:P,setOptions:function(a){M=G(!0,M,a);pb(); hide:function(){this.setVisible(!1)},select:function(a){this.selected=a=a===u?!this.selected:a;this.checkbox&&(this.checkbox.checked=a);B(this,a?"select":"unselect")},drawTracker:$a.drawTrackerGraph});v(U,{Axis:ma,Chart:Ea,Color:za,Point:Ca,Tick:xa,Renderer:Ja,Series:fa,SVGElement:O,SVGRenderer:Ja,arrayMin:La,arrayMax:va,charts:Y,dateFormat:Ka,format:ua,pathAnim:ib,getOptions:function(){return M},hasBidiBug:Db,isTouchDevice:wb,numberFormat:ka,seriesTypes:P,setOptions:function(a){M=G(!0,M,a);pb();
return M},addEvent:F,removeEvent:L,createElement:ja,discardElement:Na,css:J,each:t,extend:v,map:kb,merge:G,pick:n,splat:ea,extendClass:nb,pInt:E,wrap:bb,svg:Z,canvas:ca,vml:!Z&&!ca,product:"Highcharts 4.0.4",version:"/Highstock 2.0.4"})})(); return M},addEvent:F,removeEvent:L,createElement:ja,discardElement:Na,css:J,each:t,extend:v,map:kb,merge:G,pick:n,splat:ea,extendClass:nb,pInt:E,wrap:bb,svg:Z,canvas:ca,vml:!Z&&!ca,product:"Highcharts 4.0.4",version:"/Highstock 2.0.4"})})();

View file

@ -1,114 +1,114 @@
// //
// SunLightExample.js // SunLightExample.js
// examples // examples
// Sam Gateau // Sam Gateau
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// 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
// //
Script.include("../../utilities/tools/cookies.js"); Script.include("../../utilities/tools/cookies.js");
var panel = new Panel(10, 400); var panel = new Panel(10, 400);
panel.newSlider("Origin Longitude", -180, 180, panel.newSlider("Origin Longitude", -180, 180,
function(value) { Scene.setStageLocation(value, Scene.getStageLocationLatitude(), Scene.getStageLocationAltitude()); }, function(value) { Scene.setStageLocation(value, Scene.getStageLocationLatitude(), Scene.getStageLocationAltitude()); },
function() { return Scene.getStageLocationLongitude(); }, function() { return Scene.getStageLocationLongitude(); },
function(value) { return value.toFixed(0) + " deg"; } function(value) { return value.toFixed(0) + " deg"; }
); );
panel.newSlider("Origin Latitude", -90, 90, panel.newSlider("Origin Latitude", -90, 90,
function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), value, Scene.getStageLocationAltitude()); }, function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), value, Scene.getStageLocationAltitude()); },
function() { return Scene.getStageLocationLatitude(); }, function() { return Scene.getStageLocationLatitude(); },
function(value) { return value.toFixed(0) + " deg"; } function(value) { return value.toFixed(0) + " deg"; }
); );
panel.newSlider("Origin Altitude", 0, 1000, panel.newSlider("Origin Altitude", 0, 1000,
function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), Scene.getStageLocationLatitude(), value); }, function(value) { Scene.setStageLocation(Scene.getStageLocationLongitude(), Scene.getStageLocationLatitude(), value); },
function() { return Scene.getStageLocationAltitude(); }, function() { return Scene.getStageLocationAltitude(); },
function(value) { return (value).toFixed(0) + " km"; } function(value) { return (value).toFixed(0) + " km"; }
); );
panel.newSlider("Year Time", 0, 364, panel.newSlider("Year Time", 0, 364,
function(value) { Scene.setStageYearTime(value); }, function(value) { Scene.setStageYearTime(value); },
function() { return Scene.getStageYearTime(); }, function() { return Scene.getStageYearTime(); },
function(value) { function(value) {
var numDaysPerMonth = 365.0 / 12.0; var numDaysPerMonth = 365.0 / 12.0;
var monthly = (value / numDaysPerMonth); var monthly = (value / numDaysPerMonth);
var month = Math.floor(monthly); var month = Math.floor(monthly);
return (month + 1).toFixed(0) + "/" + Math.ceil(0.5 + (monthly - month)*Math.ceil(numDaysPerMonth)).toFixed(0); } return (month + 1).toFixed(0) + "/" + Math.ceil(0.5 + (monthly - month)*Math.ceil(numDaysPerMonth)).toFixed(0); }
); );
panel.newSlider("Day Time", 0, 24, panel.newSlider("Day Time", 0, 24,
function(value) { Scene.setStageDayTime(value); panel.update("Light Direction"); }, function(value) { Scene.setStageDayTime(value); panel.update("Light Direction"); },
function() { return Scene.getStageDayTime(); }, function() { return Scene.getStageDayTime(); },
function(value) { function(value) {
var hour = Math.floor(value); var hour = Math.floor(value);
return (hour).toFixed(0) + ":" + ((value - hour)*60.0).toFixed(0); return (hour).toFixed(0) + ":" + ((value - hour)*60.0).toFixed(0);
} }
); );
var tickTackPeriod = 50; var tickTackPeriod = 50;
var tickTackSpeed = 0.0; var tickTackSpeed = 0.0;
panel.newSlider("Tick tack time", -1.0, 1.0, panel.newSlider("Tick tack time", -1.0, 1.0,
function(value) { tickTackSpeed = value; }, function(value) { tickTackSpeed = value; },
function() { return tickTackSpeed; }, function() { return tickTackSpeed; },
function(value) { return (value).toFixed(2); } function(value) { return (value).toFixed(2); }
); );
function runStageTime() { function runStageTime() {
if (tickTackSpeed != 0.0) { if (tickTackSpeed != 0.0) {
var hour = panel.get("Day Time"); var hour = panel.get("Day Time");
hour += tickTackSpeed; hour += tickTackSpeed;
panel.set("Day Time", hour); panel.set("Day Time", hour);
if (hour >= 24.0) { if (hour >= 24.0) {
panel.set("Year Time", panel.get("Year Time") + 1); panel.set("Year Time", panel.get("Year Time") + 1);
} else if (hour < 0.0) { } else if (hour < 0.0) {
panel.set("Year Time", panel.get("Year Time") - 1); panel.set("Year Time", panel.get("Year Time") - 1);
} }
} }
} }
Script.setInterval(runStageTime, tickTackPeriod); Script.setInterval(runStageTime, tickTackPeriod);
panel.newCheckbox("Enable Sun Model", panel.newCheckbox("Enable Sun Model",
function(value) { Scene.setStageSunModelEnable((value != 0)); }, function(value) { Scene.setStageSunModelEnable((value != 0)); },
function() { return Scene.isStageSunModelEnabled(); }, function() { return Scene.isStageSunModelEnabled(); },
function(value) { return (value); } function(value) { return (value); }
); );
panel.newDirectionBox("Light Direction", panel.newDirectionBox("Light Direction",
function(value) { Scene.setKeyLightDirection(value); }, function(value) { Scene.setKeyLightDirection(value); },
function() { return Scene.getKeyLightDirection(); }, function() { return Scene.getKeyLightDirection(); },
function(value) { return value.x.toFixed(2) + "," + value.y.toFixed(2) + "," + value.z.toFixed(2); } function(value) { return value.x.toFixed(2) + "," + value.y.toFixed(2) + "," + value.z.toFixed(2); }
); );
panel.newSlider("Light Intensity", 0.0, 5, panel.newSlider("Light Intensity", 0.0, 5,
function(value) { Scene.setKeyLightIntensity(value); }, function(value) { Scene.setKeyLightIntensity(value); },
function() { return Scene.getKeyLightIntensity(); }, function() { return Scene.getKeyLightIntensity(); },
function(value) { return (value).toFixed(2); } function(value) { return (value).toFixed(2); }
); );
panel.newSlider("Ambient Light Intensity", 0.0, 1.0, panel.newSlider("Ambient Light Intensity", 0.0, 1.0,
function(value) { Scene.setKeyLightAmbientIntensity(value); }, function(value) { Scene.setKeyLightAmbientIntensity(value); },
function() { return Scene.getKeyLightAmbientIntensity(); }, function() { return Scene.getKeyLightAmbientIntensity(); },
function(value) { return (value).toFixed(2); } function(value) { return (value).toFixed(2); }
); );
panel.newColorBox("Light Color", panel.newColorBox("Light Color",
function(value) { Scene.setKeyLightColor(value); }, function(value) { Scene.setKeyLightColor(value); },
function() { return Scene.getKeyLightColor(); }, function() { return Scene.getKeyLightColor(); },
function(value) { return (value); } // "(" + value.x + "," = value.y + "," + value.z + ")"; } function(value) { return (value); } // "(" + value.x + "," = value.y + "," + value.z + ")"; }
); );
Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
function scriptEnding() { function scriptEnding() {
Menu.removeMenu("Developer > Scene"); Menu.removeMenu("Developer > Scene");
panel.destroy(); panel.destroy();
} }
Script.scriptEnding.connect(scriptEnding); Script.scriptEnding.connect(scriptEnding);

View file

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

View file

@ -1,331 +1,331 @@
// //
// Leaves.js // Leaves.js
// examples // examples
// //
// Created by Bing Shearer on 14 Jul 2015 // Created by Bing Shearer on 14 Jul 2015
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// 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
// //
var leafName = "scriptLeaf"; var leafName = "scriptLeaf";
var leafSquall = function (properties) { var leafSquall = function (properties) {
var // Properties var // Properties
squallOrigin, squallOrigin,
squallRadius, squallRadius,
leavesPerMinute = 60, leavesPerMinute = 60,
leafSize = { leafSize = {
x: 0.1, x: 0.1,
y: 0.1, y: 0.1,
z: 0.1 z: 0.1
}, },
leafFallSpeed = 1, // m/s leafFallSpeed = 1, // m/s
leafLifetime = 60, // Seconds leafLifetime = 60, // Seconds
leafSpinMax = 0, // Maximum angular velocity per axis; deg/s leafSpinMax = 0, // Maximum angular velocity per axis; deg/s
debug = false, // Display origin circle; don't use running on Stack Manager debug = false, // Display origin circle; don't use running on Stack Manager
// Other // Other
squallCircle, squallCircle,
SQUALL_CIRCLE_COLOR = { SQUALL_CIRCLE_COLOR = {
red: 255, red: 255,
green: 0, green: 0,
blue: 0 blue: 0
}, },
SQUALL_CIRCLE_ALPHA = 0.5, SQUALL_CIRCLE_ALPHA = 0.5,
SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0), SQUALL_CIRCLE_ROTATION = Quat.fromPitchYawRollDegrees(90, 0, 0),
leafProperties, leafProperties,
leaf_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ozan/support/forBing/palmLeaf.fbx", leaf_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ozan/support/forBing/palmLeaf.fbx",
leafTimer, leafTimer,
leaves = [], // HACK: Work around leaves not always getting velocities leaves = [], // HACK: Work around leaves not always getting velocities
leafVelocities = [], // HACK: Work around leaves not always getting velocities leafVelocities = [], // HACK: Work around leaves not always getting velocities
DEGREES_TO_RADIANS = Math.PI / 180, DEGREES_TO_RADIANS = Math.PI / 180,
leafDeleteOnTearDown = true, leafDeleteOnTearDown = true,
maxLeaves, maxLeaves,
leafCount, leafCount,
nearbyEntities, nearbyEntities,
complexMovement = false, complexMovement = false,
movementTime = 0, movementTime = 0,
maxSpinRadians = properties.leafSpinMax * DEGREES_TO_RADIANS, maxSpinRadians = properties.leafSpinMax * DEGREES_TO_RADIANS,
windFactor, windFactor,
leafDeleteOnGround = false, leafDeleteOnGround = false,
floorHeight = null; floorHeight = null;
function processProperties() { function processProperties() {
if (!properties.hasOwnProperty("origin")) { if (!properties.hasOwnProperty("origin")) {
print("ERROR: Leaf squall origin must be specified"); print("ERROR: Leaf squall origin must be specified");
return; return;
} }
squallOrigin = properties.origin; squallOrigin = properties.origin;
if (!properties.hasOwnProperty("radius")) { if (!properties.hasOwnProperty("radius")) {
print("ERROR: Leaf squall radius must be specified"); print("ERROR: Leaf squall radius must be specified");
return; return;
} }
squallRadius = properties.radius; squallRadius = properties.radius;
if (properties.hasOwnProperty("leavesPerMinute")) { if (properties.hasOwnProperty("leavesPerMinute")) {
leavesPerMinute = properties.leavesPerMinute; leavesPerMinute = properties.leavesPerMinute;
} }
if (properties.hasOwnProperty("leafSize")) { if (properties.hasOwnProperty("leafSize")) {
leafSize = properties.leafSize; leafSize = properties.leafSize;
} }
if (properties.hasOwnProperty("leafFallSpeed")) { if (properties.hasOwnProperty("leafFallSpeed")) {
leafFallSpeed = properties.leafFallSpeed; leafFallSpeed = properties.leafFallSpeed;
} }
if (properties.hasOwnProperty("leafLifetime")) { if (properties.hasOwnProperty("leafLifetime")) {
leafLifetime = properties.leafLifetime; leafLifetime = properties.leafLifetime;
} }
if (properties.hasOwnProperty("leafSpinMax")) { if (properties.hasOwnProperty("leafSpinMax")) {
leafSpinMax = properties.leafSpinMax; leafSpinMax = properties.leafSpinMax;
} }
if (properties.hasOwnProperty("debug")) { if (properties.hasOwnProperty("debug")) {
debug = properties.debug; debug = properties.debug;
} }
if (properties.hasOwnProperty("floorHeight")) { if (properties.hasOwnProperty("floorHeight")) {
floorHeight = properties.floorHeight; floorHeight = properties.floorHeight;
} }
if (properties.hasOwnProperty("maxLeaves")) { if (properties.hasOwnProperty("maxLeaves")) {
maxLeaves = properties.maxLeaves; maxLeaves = properties.maxLeaves;
} }
if (properties.hasOwnProperty("complexMovement")) { if (properties.hasOwnProperty("complexMovement")) {
complexMovement = properties.complexMovement; complexMovement = properties.complexMovement;
} }
if (properties.hasOwnProperty("leafDeleteOnGround")) { if (properties.hasOwnProperty("leafDeleteOnGround")) {
leafDeleteOnGround = properties.leafDeleteOnGround; leafDeleteOnGround = properties.leafDeleteOnGround;
} }
if (properties.hasOwnProperty("windFactor")) { if (properties.hasOwnProperty("windFactor")) {
windFactor = properties.windFactor; windFactor = properties.windFactor;
} else if (complexMovement == true){ } else if (complexMovement == true){
print("ERROR: Wind Factor must be defined for complex movement") print("ERROR: Wind Factor must be defined for complex movement")
} }
leafProperties = { leafProperties = {
type: "Model", type: "Model",
name: leafName, name: leafName,
modelURL: leaf_MODEL_URL, modelURL: leaf_MODEL_URL,
lifetime: leafLifetime, lifetime: leafLifetime,
dimensions: leafSize, dimensions: leafSize,
velocity: { velocity: {
x: 0, x: 0,
y: -leafFallSpeed, y: -leafFallSpeed,
z: 0 z: 0
}, },
damping: 0, damping: 0,
angularDamping: 0, angularDamping: 0,
ignoreForCollisions: true ignoreForCollisions: true
}; };
} }
function createleaf() { function createleaf() {
var angle, var angle,
radius, radius,
offset, offset,
leaf, leaf,
spin = { spin = {
x: 0, x: 0,
y: 0, y: 0,
z: 0 z: 0
}, },
i; i;
// HACK: Work around leaves not always getting velocities set at creation // HACK: Work around leaves not always getting velocities set at creation
for (i = 0; i < leaves.length; i++) { for (i = 0; i < leaves.length; i++) {
Entities.editEntity(leaves[i], leafVelocities[i]); Entities.editEntity(leaves[i], leafVelocities[i]);
} }
angle = Math.random() * leafSpinMax; angle = Math.random() * leafSpinMax;
radius = Math.random() * squallRadius; radius = Math.random() * squallRadius;
offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), { offset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, angle, 0), {
x: 0, x: 0,
y: -0.1, y: -0.1,
z: radius z: radius
}); });
leafProperties.position = Vec3.sum(squallOrigin, offset); leafProperties.position = Vec3.sum(squallOrigin, offset);
if (properties.leafSpinMax > 0 && !complexMovement) { if (properties.leafSpinMax > 0 && !complexMovement) {
spin = { spin = {
x: Math.random() * maxSpinRadians, x: Math.random() * maxSpinRadians,
y: Math.random() * maxSpinRadians, y: Math.random() * maxSpinRadians,
z: Math.random() * maxSpinRadians z: Math.random() * maxSpinRadians
}; };
leafProperties.angularVelocity = spin; leafProperties.angularVelocity = spin;
} else if (complexMovement) { } else if (complexMovement) {
spin = { spin = {
x: 0, x: 0,
y: 0, y: 0,
z: 0 z: 0
}; };
leafProperties.angularVelocity = spin leafProperties.angularVelocity = spin
} }
leaf = Entities.addEntity(leafProperties); leaf = Entities.addEntity(leafProperties);
// HACK: Work around leaves not always getting velocities set at creation // HACK: Work around leaves not always getting velocities set at creation
leaves.push(leaf); leaves.push(leaf);
leafVelocities.push({ leafVelocities.push({
velocity: leafProperties.velocity, velocity: leafProperties.velocity,
angularVelocity: spin angularVelocity: spin
}); });
if (leaves.length > 5) { if (leaves.length > 5) {
leaves.shift(); leaves.shift();
leafVelocities.shift(); leafVelocities.shift();
} }
} }
function setUp() { function setUp() {
if (debug) { if (debug) {
squallCircle = Overlays.addOverlay("circle3d", { squallCircle = Overlays.addOverlay("circle3d", {
size: { size: {
x: 2 * squallRadius, x: 2 * squallRadius,
y: 2 * squallRadius y: 2 * squallRadius
}, },
color: SQUALL_CIRCLE_COLOR, color: SQUALL_CIRCLE_COLOR,
alpha: SQUALL_CIRCLE_ALPHA, alpha: SQUALL_CIRCLE_ALPHA,
solid: true, solid: true,
visible: debug, visible: debug,
position: squallOrigin, position: squallOrigin,
rotation: SQUALL_CIRCLE_ROTATION rotation: SQUALL_CIRCLE_ROTATION
}); });
} }
leafTimer = Script.setInterval(function () { leafTimer = Script.setInterval(function () {
if (leafCount <= maxLeaves - 1) { if (leafCount <= maxLeaves - 1) {
createleaf() createleaf()
} }
}, 60000 / leavesPerMinute); }, 60000 / leavesPerMinute);
} }
Script.setInterval(function () { Script.setInterval(function () {
nearbyEntities = Entities.findEntities(squallOrigin, squallRadius); nearbyEntities = Entities.findEntities(squallOrigin, squallRadius);
newLeafMovement() newLeafMovement()
}, 100); }, 100);
function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms function newLeafMovement() { //new additions to leaf code. Operates at 10 Hz or every 100 ms
movementTime += 0.1; movementTime += 0.1;
var currentLeaf, var currentLeaf,
randomRotationSpeed = { randomRotationSpeed = {
x: maxSpinRadians * Math.sin(movementTime), x: maxSpinRadians * Math.sin(movementTime),
y: maxSpinRadians * Math.random(), y: maxSpinRadians * Math.random(),
z: maxSpinRadians * Math.sin(movementTime / 7) z: maxSpinRadians * Math.sin(movementTime / 7)
}; };
for (var i = 0; i < nearbyEntities.length; i++) { for (var i = 0; i < nearbyEntities.length; i++) {
var entityProperties = Entities.getEntityProperties(nearbyEntities[i]); var entityProperties = Entities.getEntityProperties(nearbyEntities[i]);
var entityName = entityProperties.name; var entityName = entityProperties.name;
if (leafName === entityName) { if (leafName === entityName) {
currentLeaf = nearbyEntities[i]; currentLeaf = nearbyEntities[i];
var leafHeight = entityProperties.position.y; var leafHeight = entityProperties.position.y;
if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code; if (complexMovement && leafHeight > floorHeight || complexMovement && floorHeight == null) { //actual new movement code;
var leafCurrentVel = entityProperties.velocity, var leafCurrentVel = entityProperties.velocity,
leafCurrentRot = entityProperties.rotation, leafCurrentRot = entityProperties.rotation,
yVec = { yVec = {
x: 0, x: 0,
y: 1, y: 1,
z: 0 z: 0
}, },
leafYinWFVec = Vec3.multiplyQbyV(leafCurrentRot, yVec), leafYinWFVec = Vec3.multiplyQbyV(leafCurrentRot, yVec),
leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec), leafLocalHorVec = Vec3.cross(leafYinWFVec, yVec),
leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec), leafMostDownVec = Vec3.cross(leafYinWFVec, leafLocalHorVec),
leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor), leafDesiredVel = Vec3.multiply(leafMostDownVec, windFactor),
leafVelDelt = Vec3.subtract(leafDesiredVel, leafCurrentVel), leafVelDelt = Vec3.subtract(leafDesiredVel, leafCurrentVel),
leafNewVel = Vec3.sum(leafCurrentVel, Vec3.multiply(leafVelDelt, windFactor)); leafNewVel = Vec3.sum(leafCurrentVel, Vec3.multiply(leafVelDelt, windFactor));
Entities.editEntity(currentLeaf, { Entities.editEntity(currentLeaf, {
angularVelocity: randomRotationSpeed, angularVelocity: randomRotationSpeed,
velocity: leafNewVel velocity: leafNewVel
}) })
} else if (leafHeight <= floorHeight) { } else if (leafHeight <= floorHeight) {
if (!leafDeleteOnGround) { if (!leafDeleteOnGround) {
Entities.editEntity(nearbyEntities[i], { Entities.editEntity(nearbyEntities[i], {
locked: false, locked: false,
velocity: { velocity: {
x: 0, x: 0,
y: 0, y: 0,
z: 0 z: 0
}, },
angularVelocity: { angularVelocity: {
x: 0, x: 0,
y: 0, y: 0,
z: 0 z: 0
} }
}) })
} else { } else {
Entity.deleteEntity(currentLeaf); Entity.deleteEntity(currentLeaf);
} }
} }
} }
} }
} }
getLeafCount = Script.setInterval(function () { getLeafCount = Script.setInterval(function () {
leafCount = 0 leafCount = 0
for (var i = 0; i < nearbyEntities.length; i++) { for (var i = 0; i < nearbyEntities.length; i++) {
var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; var entityName = Entities.getEntityProperties(nearbyEntities[i]).name;
//Stop Leaves at floorHeight //Stop Leaves at floorHeight
if (leafName === entityName) { if (leafName === entityName) {
leafCount++; leafCount++;
if (i == nearbyEntities.length - 1) { if (i == nearbyEntities.length - 1) {
//print(leafCount); //print(leafCount);
} }
} }
} }
}, 1000) }, 1000)
function tearDown() { function tearDown() {
Script.clearInterval(leafTimer); Script.clearInterval(leafTimer);
Overlays.deleteOverlay(squallCircle); Overlays.deleteOverlay(squallCircle);
if (leafDeleteOnTearDown) { if (leafDeleteOnTearDown) {
for (var i = 0; i < nearbyEntities.length; i++) { for (var i = 0; i < nearbyEntities.length; i++) {
var entityName = Entities.getEntityProperties(nearbyEntities[i]).name; var entityName = Entities.getEntityProperties(nearbyEntities[i]).name;
if (leafName === entityName) { if (leafName === entityName) {
//We have a match - delete this entity //We have a match - delete this entity
Entities.editEntity(nearbyEntities[i], { Entities.editEntity(nearbyEntities[i], {
locked: false locked: false
}); });
Entities.deleteEntity(nearbyEntities[i]); Entities.deleteEntity(nearbyEntities[i]);
} }
} }
} }
} }
processProperties(); processProperties();
setUp(); setUp();
Script.scriptEnding.connect(tearDown); Script.scriptEnding.connect(tearDown);
return {}; return {};
}; };
var leafSquall1 = new leafSquall({ var leafSquall1 = new leafSquall({
origin: { origin: {
x: 3071.5, x: 3071.5,
y: 2170, y: 2170,
z: 6765.3 z: 6765.3
}, },
radius: 100, radius: 100,
leavesPerMinute: 30, leavesPerMinute: 30,
leafSize: { leafSize: {
x: 0.3, x: 0.3,
y: 0.00, y: 0.00,
z: 0.3 z: 0.3
}, },
leafFallSpeed: 0.4, leafFallSpeed: 0.4,
leafLifetime: 100, leafLifetime: 100,
leafSpinMax: 30, leafSpinMax: 30,
debug: false, debug: false,
maxLeaves: 100, maxLeaves: 100,
leafDeleteOnTearDown: true, leafDeleteOnTearDown: true,
complexMovement: true, complexMovement: true,
floorHeight: 2143.5, floorHeight: 2143.5,
windFactor: 0.5, windFactor: 0.5,
leafDeleteOnGround: false leafDeleteOnGround: false
}); });
// todo // todo
//deal with depth issue //deal with depth issue

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,204 +1,204 @@
// //
// walkFilters.js // walkFilters.js
// version 1.1 // version 1.1
// //
// Created by David Wooldridge, June 2015 // Created by David Wooldridge, June 2015
// Copyright © 2014 - 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// 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.2+
// //
// 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 // simple averaging (LP) filter for damping / smoothing
AveragingFilter = function(length) { AveragingFilter = function(length) {
// initialise the array of past values // initialise the array of past values
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) {
this.pastValues.push(arguments[0]); this.pastValues.push(arguments[0]);
this.pastValues.shift(); this.pastValues.shift();
var nextOutputValue = 0; var nextOutputValue = 0;
for (var value in this.pastValues) nextOutputValue += this.pastValues[value]; 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 // 2nd order 2Hz Butterworth LP filter
ButterworthFilter = function() { ButterworthFilter = function() {
// coefficients calculated at: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html // coefficients calculated at: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
this.gain = 104.9784742; this.gain = 104.9784742;
this.coeffOne = -0.7436551950; this.coeffOne = -0.7436551950;
this.coeffTwo = 1.7055521455; this.coeffTwo = 1.7055521455;
// 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 < 3; 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[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;
var iterations = this.numHarmonics * 2 + 2; var iterations = this.numHarmonics * 2 + 2;
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
if (n === 3 || n === 7 || n === 11 || n === 15) { if (n === 3 || n === 7 || n === 11 || n === 15) {
mulitplier *= -1; mulitplier *= -1;
} }
harmonics += mulitplier * Math.sin(n * frequency); harmonics += mulitplier * Math.sin(n * frequency);
} }
break; break;
} }
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);
} }
break; break;
} }
} }
} }
// 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-calculated harmonics (Fourier synthesis) // 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 literal
filter = (function() { filter = (function() {
const HALF_CYCLE = 180; const HALF_CYCLE = 180;
// Bezier private variables // Bezier private variables
var _C1 = {x:0, y:0}; var _C1 = {x:0, y:0};
var _C4 = {x:1, y:1}; 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) };
function _B3(t) { return 3 * t * (1 - t) * (1 - t) }; function _B3(t) { return 3 * t * (1 - t) * (1 - t) };
function _B4(t) { return (1 - t) * (1 - t) * (1 - t) }; function _B4(t) { return (1 - t) * (1 - t) * (1 - t) };
return { return {
// helper methods // helper methods
degToRad: function(degrees) { degToRad: function(degrees) {
var convertedValue = degrees * Math.PI / HALF_CYCLE; var convertedValue = degrees * Math.PI / HALF_CYCLE;
return convertedValue; return convertedValue;
}, },
radToDeg: function(radians) { radToDeg: function(radians) {
var convertedValue = radians * HALF_CYCLE / Math.PI; var convertedValue = radians * HALF_CYCLE / 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
// simple averaging (LP) filter for damping / smoothing // simple averaging (LP) filter for damping / smoothing
createAveragingFilter: function(length) { createAveragingFilter: function(length) {
var newAveragingFilter = new AveragingFilter(length); var newAveragingFilter = new AveragingFilter(length);
return newAveragingFilter; return newAveragingFilter;
}, },
// provides LP filtering with improved frequency / phase response // provides LP filtering with improved frequency / phase response
createButterworthFilter: function() { createButterworthFilter: function() {
var newButterworthFilter = new ButterworthFilter(); var newButterworthFilter = new ButterworthFilter();
return newButterworthFilter; return newButterworthFilter;
}, },
// generates sawtooth, triangle or square waves using harmonics // 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 // 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 response curve shaping for more natural transitions // Bezier response curve shaping for more natural transitions
bezier: function(input, C2, C3) { 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/
input = 1 - input; input = 1 - input;
return _C1.y * _B1(input) + C2.y * _B2(input) + C3.y * _B3(input) + _C4.y * _B4(input); return _C1.y * _B1(input) + C2.y * _B2(input) + C3.y * _B3(input) + _C4.y * _B4(input);
}, },
// simple clipping filter (special case for hips y-axis skeleton offset for walk animation) // 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;
} }
return outputValue; return outputValue;
} }
} }
})(); })();

View file

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

View file

@ -1,32 +1,32 @@
// //
// createFlashlight.js // createFlashlight.js
// examples/entityScripts // examples/entityScripts
// //
// Created by Sam Gateau on 9/9/15. // Created by Sam Gateau on 9/9/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// This is a toy script that create a flashlight entity that lit when grabbed // This is a toy script that create a flashlight entity that lit when grabbed
// This can be run from an interface and the flashlight will get deleted from the domain when quitting // This can be run from an interface and the flashlight will get deleted from the domain when quitting
// //
// 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
// //
/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
Script.include("https://hifi-public.s3.amazonaws.com/scripts/utilities.js"); Script.include("https://hifi-public.s3.amazonaws.com/scripts/utilities.js");
var scriptURL = Script.resolvePath('flashlight.js?123123'); var scriptURL = Script.resolvePath('flashlight.js?123123');
var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"; var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx";
var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation())));
var flashlight = Entities.addEntity({ var flashlight = Entities.addEntity({
type: "Model", type: "Model",
modelURL: modelURL, modelURL: modelURL,
position: center, position: center,
dimensions: { x: 0.08, y: 0.30, z: 0.08}, dimensions: { x: 0.08, y: 0.30, z: 0.08},
collisionsWillMove: true, collisionsWillMove: true,
shapeType: 'box', shapeType: 'box',
script: scriptURL script: scriptURL
}); });

View file

@ -1,269 +1,269 @@
// //
// flashlight.js // flashlight.js
// //
// Script Type: Entity // Script Type: Entity
// //
// Created by Sam Gateau on 9/9/15. // Created by Sam Gateau on 9/9/15.
// Additions by James B. Pollack @imgntn on 9/21/2015 // Additions by James B. Pollack @imgntn on 9/21/2015
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// This is a toy script that can be added to the Flashlight model entity: // This is a toy script that can be added to the Flashlight model entity:
// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" // "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"
// that creates a spotlight attached with the flashlight model while the entity is grabbed // that creates a spotlight attached with the flashlight model while the entity is grabbed
// //
// 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
// //
/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ /*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
(function() { (function() {
Script.include("../../libraries/utils.js"); Script.include("../../libraries/utils.js");
var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav';
var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav';
//we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them
var startTime = Date.now(); var startTime = Date.now();
//if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value.
var LIFETIME = 25; var LIFETIME = 25;
var MSEC_PER_SEC = 1000.0; var MSEC_PER_SEC = 1000.0;
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
function Flashlight() { function Flashlight() {
return; return;
} }
//if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will //if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will
var DISABLE_LIGHT_THRESHOLD = 0.7; var DISABLE_LIGHT_THRESHOLD = 0.7;
// These constants define the Spotlight position and orientation relative to the model // These constants define the Spotlight position and orientation relative to the model
var MODEL_LIGHT_POSITION = { var MODEL_LIGHT_POSITION = {
x: 0, x: 0,
y: -0.3, y: -0.3,
z: 0 z: 0
}; };
var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
x: 1, x: 1,
y: 0, y: 0,
z: 0 z: 0
}); });
var GLOW_LIGHT_POSITION = { var GLOW_LIGHT_POSITION = {
x: 0, x: 0,
y: -0.1, y: -0.1,
z: 0 z: 0
}; };
// Evaluate the world light entity positions and orientations from the model ones // Evaluate the world light entity positions and orientations from the model ones
function evalLightWorldTransform(modelPos, modelRot) { function evalLightWorldTransform(modelPos, modelRot) {
return { return {
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
}; };
} }
function glowLightWorldTransform(modelPos, modelRot) { function glowLightWorldTransform(modelPos, modelRot) {
return { return {
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, GLOW_LIGHT_POSITION)), p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, GLOW_LIGHT_POSITION)),
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
}; };
} }
Flashlight.prototype = { Flashlight.prototype = {
lightOn: false, lightOn: false,
hand: null, hand: null,
whichHand: null, whichHand: null,
hasSpotlight: false, hasSpotlight: false,
spotlight: null, spotlight: null,
setRightHand: function() { setRightHand: function() {
this.hand = 'RIGHT'; this.hand = 'RIGHT';
}, },
setLeftHand: function() { setLeftHand: function() {
this.hand = 'LEFT'; this.hand = 'LEFT';
}, },
startNearGrab: function() { startNearGrab: function() {
if (!this.hasSpotlight) { if (!this.hasSpotlight) {
//this light casts the beam //this light casts the beam
this.spotlight = Entities.addEntity({ this.spotlight = Entities.addEntity({
type: "Light", type: "Light",
isSpotlight: true, isSpotlight: true,
dimensions: { dimensions: {
x: 2, x: 2,
y: 2, y: 2,
z: 20 z: 20
}, },
color: { color: {
red: 255, red: 255,
green: 255, green: 255,
blue: 255 blue: 255
}, },
intensity: 2, intensity: 2,
exponent: 0.3, exponent: 0.3,
cutoff: 20, cutoff: 20,
lifetime: LIFETIME lifetime: LIFETIME
}); });
//this light creates the effect of a bulb at the end of the flashlight //this light creates the effect of a bulb at the end of the flashlight
this.glowLight = Entities.addEntity({ this.glowLight = Entities.addEntity({
type: "Light", type: "Light",
dimensions: { dimensions: {
x: 0.25, x: 0.25,
y: 0.25, y: 0.25,
z: 0.25 z: 0.25
}, },
isSpotlight: false, isSpotlight: false,
color: { color: {
red: 255, red: 255,
green: 255, green: 255,
blue: 255 blue: 255
}, },
exponent: 0, exponent: 0,
cutoff: 90, // in degrees cutoff: 90, // in degrees
lifetime: LIFETIME lifetime: LIFETIME
}); });
this.hasSpotlight = true; this.hasSpotlight = true;
} }
}, },
setWhichHand: function() { setWhichHand: function() {
this.whichHand = this.hand; this.whichHand = this.hand;
}, },
continueNearGrab: function() { continueNearGrab: function() {
if (this.whichHand === null) { if (this.whichHand === null) {
//only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten
this.setWhichHand(); this.setWhichHand();
} else { } else {
this.updateLightPositions(); this.updateLightPositions();
this.changeLightWithTriggerPressure(this.whichHand); this.changeLightWithTriggerPressure(this.whichHand);
} }
}, },
releaseGrab: function() { releaseGrab: function() {
//delete the lights and reset state //delete the lights and reset state
if (this.hasSpotlight) { if (this.hasSpotlight) {
Entities.deleteEntity(this.spotlight); Entities.deleteEntity(this.spotlight);
Entities.deleteEntity(this.glowLight); Entities.deleteEntity(this.glowLight);
this.hasSpotlight = false; this.hasSpotlight = false;
this.glowLight = null; this.glowLight = null;
this.spotlight = null; this.spotlight = null;
this.whichHand = null; this.whichHand = null;
this.lightOn = false; this.lightOn = false;
} }
}, },
updateLightPositions: function() { updateLightPositions: function() {
var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
//move the two lights along the vectors we set above //move the two lights along the vectors we set above
var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation); var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation);
//move them with the entity model //move them with the entity model
Entities.editEntity(this.spotlight, { Entities.editEntity(this.spotlight, {
position: lightTransform.p, position: lightTransform.p,
rotation: lightTransform.q, rotation: lightTransform.q,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
}); });
Entities.editEntity(this.glowLight, { Entities.editEntity(this.glowLight, {
position: glowLightTransform.p, position: glowLightTransform.p,
rotation: glowLightTransform.q, rotation: glowLightTransform.q,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
}); });
}, },
changeLightWithTriggerPressure: function(flashLightHand) { changeLightWithTriggerPressure: function(flashLightHand) {
var handClickString = flashLightHand + "_HAND_CLICK"; var handClickString = flashLightHand + "_HAND_CLICK";
var handClick = Controller.findAction(handClickString); var handClick = Controller.findAction(handClickString);
this.triggerValue = Controller.getActionValue(handClick); this.triggerValue = Controller.getActionValue(handClick);
if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) {
this.turnLightOff(); this.turnLightOff();
} else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) {
this.turnLightOn(); this.turnLightOn();
} }
return; return;
}, },
turnLightOff: function() { turnLightOff: function() {
this.playSoundAtCurrentPosition(false); this.playSoundAtCurrentPosition(false);
Entities.editEntity(this.spotlight, { Entities.editEntity(this.spotlight, {
intensity: 0 intensity: 0
}); });
Entities.editEntity(this.glowLight, { Entities.editEntity(this.glowLight, {
intensity: 0 intensity: 0
}); });
this.lightOn = false; this.lightOn = false;
}, },
turnLightOn: function() { turnLightOn: function() {
this.playSoundAtCurrentPosition(true); this.playSoundAtCurrentPosition(true);
Entities.editEntity(this.glowLight, { Entities.editEntity(this.glowLight, {
intensity: 2 intensity: 2
}); });
Entities.editEntity(this.spotlight, { Entities.editEntity(this.spotlight, {
intensity: 2 intensity: 2
}); });
this.lightOn = true; this.lightOn = true;
}, },
playSoundAtCurrentPosition: function(playOnSound) { playSoundAtCurrentPosition: function(playOnSound) {
var position = Entities.getEntityProperties(this.entityID, "position").position; var position = Entities.getEntityProperties(this.entityID, "position").position;
var audioProperties = { var audioProperties = {
volume: 0.25, volume: 0.25,
position: position position: position
}; };
if (playOnSound) { if (playOnSound) {
Audio.playSound(this.ON_SOUND, audioProperties); Audio.playSound(this.ON_SOUND, audioProperties);
} else { } else {
Audio.playSound(this.OFF_SOUND, audioProperties); Audio.playSound(this.OFF_SOUND, audioProperties);
} }
}, },
preload: function(entityID) { preload: function(entityID) {
// preload() will be called when the entity has become visible (or known) to the interface // preload() will be called when the entity has become visible (or known) to the interface
// it gives us a chance to set our local JavaScript object up. In this case it means: // it gives us a chance to set our local JavaScript object up. In this case it means:
// * remembering our entityID, so we can access it in cases where we're called without an entityID // * remembering our entityID, so we can access it in cases where we're called without an entityID
// * preloading sounds // * preloading sounds
this.entityID = entityID; this.entityID = entityID;
this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL);
this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL);
}, },
unload: function() { unload: function() {
// unload() will be called when our entity is no longer available. It may be because we were deleted, // unload() will be called when our entity is no longer available. It may be because we were deleted,
// or because we've left the domain or quit the application. // or because we've left the domain or quit the application.
if (this.hasSpotlight) { if (this.hasSpotlight) {
Entities.deleteEntity(this.spotlight); Entities.deleteEntity(this.spotlight);
Entities.deleteEntity(this.glowLight); Entities.deleteEntity(this.glowLight);
this.hasSpotlight = false; this.hasSpotlight = false;
this.glowLight = null; this.glowLight = null;
this.spotlight = null; this.spotlight = null;
this.whichHand = null; this.whichHand = null;
this.lightOn = false; this.lightOn = false;
} }
}, },
}; };
// entity scripts always need to return a newly constructed object of our type // entity scripts always need to return a newly constructed object of our type
return new Flashlight(); return new Flashlight();
}); });

View file

@ -1,87 +1,87 @@
// //
// SunLightExample.js // SunLightExample.js
// examples // examples
// Sam Gateau // Sam Gateau
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// 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
// //
Script.include("cookies.js"); Script.include("cookies.js");
var panel = new Panel(10, 100); var panel = new Panel(10, 100);
function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) { function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) {
this.subPanel = panel.newSubPanel(name); this.subPanel = panel.newSubPanel(name);
this.subPanel.newSlider("Num Feed", 0, 1, this.subPanel.newSlider("Num Feed", 0, 1,
function(value) { }, function(value) { },
feedGetter, feedGetter,
function(value) { return (value); }); function(value) { return (value); });
this.subPanel.newSlider("Num Drawn", 0, 1, this.subPanel.newSlider("Num Drawn", 0, 1,
function(value) { }, function(value) { },
drawGetter, drawGetter,
function(value) { return (value); }); function(value) { return (value); });
this.subPanel.newSlider("Max Drawn", -1, 1, this.subPanel.newSlider("Max Drawn", -1, 1,
capSetter, capSetter,
capGetter, capGetter,
function(value) { return (value); }); function(value) { return (value); });
this.update = function () { this.update = function () {
var numFeed = this.subPanel.get("Num Feed"); var numFeed = this.subPanel.get("Num Feed");
this.subPanel.set("Num Feed", numFeed); this.subPanel.set("Num Feed", numFeed);
this.subPanel.set("Num Drawn", this.subPanel.get("Num Drawn")); this.subPanel.set("Num Drawn", this.subPanel.get("Num Drawn"));
var numMax = Math.max(numFeed, 1); var numMax = Math.max(numFeed, 1);
this.subPanel.getWidget("Num Feed").setMaxValue(numMax); this.subPanel.getWidget("Num Feed").setMaxValue(numMax);
this.subPanel.getWidget("Num Drawn").setMaxValue(numMax); this.subPanel.getWidget("Num Drawn").setMaxValue(numMax);
this.subPanel.getWidget("Max Drawn").setMaxValue(numMax); this.subPanel.getWidget("Max Drawn").setMaxValue(numMax);
}; };
}; };
var opaquesCounter = new CounterWidget(panel, "Opaques", var opaquesCounter = new CounterWidget(panel, "Opaques",
function () { return Scene.getEngineNumFeedOpaqueItems(); }, function () { return Scene.getEngineNumFeedOpaqueItems(); },
function () { return Scene.getEngineNumDrawnOpaqueItems(); }, function () { return Scene.getEngineNumDrawnOpaqueItems(); },
function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); }, function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); },
function () { return Scene.getEngineMaxDrawnOpaqueItems(); } function () { return Scene.getEngineMaxDrawnOpaqueItems(); }
); );
var transparentsCounter = new CounterWidget(panel, "Transparents", var transparentsCounter = new CounterWidget(panel, "Transparents",
function () { return Scene.getEngineNumFeedTransparentItems(); }, function () { return Scene.getEngineNumFeedTransparentItems(); },
function () { return Scene.getEngineNumDrawnTransparentItems(); }, function () { return Scene.getEngineNumDrawnTransparentItems(); },
function(value) { Scene.setEngineMaxDrawnTransparentItems(value); }, function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
function () { return Scene.getEngineMaxDrawnTransparentItems(); } function () { return Scene.getEngineMaxDrawnTransparentItems(); }
); );
var overlaysCounter = new CounterWidget(panel, "Overlays", var overlaysCounter = new CounterWidget(panel, "Overlays",
function () { return Scene.getEngineNumFeedOverlay3DItems(); }, function () { return Scene.getEngineNumFeedOverlay3DItems(); },
function () { return Scene.getEngineNumDrawnOverlay3DItems(); }, function () { return Scene.getEngineNumDrawnOverlay3DItems(); },
function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); }, function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); },
function () { return Scene.getEngineMaxDrawnOverlay3DItems(); } function () { return Scene.getEngineMaxDrawnOverlay3DItems(); }
); );
panel.newCheckbox("Display status", panel.newCheckbox("Display status",
function(value) { Scene.setEngineDisplayItemStatus(value); }, function(value) { Scene.setEngineDisplayItemStatus(value); },
function() { return Scene.doEngineDisplayItemStatus(); }, function() { return Scene.doEngineDisplayItemStatus(); },
function(value) { return (value); } function(value) { return (value); }
); );
var tickTackPeriod = 500; var tickTackPeriod = 500;
function updateCounters() { function updateCounters() {
opaquesCounter.update(); opaquesCounter.update();
transparentsCounter.update(); transparentsCounter.update();
overlaysCounter.update(); overlaysCounter.update();
} }
Script.setInterval(updateCounters, tickTackPeriod); Script.setInterval(updateCounters, tickTackPeriod);
Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
function scriptEnding() { function scriptEnding() {
panel.destroy(); panel.destroy();
} }
Script.scriptEnding.connect(scriptEnding); Script.scriptEnding.connect(scriptEnding);

View file

@ -1,454 +1,454 @@
// //
// walk.js // walk.js
// version 1.25 // version 1.25
// //
// Created by David Wooldridge, June 2015 // Created by David Wooldridge, June 2015
// Copyright © 2014 - 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// Animates an avatar using procedural animation techniques. // Animates an avatar using procedural animation techniques.
// //
// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools // Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
// //
// 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
// //
// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files // animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files
const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/"; const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/";
var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/"; var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/";
Script.include([ Script.include([
"./libraries/walkConstants.js", "./libraries/walkConstants.js",
"./libraries/walkFilters.js", "./libraries/walkFilters.js",
"./libraries/walkApi.js", "./libraries/walkApi.js",
pathToAssets + "walkAssets.js" pathToAssets + "walkAssets.js"
]); ]);
// construct Avatar, Motion and (null) Transition // construct Avatar, Motion and (null) Transition
var avatar = new Avatar(); var avatar = new Avatar();
var motion = new Motion(); var motion = new Motion();
var nullTransition = new Transition(); var nullTransition = new Transition();
motion.currentTransition = nullTransition; motion.currentTransition = nullTransition;
// create settings (gets initial values from avatar) // create settings (gets initial values from avatar)
Script.include("./libraries/walkSettings.js"); Script.include("./libraries/walkSettings.js");
// Main loop // Main loop
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
if (motion.isLive) { if (motion.isLive) {
// assess current locomotion state // assess current locomotion state
motion.assess(deltaTime); motion.assess(deltaTime);
// decide which animation should be playing // decide which animation should be playing
selectAnimation(); selectAnimation();
// advance the animation cycle/s by the correct amount/s // advance the animation cycle/s by the correct amount/s
advanceAnimations(); advanceAnimations();
// update the progress of any live transitions // update the progress of any live transitions
updateTransitions(); updateTransitions();
// apply translation and rotations // apply translation and rotations
renderMotion(); renderMotion();
// save this frame's parameters // save this frame's parameters
motion.saveHistory(); motion.saveHistory();
} }
}); });
// helper function for selectAnimation() // helper function for selectAnimation()
function setTransition(nextAnimation, playTransitionReachPoses) { function setTransition(nextAnimation, playTransitionReachPoses) {
var lastTransition = motion.currentTransition; var lastTransition = motion.currentTransition;
var lastAnimation = avatar.currentAnimation; var lastAnimation = avatar.currentAnimation;
// if already transitioning from a blended walk need to maintain the previous walk's direction // if already transitioning from a blended walk need to maintain the previous walk's direction
if (lastAnimation.lastDirection) { if (lastAnimation.lastDirection) {
switch(lastAnimation.lastDirection) { switch(lastAnimation.lastDirection) {
case FORWARDS: case FORWARDS:
lastAnimation = avatar.selectedWalk; lastAnimation = avatar.selectedWalk;
break; break;
case BACKWARDS: case BACKWARDS:
lastAnimation = avatar.selectedWalkBackwards; lastAnimation = avatar.selectedWalkBackwards;
break; break;
case LEFT: case LEFT:
lastAnimation = avatar.selectedSideStepLeft; lastAnimation = avatar.selectedSideStepLeft;
break; break;
case RIGHT: case RIGHT:
lastAnimation = avatar.selectedSideStepRight; lastAnimation = avatar.selectedSideStepRight;
break; break;
} }
} }
motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses);
avatar.currentAnimation = nextAnimation; avatar.currentAnimation = nextAnimation;
// reset default first footstep // reset default first footstep
if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) { if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) {
avatar.nextStep = RIGHT; avatar.nextStep = RIGHT;
} }
} }
// fly animation blending: smoothing / damping filters // fly animation blending: smoothing / damping filters
const FLY_BLEND_DAMPING = 50; const FLY_BLEND_DAMPING = 50;
var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
// select / blend the appropriate animation for the current state of motion // select / blend the appropriate animation for the current state of motion
function selectAnimation() { function selectAnimation() {
var playTransitionReachPoses = true; var playTransitionReachPoses = true;
// select appropriate animation. create transitions where appropriate // select appropriate animation. create transitions where appropriate
switch (motion.nextState) { switch (motion.nextState) {
case STATIC: { case STATIC: {
if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD &&
avatar.currentAnimation !== avatar.selectedIdle) { avatar.currentAnimation !== avatar.selectedIdle) {
setTransition(avatar.selectedIdle, playTransitionReachPoses); setTransition(avatar.selectedIdle, playTransitionReachPoses);
} else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) &&
avatar.currentAnimation !== avatar.selectedHover) { avatar.currentAnimation !== avatar.selectedHover) {
setTransition(avatar.selectedHover, playTransitionReachPoses); setTransition(avatar.selectedHover, playTransitionReachPoses);
} }
motion.state = STATIC; motion.state = STATIC;
avatar.selectedWalkBlend.lastDirection = NONE; avatar.selectedWalkBlend.lastDirection = NONE;
break; break;
} }
case SURFACE_MOTION: { case SURFACE_MOTION: {
// walk transition reach poses are currently only specified for starting to walk forwards // walk transition reach poses are currently only specified for starting to walk forwards
playTransitionReachPoses = (motion.direction === FORWARDS); playTransitionReachPoses = (motion.direction === FORWARDS);
var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend);
switch (motion.direction) { switch (motion.direction) {
case FORWARDS: case FORWARDS:
if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) {
animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend);
avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength;
} }
avatar.selectedWalkBlend.lastDirection = FORWARDS; avatar.selectedWalkBlend.lastDirection = FORWARDS;
break; break;
case BACKWARDS: case BACKWARDS:
if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) {
animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend);
avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength;
} }
avatar.selectedWalkBlend.lastDirection = BACKWARDS; avatar.selectedWalkBlend.lastDirection = BACKWARDS;
break; break;
case LEFT: case LEFT:
animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend);
avatar.selectedWalkBlend.lastDirection = LEFT; avatar.selectedWalkBlend.lastDirection = LEFT;
avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength;
break break
case RIGHT: case RIGHT:
animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend);
avatar.selectedWalkBlend.lastDirection = RIGHT; avatar.selectedWalkBlend.lastDirection = RIGHT;
avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength;
break; break;
default: default:
// condition occurs when the avi goes through the floor due to collision hull errors // condition occurs when the avi goes through the floor due to collision hull errors
animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend);
avatar.selectedWalkBlend.lastDirection = FORWARDS; avatar.selectedWalkBlend.lastDirection = FORWARDS;
avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength;
break; break;
} }
if (!isAlreadyWalking && !motion.isComingToHalt) { if (!isAlreadyWalking && !motion.isComingToHalt) {
setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); setTransition(avatar.selectedWalkBlend, playTransitionReachPoses);
} }
motion.state = SURFACE_MOTION; motion.state = SURFACE_MOTION;
break; break;
} }
case AIR_MOTION: { case AIR_MOTION: {
// blend the up, down, forward and backward flying animations relative to motion speed and direction // blend the up, down, forward and backward flying animations relative to motion speed and direction
animationOperations.zeroAnimation(avatar.selectedFlyBlend); animationOperations.zeroAnimation(avatar.selectedFlyBlend);
// calculate influences based on velocity and direction // calculate influences based on velocity and direction
var velocityMagnitude = Vec3.length(motion.velocity); var velocityMagnitude = Vec3.length(motion.velocity);
var verticalProportion = motion.velocity.y / velocityMagnitude; var verticalProportion = motion.velocity.y / velocityMagnitude;
var thrustProportion = motion.velocity.z / velocityMagnitude / 2; var thrustProportion = motion.velocity.z / velocityMagnitude / 2;
// directional components // directional components
var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; var upComponent = motion.velocity.y > 0 ? verticalProportion : 0;
var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0;
var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0;
var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0;
// smooth / damp directional components to add visual 'weight' // smooth / damp directional components to add visual 'weight'
upComponent = flyUpFilter.process(upComponent); upComponent = flyUpFilter.process(upComponent);
downComponent = flyDownFilter.process(downComponent); downComponent = flyDownFilter.process(downComponent);
forwardComponent = flyForwardFilter.process(forwardComponent); forwardComponent = flyForwardFilter.process(forwardComponent);
backwardComponent = flyBackwardFilter.process(backwardComponent); backwardComponent = flyBackwardFilter.process(backwardComponent);
// normalise directional components // normalise directional components
var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; var normaliser = upComponent + downComponent + forwardComponent + backwardComponent;
upComponent = upComponent / normaliser; upComponent = upComponent / normaliser;
downComponent = downComponent / normaliser; downComponent = downComponent / normaliser;
forwardComponent = forwardComponent / normaliser; forwardComponent = forwardComponent / normaliser;
backwardComponent = backwardComponent / normaliser; backwardComponent = backwardComponent / normaliser;
// blend animations proportionally // blend animations proportionally
if (upComponent > 0) { if (upComponent > 0) {
animationOperations.blendAnimation(avatar.selectedFlyUp, animationOperations.blendAnimation(avatar.selectedFlyUp,
avatar.selectedFlyBlend, avatar.selectedFlyBlend,
upComponent); upComponent);
} }
if (downComponent > 0) { if (downComponent > 0) {
animationOperations.blendAnimation(avatar.selectedFlyDown, animationOperations.blendAnimation(avatar.selectedFlyDown,
avatar.selectedFlyBlend, avatar.selectedFlyBlend,
downComponent); downComponent);
} }
if (forwardComponent > 0) { if (forwardComponent > 0) {
animationOperations.blendAnimation(avatar.selectedFly, animationOperations.blendAnimation(avatar.selectedFly,
avatar.selectedFlyBlend, avatar.selectedFlyBlend,
Math.abs(forwardComponent)); Math.abs(forwardComponent));
} }
if (backwardComponent > 0) { if (backwardComponent > 0) {
animationOperations.blendAnimation(avatar.selectedFlyBackwards, animationOperations.blendAnimation(avatar.selectedFlyBackwards,
avatar.selectedFlyBlend, avatar.selectedFlyBlend,
Math.abs(backwardComponent)); Math.abs(backwardComponent));
} }
if (avatar.currentAnimation !== avatar.selectedFlyBlend) { if (avatar.currentAnimation !== avatar.selectedFlyBlend) {
setTransition(avatar.selectedFlyBlend, playTransitionReachPoses); setTransition(avatar.selectedFlyBlend, playTransitionReachPoses);
} }
motion.state = AIR_MOTION; motion.state = AIR_MOTION;
avatar.selectedWalkBlend.lastDirection = NONE; avatar.selectedWalkBlend.lastDirection = NONE;
break; break;
} }
} // end switch next state of motion } // end switch next state of motion
} }
// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions // determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions
function advanceAnimations() { function advanceAnimations() {
var wheelAdvance = 0; var wheelAdvance = 0;
// turn the frequency time wheel // turn the frequency time wheel
if (avatar.currentAnimation === avatar.selectedWalkBlend) { if (avatar.currentAnimation === avatar.selectedWalkBlend) {
// Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach // Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach
// wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed
// omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length // omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length
var speed = Vec3.length(motion.velocity); var speed = Vec3.length(motion.velocity);
motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI; motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI;
var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius; var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius;
// calculate the degrees turned (at this angular speed) since last frame // calculate the degrees turned (at this angular speed) since last frame
wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity);
} else { } else {
// turn the frequency time wheel by the amount specified for this animation // turn the frequency time wheel by the amount specified for this animation
wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime);
} }
if (motion.currentTransition !== nullTransition) { if (motion.currentTransition !== nullTransition) {
// the last animation is still playing so we turn it's frequency time wheel to maintain the animation // the last animation is still playing so we turn it's frequency time wheel to maintain the animation
if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) { if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) {
// if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition // if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition
var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1; var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1;
if ((motion.currentTransition.lastFrequencyTimeWheelPos > if ((motion.currentTransition.lastFrequencyTimeWheelPos >
(motion.currentTransition.stopAngle - tolerance)) && (motion.currentTransition.stopAngle - tolerance)) &&
(motion.currentTransition.lastFrequencyTimeWheelPos < (motion.currentTransition.lastFrequencyTimeWheelPos <
(motion.currentTransition.stopAngle + tolerance))) { (motion.currentTransition.stopAngle + tolerance))) {
motion.currentTransition.lastFrequencyTimeIncrement = 0; motion.currentTransition.lastFrequencyTimeIncrement = 0;
} }
} }
motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime);
} }
// avoid unnaturally fast walking when landing at speed - simulates skimming / skidding // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding
if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) {
wheelAdvance = 0; wheelAdvance = 0;
} }
// advance the walk wheel the appropriate amount // advance the walk wheel the appropriate amount
motion.advanceFrequencyTimeWheel(wheelAdvance); motion.advanceFrequencyTimeWheel(wheelAdvance);
// walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed)
const ALMOST_ONE = 0.97; const ALMOST_ONE = 0.97;
if (avatar.currentAnimation === avatar.selectedWalkBlend && if (avatar.currentAnimation === avatar.selectedWalkBlend &&
(Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) {
var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt;
const TOLERANCE = 1.0; const TOLERANCE = 1.0;
if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) && if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) &&
motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) && motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) &&
motion.currentTransition === nullTransition) { motion.currentTransition === nullTransition) {
// measure and save stride length // measure and save stride length
var footRPos = MyAvatar.getJointPosition("RightFoot"); var footRPos = MyAvatar.getJointPosition("RightFoot");
var footLPos = MyAvatar.getJointPosition("LeftFoot"); var footLPos = MyAvatar.getJointPosition("LeftFoot");
avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos); avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos);
avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength; avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength;
} else { } else {
// use the previously saved value for stride length // use the previously saved value for stride length
avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength; avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength;
} }
} // end get walk stride length } // end get walk stride length
} }
// initialise a new transition. update progress of a live transition // initialise a new transition. update progress of a live transition
function updateTransitions() { function updateTransitions() {
if (motion.currentTransition !== nullTransition) { if (motion.currentTransition !== nullTransition) {
// is this a new transition? // is this a new transition?
if (motion.currentTransition.progress === 0) { if (motion.currentTransition.progress === 0) {
// do we have overlapping transitions? // do we have overlapping transitions?
if (motion.currentTransition.lastTransition !== nullTransition) { if (motion.currentTransition.lastTransition !== nullTransition) {
// is the last animation for the nested transition the same as the new animation? // is the last animation for the nested transition the same as the new animation?
if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) { if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) {
// then sync the nested transition's frequency time wheel for a smooth animation blend // then sync the nested transition's frequency time wheel for a smooth animation blend
motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos; motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos;
} }
} }
} }
if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) { if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) {
motion.currentTransition = nullTransition; motion.currentTransition = nullTransition;
} }
} }
} }
// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity // helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity
var leanPitchSmoothingFilter = filter.createButterworthFilter(); var leanPitchSmoothingFilter = filter.createButterworthFilter();
function getLeanPitch() { function getLeanPitch() {
var leanProgress = 0; var leanProgress = 0;
if (motion.direction === DOWN || if (motion.direction === DOWN ||
motion.direction === FORWARDS || motion.direction === FORWARDS ||
motion.direction === BACKWARDS) { motion.direction === BACKWARDS) {
leanProgress = -motion.velocity.z / TOP_SPEED; leanProgress = -motion.velocity.z / TOP_SPEED;
} }
// use filters to shape the walking acceleration response // use filters to shape the walking acceleration response
leanProgress = leanPitchSmoothingFilter.process(leanProgress); leanProgress = leanPitchSmoothingFilter.process(leanProgress);
return PITCH_MAX * leanProgress; return PITCH_MAX * leanProgress;
} }
// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning // helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning
var leanRollSmoothingFilter = filter.createButterworthFilter(); var leanRollSmoothingFilter = filter.createButterworthFilter();
function getLeanRoll() { function getLeanRoll() {
var leanRollProgress = 0; var leanRollProgress = 0;
var linearContribution = 0; var linearContribution = 0;
const LOG_SCALER = 8; const LOG_SCALER = 8;
if (Vec3.length(motion.velocity) > 0) { if (Vec3.length(motion.velocity) > 0) {
linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER;
} }
var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX; var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX;
leanRollProgress = linearContribution; leanRollProgress = linearContribution;
leanRollProgress *= angularContribution; leanRollProgress *= angularContribution;
// shape the response curve // shape the response curve
leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0});
// which way to lean? // which way to lean?
var turnSign = (motion.yawDelta >= 0) ? 1 : -1; var turnSign = (motion.yawDelta >= 0) ? 1 : -1;
if (motion.direction === BACKWARDS || if (motion.direction === BACKWARDS ||
motion.direction === LEFT) { motion.direction === LEFT) {
turnSign *= -1; turnSign *= -1;
} }
// filter progress // filter progress
leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress); leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress);
return ROLL_MAX * leanRollProgress; return ROLL_MAX * leanRollProgress;
} }
// animate the avatar using sine waves, geometric waveforms and harmonic generators // animate the avatar using sine waves, geometric waveforms and harmonic generators
function renderMotion() { function renderMotion() {
// leaning in response to speed and acceleration // leaning in response to speed and acceleration
var leanPitch = motion.state === STATIC ? 0 : getLeanPitch(); var leanPitch = motion.state === STATIC ? 0 : getLeanPitch();
var leanRoll = motion.state === STATIC ? 0 : getLeanRoll(); var leanRoll = motion.state === STATIC ? 0 : getLeanRoll();
var lastDirection = motion.lastDirection; var lastDirection = motion.lastDirection;
// hips translations from currently playing animations // hips translations from currently playing animations
var hipsTranslations = {x:0, y:0, z:0}; var hipsTranslations = {x:0, y:0, z:0};
if (motion.currentTransition !== nullTransition) { if (motion.currentTransition !== nullTransition) {
// maintain previous direction when transitioning from a walk // maintain previous direction when transitioning from a walk
if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) {
motion.lastDirection = motion.currentTransition.lastDirection; motion.lastDirection = motion.currentTransition.lastDirection;
} }
hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos, hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos,
motion.lastDirection); motion.lastDirection);
} else { } else {
hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation, hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation,
motion.frequencyTimeWheelPos, motion.frequencyTimeWheelPos,
motion.direction); motion.direction);
} }
// factor any leaning into the hips offset // factor any leaning into the hips offset
hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch));
hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll));
// ensure skeleton offsets are within the 1m limit // ensure skeleton offsets are within the 1m limit
hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x;
hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x;
hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y; hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y;
hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y; hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y;
hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z; hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z;
hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z; hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z;
// apply translations // apply translations
MyAvatar.setSkeletonOffset(hipsTranslations); MyAvatar.setSkeletonOffset(hipsTranslations);
// play footfall sound? // play footfall sound?
var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds;
if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) {
if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend ||
motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) {
producingFootstepSounds = true; producingFootstepSounds = true;
} }
} }
if (producingFootstepSounds) { if (producingFootstepSounds) {
const QUARTER_CYCLE = 90; const QUARTER_CYCLE = 90;
const THREE_QUARTER_CYCLE = 270; const THREE_QUARTER_CYCLE = 270;
var ftWheelPosition = motion.frequencyTimeWheelPos; var ftWheelPosition = motion.frequencyTimeWheelPos;
if (motion.currentTransition !== nullTransition && if (motion.currentTransition !== nullTransition &&
motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) {
ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos;
} }
if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) { if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) {
avatar.makeFootStepSound(); avatar.makeFootStepSound();
} else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) { } else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) {
avatar.makeFootStepSound(); avatar.makeFootStepSound();
} }
} }
// apply joint rotations // apply joint rotations
for (jointName in avatar.currentAnimation.joints) { for (jointName in avatar.currentAnimation.joints) {
var joint = walkAssets.animationReference.joints[jointName]; var joint = walkAssets.animationReference.joints[jointName];
var jointRotations = undefined; var jointRotations = undefined;
// ignore arms / head rotations if options are selected in the settings // ignore arms / head rotations if options are selected in the settings
if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) {
continue; continue;
} }
if (avatar.headFree && joint.IKChain === "Head") { if (avatar.headFree && joint.IKChain === "Head") {
continue; continue;
} }
// if there's a live transition, blend the rotations with the last animation's rotations // if there's a live transition, blend the rotations with the last animation's rotations
if (motion.currentTransition !== nullTransition) { if (motion.currentTransition !== nullTransition) {
jointRotations = motion.currentTransition.blendRotations(jointName, jointRotations = motion.currentTransition.blendRotations(jointName,
motion.frequencyTimeWheelPos, motion.frequencyTimeWheelPos,
motion.lastDirection); motion.lastDirection);
} else { } else {
jointRotations = animationOperations.calculateRotations(jointName, jointRotations = animationOperations.calculateRotations(jointName,
avatar.currentAnimation, avatar.currentAnimation,
motion.frequencyTimeWheelPos, motion.frequencyTimeWheelPos,
motion.direction); motion.direction);
} }
// apply angular velocity and speed induced leaning // apply angular velocity and speed induced leaning
if (jointName === "Hips") { if (jointName === "Hips") {
jointRotations.x += leanPitch; jointRotations.x += leanPitch;
jointRotations.z += leanRoll; jointRotations.z += leanRoll;
} }
// apply rotations // apply rotations
MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations)); MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations));
} }
} }

View file

@ -1,334 +1,334 @@
display_width 800 display_width 800
max_init_image_width 800 max_init_image_width 800
max_work_image_width 384 max_work_image_width 384
fast_image_resize 1 fast_image_resize 1
camera_input 0 camera_input 0
camera_device 0 camera_device 0
camera_width 800 camera_width 800
camera_height 600 camera_height 600
camera_frame_rate 30 camera_frame_rate 30
camera_mirror 1 camera_mirror 1
camera_settings_dialog 0 camera_settings_dialog 0
camera_auto_settings 0 camera_auto_settings 0
video_file_sync 1 video_file_sync 1
automatic_initialisation 1 automatic_initialisation 1
init_yaw_threshold 0.005 init_yaw_threshold 0.005
init_roll_threshold 10 init_roll_threshold 10
init_velocity_threshold 0.015 init_velocity_threshold 0.015
init_timeout 1000 init_timeout 1000
init_timeout_enable 6 init_timeout_enable 6
init_display_status 1 init_display_status 1
recovery_timeout 800 recovery_timeout 800
display_video 1 display_video 1
display_model_texture 0 display_model_texture 0
display_tri_mask 0 display_tri_mask 0
display_model_wireframe 0 display_model_wireframe 0
display_results 1 display_results 1
display_track_points 0 display_track_points 0
detect_strip_area_threshold 1000 detect_strip_area_threshold 1000
detect_strip_angle_threshold 0.15 detect_strip_angle_threshold 0.15
detect_strip_ratio_threshold 0.2 detect_strip_ratio_threshold 0.2
detect_strip_perfect_ratio 6.848 detect_strip_perfect_ratio 6.848
detect_strip_roi_y_offset 0 detect_strip_roi_y_offset 0
detect_strip_roi_width 2 detect_strip_roi_width 2
detect_strip_roi_height 4 detect_strip_roi_height 4
smoothing_factors smoothing_factors
5 25 -2 100 -1 50 25 0 5 25 -2 100 -1 50 25 0
#translation rotation action_units eyebrows mouth gaze eye_closure other #translation rotation action_units eyebrows mouth gaze eye_closure other
process_eyes 1 process_eyes 1
leye_closing_au 12 leye_closing_au 12
reye_closing_au 12 reye_closing_au 12
eye_h_rotation_au 15 eye_h_rotation_au 15
eye_v_rotation_au 16 eye_v_rotation_au 16
eye_points_coords eye_points_coords
162 1.0 0.0 0.0 162 1.0 0.0 0.0
157 0.0 0.0 1.0 157 0.0 0.0 1.0
bdts_points_use bdts_points_use
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
#3.5 3.6 3.7 3.8 3.11 3.12 8.1 8.2 8.3 8.4 9.1 9.2 9.3 4.1 4.2 4.3 4.4 4.5 4.6 2.1 #3.5 3.6 3.7 3.8 3.11 3.12 8.1 8.2 8.3 8.4 9.1 9.2 9.3 4.1 4.2 4.3 4.4 4.5 4.6 2.1
bdts_points_angle bdts_points_angle
0 0 20 -20 20 -20 0 0 20 -20 20 -20 0 25 -25 20 -20 20 -20 0 0 0 0 20 -20 20 -20 0 0 20 -20 20 -20 0 25 -25 20 -20 20 -20 0 0
model_filename candide3-exp.wfm model_filename candide3-exp.wfm
fdp_filename candide3.fdp fdp_filename candide3.fdp
bdts_data_path bdtsdata bdts_data_path bdtsdata
au_use au_use
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
#AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23 #AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
au_names au_names
au_nose_wrinkler au_nose_wrinkler
au_jaw_z_push au_jaw_z_push
au_jaw_x_push au_jaw_x_push
au_jaw_drop au_jaw_drop
au_lower_lip_drop au_lower_lip_drop
au_upper_lip_raiser au_upper_lip_raiser
au_lip_stretcher_left au_lip_stretcher_left
au_lip_corner_depressor au_lip_corner_depressor
au_lip_presser au_lip_presser
au_left_outer_brow_raiser au_left_outer_brow_raiser
au_left_inner_brow_raiser au_left_inner_brow_raiser
au_left_brow_lowerer au_left_brow_lowerer
au_leye_closed au_leye_closed
au_lid_tightener au_lid_tightener
au_upper_lid_raiser au_upper_lid_raiser
au_rotate_eyes_left au_rotate_eyes_left
au_rotate_eyes_down au_rotate_eyes_down
au_lower_lip_x_push au_lower_lip_x_push
au_lip_stretcher_right au_lip_stretcher_right
au_right_outer_brow_raiser au_right_outer_brow_raiser
au_right_inner_brow_raiser au_right_inner_brow_raiser
au_right_brow_lowerer au_right_brow_lowerer
au_reye_closed au_reye_closed
ekf_sensitivity ekf_sensitivity
100 100 100 100 100 100 100 100 100 100 100 200 200 100 100 400 400 100 100 100 100 300 300 100 100 400 400 100 100 100 100 100 100 100 100 100 100 100 100 100 200 200 100 100 400 400 100 100 100 100 300 300 100 100 400 400 100 100
#x y z rx ry rz AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23 #x y z rx ry rz AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
au_gravity au_gravity
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
#AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23 #AU1 AU2 AU3 AU4 AU5 AU6 AU7 AU8 AU9 AU10 AU11 AU12 AU13 AU14 AU15 AU16 AU17 AU18 AU19 AU20 AU21 AU22 AU23
gravity_threshold 0.0 gravity_threshold 0.0
camera_focus 3 camera_focus 3
tex_size 512 tex_size 512
ROI_num 14 ROI_num 14
#ROI 0 - nose region (setting default values) #ROI 0 - nose region (setting default values)
feature_points_num[0] 7 feature_points_num[0] 7
feature_points_tri_use_num[0] 21 feature_points_tri_use_num[0] 21
feature_points_tri_use_list[0] feature_points_tri_use_list[0]
48 154 54 55 152 45 46 47 103 109 48 154 54 55 152 45 46 47 103 109
108 107 106 101 104 110 111 105 99 102 108 107 106 101 104 110 111 105 99 102
100 100
bound_rect_modifiers[0] -10 -10 -20 10 bound_rect_modifiers[0] -10 -10 -20 10
feature_points_min_distance[0] 0.78125 feature_points_min_distance[0] 0.78125
feature_point_block_size[0] 0.46875 feature_point_block_size[0] 0.46875
search_range[0] 4.0625 4.0625 search_range[0] 4.0625 4.0625
refine_range[0] 0.3125 0.3125 refine_range[0] 0.3125 0.3125
patch_size[0] 4.6875 patch_size[0] 4.6875
match_method[0] 5 match_method[0] 5
bad_match_threshold[0] 0.35 bad_match_threshold[0] 0.35
sensitivity_falloff[0] 10 sensitivity_falloff[0] 10
init_angle[0] 0 init_angle[0] 0
feature_points_coords[0] feature_points_coords[0]
97 0.18 0.54 0.28 97 0.18 0.54 0.28
90 0.18 0.28 0.54 90 0.18 0.28 0.54
51 0.76 0.09 0.15 51 0.76 0.09 0.15
97 0.36 0.10 0.54 97 0.36 0.10 0.54
90 0.36 0.54 0.10 90 0.36 0.54 0.10
69 0.55 0.10 0.35 69 0.55 0.10 0.35
67 0.55 0.35 0.10 67 0.55 0.35 0.10
#ROI 1 - left eyebrow region #ROI 1 - left eyebrow region
feature_points_num[1] 4 feature_points_num[1] 4
feature_points_tri_use_num[1] 2 feature_points_tri_use_num[1] 2
feature_points_tri_use_list[1] feature_points_tri_use_list[1]
25 26 25 26
bound_rect_modifiers[1] 2 2 40 2 bound_rect_modifiers[1] 2 2 40 2
feature_points_coords[1] feature_points_coords[1]
25 0.0 0.0 1.0 25 0.0 0.0 1.0
26 0.15 0.1 0.75 26 0.15 0.1 0.75
25 1.0 0.0 0.0 25 1.0 0.0 0.0
26 0.2 0.4 0.4 26 0.2 0.4 0.4
#ROI 2 - right eyebrow region #ROI 2 - right eyebrow region
feature_points_num[2] 4 feature_points_num[2] 4
feature_points_tri_use_num[2] 2 feature_points_tri_use_num[2] 2
feature_points_tri_use_list[2] feature_points_tri_use_list[2]
33 34 33 34
bound_rect_modifiers[2] 2 2 40 2 bound_rect_modifiers[2] 2 2 40 2
feature_points_coords[2] feature_points_coords[2]
33 0.15 0.75 0.1 33 0.15 0.75 0.1
34 1.0 0.0 0.0 34 1.0 0.0 0.0
33 0.0 0.0 1.0 33 0.0 0.0 1.0
33 0.2 0.4 0.4 33 0.2 0.4 0.4
#ROI 3 - left outer eye corner region #ROI 3 - left outer eye corner region
feature_points_num[3] 3 feature_points_num[3] 3
feature_points_tri_use_num[3] 4 feature_points_tri_use_num[3] 4
feature_points_tri_use_list[3] feature_points_tri_use_list[3]
112 23 39 115 112 23 39 115
bound_rect_modifiers[3] -5 -5 -25 -25 bound_rect_modifiers[3] -5 -5 -25 -25
feature_points_coords[3] feature_points_coords[3]
23 0 0.2 0.8 23 0 0.2 0.8
119 0.8351877 0.08414026 0.08067206 119 0.8351877 0.08414026 0.08067206
116 0.3218788 0.4626164 0.2155048 116 0.3218788 0.4626164 0.2155048
#ROI 4 - right outer eye corner region #ROI 4 - right outer eye corner region
feature_points_num[4] 3 feature_points_num[4] 3
feature_points_tri_use_num[4] 4 feature_points_tri_use_num[4] 4
feature_points_tri_use_list[4] feature_points_tri_use_list[4]
142 36 42 145 142 36 42 145
bound_rect_modifiers[4] -5 -5 -25 -25 bound_rect_modifiers[4] -5 -5 -25 -25
feature_points_coords[4] feature_points_coords[4]
36 0 0.8 0.2 36 0 0.8 0.2
151 0.8566859 0.0405132 0.1028009 151 0.8566859 0.0405132 0.1028009
146 0.2871178 0.3467231 0.366159 146 0.2871178 0.3467231 0.366159
#ROI 5 - left inner eye corner region #ROI 5 - left inner eye corner region
feature_points_num[5] 3 feature_points_num[5] 3
feature_points_tri_use_num[5] 5 feature_points_tri_use_num[5] 5
feature_points_tri_use_list[5] feature_points_tri_use_list[5]
122 28 99 100 125 122 28 99 100 125
bound_rect_modifiers[5] -5 -5 -25 -40 bound_rect_modifiers[5] -5 -5 -25 -40
feature_points_coords[5] feature_points_coords[5]
99 0.2 0.1 0.7 99 0.2 0.1 0.7
122 0.2664618 0.3707059 0.3628323 122 0.2664618 0.3707059 0.3628323
125 0.387767 0.4655813 0.1466517 125 0.387767 0.4655813 0.1466517
#ROI 6 - right inner eye corner region #ROI 6 - right inner eye corner region
feature_points_num[6] 3 feature_points_num[6] 3
feature_points_tri_use_num[6] 5 feature_points_tri_use_num[6] 5
feature_points_tri_use_list[6] feature_points_tri_use_list[6]
132 31 102 104 135 132 31 102 104 135
bound_rect_modifiers[6] -5 -5 -25 -40 bound_rect_modifiers[6] -5 -5 -25 -40
feature_points_coords[6] feature_points_coords[6]
102 0.2 0.7 0.1 102 0.2 0.7 0.1
132 0.3673472 0.2426805 0.3899724 132 0.3673472 0.2426805 0.3899724
135 0.2833096 0.1345753 0.5821151 135 0.2833096 0.1345753 0.5821151
#ROI 7 - lower lip region #ROI 7 - lower lip region
feature_points_num[7] 6 feature_points_num[7] 6
feature_points_tri_use_num[7] 6 feature_points_tri_use_num[7] 6
feature_points_tri_use_list[7] feature_points_tri_use_list[7]
79 80 82 84 52 53 79 80 82 84 52 53
bound_rect_modifiers[7] 0 0 0 -80 bound_rect_modifiers[7] 0 0 0 -80
refine_range[7] 0.5 1 refine_range[7] 0.5 1
patch_size[7] 7 patch_size[7] 7
feature_points_coords[7] feature_points_coords[7]
80 0.0 0.0 1.0 80 0.0 0.0 1.0
80 1.0 0.0 0.0 80 1.0 0.0 0.0
80 0.0 1.0 0.0 80 0.0 1.0 0.0
79 0.0 0.0 1.0 79 0.0 0.0 1.0
82 0.1 0.3 0.6 82 0.1 0.3 0.6
84 0.1 0.6 0.3 84 0.1 0.6 0.3
#ROI 8 - upper lip region #ROI 8 - upper lip region
feature_points_num[8] 6 feature_points_num[8] 6
feature_points_tri_use_num[8] 10 feature_points_tri_use_num[8] 10
feature_points_tri_use_list[8] feature_points_tri_use_list[8]
69 49 155 51 50 153 44 67 57 60 69 49 155 51 50 153 44 67 57 60
bound_rect_modifiers[8] 0 0 -70 0 bound_rect_modifiers[8] 0 0 -70 0
refine_range[8] 0.5 1 refine_range[8] 0.5 1
patch_size[8] 7 patch_size[8] 7
feature_points_coords[8] feature_points_coords[8]
67 0.1 0.45 0.45 67 0.1 0.45 0.45
69 0.1 0.45 0.45 69 0.1 0.45 0.45
57 0.0 0.0 1.0 57 0.0 0.0 1.0
60 0.0 1.0 0.0 60 0.0 1.0 0.0
51 0.0 1.0 0.0 51 0.0 1.0 0.0
51 0.3 0.7 0.0 51 0.3 0.7 0.0
#ROI 9 - left lip corner region #ROI 9 - left lip corner region
feature_points_num[9] 4 feature_points_num[9] 4
feature_points_tri_use_num[9] 4 feature_points_tri_use_num[9] 4
feature_points_tri_use_list[9] feature_points_tri_use_list[9]
87 89 81 68 87 89 81 68
bound_rect_modifiers[9] 0 0 -35 -35 bound_rect_modifiers[9] 0 0 -35 -35
refine_range[9] 1 1 refine_range[9] 1 1
patch_size[9] 7 patch_size[9] 7
feature_points_coords[9] feature_points_coords[9]
87 0.0 0.0 1.0 87 0.0 0.0 1.0
87 0.2 0.0 0.8 87 0.2 0.0 0.8
66 0.33 0.33 0.34 66 0.33 0.33 0.34
72 0.33 0.33 0.34 72 0.33 0.33 0.34
#ROI 10 - right lip corner region #ROI 10 - right lip corner region
feature_points_num[10] 4 feature_points_num[10] 4
feature_points_tri_use_num[10] 4 feature_points_tri_use_num[10] 4
feature_points_tri_use_list[10] feature_points_tri_use_list[10]
94 96 83 70 94 96 83 70
bound_rect_modifiers[10] 0 0 -35 -35 bound_rect_modifiers[10] 0 0 -35 -35
refine_range[10] 1 1 refine_range[10] 1 1
patch_size[10] 7 patch_size[10] 7
feature_points_coords[10] feature_points_coords[10]
94 0.0 1.0 0.0 94 0.0 1.0 0.0
94 0.2 0.8 0.0 94 0.2 0.8 0.0
64 0.33 0.33 0.34 64 0.33 0.33 0.34
78 0.33 0.33 0.34 78 0.33 0.33 0.34
#ROI 11 - jaw region #ROI 11 - jaw region
feature_points_num[11] 4 feature_points_num[11] 4
feature_points_tri_use_num[11] 2 feature_points_tri_use_num[11] 2
feature_points_tri_use_list[11] feature_points_tri_use_list[11]
52 53 52 53
bound_rect_modifiers[11] 0 0 -30 0 bound_rect_modifiers[11] 0 0 -30 0
refine_range[11] 0.5 1 refine_range[11] 0.5 1
patch_size[11] 7 patch_size[11] 7
bad_match_threshold[11] 0.6 bad_match_threshold[11] 0.6
feature_points_coords[11] feature_points_coords[11]
52 0.4 0.3 0.3 52 0.4 0.3 0.3
53 0.4 0.3 0.3 53 0.4 0.3 0.3
87 0.0 0.5 0.5 87 0.0 0.5 0.5
94 0.0 0.5 0.5 94 0.0 0.5 0.5
feature_points_num[12] 6 feature_points_num[12] 6
feature_points_tri_use_num[12] 3 feature_points_tri_use_num[12] 3
feature_points_tri_use_list[12] feature_points_tri_use_list[12]
188 189 190 191 188 189 190 191
bound_rect_modifiers[12] -30 0 0 -30 bound_rect_modifiers[12] -30 0 0 -30
init_angle[12] -20 init_angle[12] -20
feature_points_num[13] 6 feature_points_num[13] 6
feature_points_tri_use_num[13] 3 feature_points_tri_use_num[13] 3
feature_points_tri_use_list[13] feature_points_tri_use_list[13]
192 193 194 195 192 193 194 195
bound_rect_modifiers[13] 0 -30 0 -30 bound_rect_modifiers[13] 0 -30 0 -30
init_angle[13] 20 init_angle[13] 20
recovery_frames 4 recovery_frames 4
global_bad_match_threshold 0.5 global_bad_match_threshold 0.5
visibility_check 1 visibility_check 1
rotation_limit rotation_limit
-1.570796 1.570796 -1.570796 1.570796
1.570796 4.712389 1.570796 4.712389
-3.2 3.2 -3.2 3.2
translation_limit translation_limit
-4 4 -4 4
-3 3 -3 3
0 11 0 11
action_unit_limit action_unit_limit
-0.5 0.5 -0.5 0.5
-0.5 0.5 -0.5 0.5
-1.0 1.0 -1.0 1.0
-0.05 1.2 -0.05 1.2
-0.05 1.5 -0.05 1.5
-0.05 1.5 -0.05 1.5
-1.0 1.0 -1.0 1.0
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-1.5 2 -1.5 2
-1.5 2 -1.5 2
-1 1.5 -1 1.5
-2.8 2.8 -2.8 2.8
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-100 100 -100 100
-100 100 -100 100
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-1.5 1.5 -1.5 1.5
-2.8 2.8 -2.8 2.8