LabanotationSuite/MSRAbotSimulation/js/app.js

567 строки
18 KiB
JavaScript

//--------------------------------------------------------------------------------------------
// Copyright(c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// --------------------------------------------------------------------------------------------
'use strict';
var _app = null;
//--------------------------------------------------------------------------------------------
var APP = function (domTarget)
{
this.self = this;
this.container = domTarget;
this.clock = null;
this.renderer = null;
this.scene = null;
this.camera = null;
this.enableStats = false;
this.stats = null;
this.nativeWidth = 0;
this.nativeHeight = 0;
this.screenWidth = window.innerWidth;
this.screenHeight = window.innerHeight;
this.hiding = null;
this.eventDoneInit = null;
//
// objects & modules
this.msrabot = null;
this.labanotation = null;
//
// input events
this.mouse = new THREE.Vector3(0, 0, 0);
this.touches = [];
}
//--------------------------------------------------------------------------------------------
APP.prototype.constructor = APP;
//--------------------------------------------------------------------------------------------
APP.prototype.initialize = function initAPP()
{
this.setupRenderer();
this.setupDomEvents();
this.setupMiscellaneous();
this.createDebugLabels();
this.initializeScene();
//
// load default labanotation file
this.loadNewFile(this.params.gesture);
}
//--------------------------------------------------------------------------------------------
APP.prototype.setupRenderer = function ()
{
this.clock = new THREE.Clock();
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.screenWidth, this.screenHeight);
this.renderer.setClearColor(0x000080, 1);
this.renderer.shadowMap.enabled = true;
this.container.appendChild(this.renderer.domElement);
this.nativeWidth = this.renderer.domElement.clientWidth;
this.nativeHeight = this.renderer.domElement.clientHeight;
//
// stats
if (this.enableStats) {
this.stats = new Stats();
this.container.appendChild(this.stats.dom);
}
}
//--------------------------------------------------------------------------------------------
APP.prototype.setupDomEvents = function ()
{
window.addEventListener('resize', this.onWindowResize.bind(this), false);
document.addEventListener('keydown', this.onDocumentKeyDown.bind(this), false);
document.addEventListener('mousedown', this.onDocumentMouseDown.bind(this), false);
document.addEventListener('mousemove', this.onDocumentMouseMove.bind(this), false);
document.addEventListener('mouseup', this.onDocumentMouseUp.bind(this), false);
document.addEventListener('wheel', this.onDocumentMouseWheel.bind(this), false);
document.addEventListener('touchstart', this.onDocumentTouchStart.bind(this), false);
document.addEventListener('touchmove', this.onDocumentTouchMove.bind(this), false);
document.addEventListener('touchend', this.onDocumentTouchEnd.bind(this), false);
document.addEventListener('contextmenu', this.onContextMenu.bind(this), false);
}
//--------------------------------------------------------------------------------------------
APP.prototype.setupMiscellaneous = function ()
{
var scope = this;
//
// create form element to support uploading of local files
var form = document.createElement('form');
form.style.display = 'none';
document.body.appendChild(form);
this.fileInput = document.createElement('input');
this.fileInput.multiple = true;
this.fileInput.type = 'file';
this.fileInput.addEventListener('change', function () {
scope.importFile(scope.fileInput.files);
form.reset();
});
form.appendChild(this.fileInput);
//
// dat.GUI
var gui = new dat.GUI({ width: 400 });
var files = ['Ges01_wavehand', 'Ges02_balancinghands', 'Ges03_drawlines', 'Ges04_comehere', 'Ges05_demopoint', 'Ges06_chickenwing'];
var fileNames = [];
fileNames.push("-- Import/Upload JSON File --");
for (var i = 0; i < files.length; i++) {
fileNames.push(files[i] + ".naive");
fileNames.push(files[i] + ".total");
fileNames.push(files[i] + ".parallel");
}
this.params = {
gesture: fileNames[2],
animationSpeed: 1,
opacity: 0.4,
staticElbow: true,
showHelpers: false,
};
var folder = gui.addFolder('Labanotation');
folder.add(this.params, 'gesture', fileNames).onChange(function () {
if (scope.params.gesture == fileNames[0]) {
scope.fileInput.click();
} else
scope.loadNewFile(scope.params.gesture);
});
folder.add(this.params, 'animationSpeed', 0.0, 3.0).step(0.01).onChange(function () {
});
folder.open();
folder = gui.addFolder('MSRAbot');
folder.add(this.params, 'staticElbow').onChange(function () {
if (scope.msrabot)
scope.msrabot.setStaticElbow(scope.params.staticElbow);
});
folder.add(this.params, 'showHelpers').onChange(function () {
if (scope.msrabot)
scope.msrabot.setShowHelpers(scope.params.showHelpers);
});
folder.add(this.params, 'opacity', 0.0, 1.0).step(0.01).onChange(function () {
scope.changeMSRAbotOpacity(scope.params.opacity);
});
// folder.open();
}
//--------------------------------------------------------------------------------------------
APP.prototype.initializeScene = function ()
{
var scope = this;
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xf0f0f0);
this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
this.camera.position.set(0, 260, 600);
this.camera.lookAt(0, 160, 0);
this.scene.add(this.camera);
this.scene.add(new THREE.AmbientLight(0x707070));
//
// lights
{
var intensity = 1.5;
var distance = 0;
var angle = Math.PI / 4;
var penumbra = 0.5;
var shadow_mapsize = 4096;
var shadow_bias = -0.0000222;
var light = new THREE.SpotLight(0x606060, intensity, distance, angle, penumbra);
light.position.set(-430, 825, 1000);
light.castShadow = true;
light.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(120, 1, 20, 5000));
light.shadow.bias = shadow_bias;
light.shadow.mapSize.width = shadow_mapsize;
light.shadow.mapSize.height = shadow_mapsize;
this.scene.add(light);
var light = new THREE.SpotLight(0x303030, intensity, distance, angle, penumbra);
light.position.set(-430, 825, -1000);
light.castShadow = true;
light.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(120, 1, 20, 5000));
light.shadow.bias = shadow_bias;
light.shadow.mapSize.width = shadow_mapsize;
light.shadow.mapSize.height = shadow_mapsize;
this.scene.add(light);
}
//
// create plane MSRAbot stands on
var planeGeometry = new THREE.PlaneBufferGeometry(2000, 2000);
var planeMaterial = new THREE.MeshPhongMaterial({ color: 0xf0f0f0, flatShading: true, side: THREE.FrontSide });
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
planeGeometry.rotateX(-Math.PI / 2);
plane.receiveShadow = true;
this.scene.add(plane);
var helper = new THREE.GridHelper(2000, 100);
helper.position.y = plane.position.y + 1;
helper.material.opacity = 0.25;
helper.material.transparent = true;
this.scene.add(helper);
//
// create camera and scene panning controls
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.damping = 0.2;
this.controls.addEventListener('change', function () {
scope.render();
});
this.controls.addEventListener('start', function () {
scope.cancelHideTransorm();
});
this.controls.addEventListener('end', function () {
scope.delayHideTransform();
});
this.controls.target.set(0, 160, 0);
this.controls.update();
this.transformControl = new THREE.TransformControls(this.camera, this.renderer.domElement);
this.transformControl.showZ = false;
this.transformControl.addEventListener('change', function () {
scope.render();
});
this.transformControl.addEventListener('dragging-changed', function (event) {
scope.controls.enabled = !event.value;
});
this.scene.add(this.transformControl);
// Hiding transform situation is a little in a mess :()
this.transformControl.addEventListener('change', function () {
scope.cancelHideTransorm();
});
this.transformControl.addEventListener('mouseDown', function () {
scope.cancelHideTransorm();
});
this.transformControl.addEventListener('mouseUp', function () {
scope.delayHideTransform();
});
//
// set up custom event used by labanotation and msrabot modules
// signaling they''re done initializing
this.eventDoneInit = new CustomEvent('doneInit', { "bubbles": true, "cancelable": false });
document.addEventListener('doneInit', function (e) {
if ((scope.msrabot != null) && (scope.msrabot.doneInitializing) && (scope.labanotation != null) && (scope.labanotation.doneInitializing))
scope.doneInitializing();
});
//
// create MSRAbot module
this.msrabot = new MSRAbot(this);
if (this.msrabot != null)
this.msrabot.initialize(plane.position);
//
// create labanotation handling module
this.labanotation = new Labanotation(this);
if (this.labanotation != null)
this.labanotation.initialize();
}
//--------------------------------------------------------------------------------------------
APP.prototype.createDebugLabels = function ()
{
var x = 10;
var y = 86;
this.dbgLabel1 = this.createDebugLabel('dbgLabel1', x, y);
y += 28;
//this.dbgLabel2 = this.createDebugLabel('dbgLabel2', x, y);
//y += 28;
//this.dbgLabel3 = this.createDebugLabel('dbgLabel3', x, y);
}
//--------------------------------------------------------------------------------------------
APP.prototype.createDebugLabel = function (name, x, y)
{
var dbgLabel = document.createElement('div');
dbgLabel.id = name;
dbgLabel.textContent = '';
dbgLabel.style.left = '' + x + 'px';
dbgLabel.style.top = '' + y + 'px';
dbgLabel.style.opacity = "0.8";
dbgLabel.style.padding = "4px";
dbgLabel.style.borderBottom = "1px solid #363636";
dbgLabel.style.fontFamily = "Monospace";
dbgLabel.style.color = "#000";
dbgLabel.style.zIndex = 10002;
dbgLabel.style.position = "fixed";
document.body.appendChild(dbgLabel);
return dbgLabel;
}
//--------------------------------------------------------------------------------------------
APP.prototype.doneInitializing = function ()
{
}
//--------------------------------------------------------------------------------------------
APP.prototype.loadNewFile = function (filename)
{
if (this.labanotation != null)
this.labanotation.loadNewFile(filename);
}
//--------------------------------------------------------------------------------------------
APP.prototype.changeMSRAbotOpacity = function (opacity)
{
if (this.msrabot != null)
this.msrabot.changeOpacity(opacity);
}
//--------------------------------------------------------------------------------------------
APP.prototype.importFile = function (files)
{
if (files.length < 1)
return;
var scope = this;
var map = {};
var file = files[0];
map[file.name] = file;
var manager = new THREE.LoadingManager();
manager.setURLModifier(function (url) {
var file = filesMap[url];
if (file) {
console.log('Loading', url);
return URL.createObjectURL(file);
}
return url;
});
for (var i = 0; i < files.length; i++) {
scope.loadFile(files[i], manager);
}
}
//--------------------------------------------------------------------------------------------
APP.prototype.loadFile = function (file, manager)
{
var scope = this;
var filename = file.name;
var extension = filename.split('.').pop().toLowerCase();
var reader = new FileReader();
reader.addEventListener('progress', function (event) {
var size = '(' + Math.floor(event.total / 1000).toFixed(0) + ' KB)';
var progress = Math.floor((event.loaded / event.total) * 100) + '%';
console.log('Loading', filename, size, progress);
});
if (extension != 'json') {
alert("please import a file with extension .json");
return;
}
//
// read json file
reader.addEventListener('load', function (event) {
var contents = event.target.result;
if (contents.indexOf('postMessage') !== - 1) {
var blob = new Blob([contents], { type: 'text/javascript' });
var url = URL.createObjectURL(blob);
var worker = new Worker(url);
worker.onmessage = function (event) {
event.data.metadata = { version: 2 };
scope.labanotation.loadLabanotationData(filename, event.data);
};
worker.postMessage(Date.now());
return;
}
// >= 3.0
var data;
try {
data = JSON.parse(contents);
} catch (error) {
alert(error);
return;
}
scope.labanotation.loadLabanotationData(filename, data);
}, false);
reader.readAsText(file);
}
//--------------------------------------------------------------------------------------------
APP.prototype.delayHideTransform = function ()
{
this.cancelHideTransorm();
this.hideTransform();
}
//--------------------------------------------------------------------------------------------
APP.prototype.hideTransform = function ()
{
var scope = this;
this.hiding = setTimeout(function () {
scope.transformControl.detach(scope.transformControl.object);
}, 2500);
}
//--------------------------------------------------------------------------------------------
APP.prototype.cancelHideTransorm = function ()
{
if (this.hiding) {
clearTimeout(this.hiding);
this.hiding = null;
}
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentKeyDown = function (event)
{
switch (event.keyCode) {
case 0x41: // 'A'
break;
case 0x44: // 'D'
break;
}
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentMouseDown = function (event)
{
// event.preventDefault();
this.mouse.x = (event.clientX / this.nativeWidth) * 2 - 1;
this.mouse.y = -(event.clientY / this.nativeHeight) * 2 + 1;
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentMouseMove = function (event)
{
// event.preventDefault();
this.mouse.x = (event.clientX / this.nativeWidth) * 2 - 1;
this.mouse.y = -(event.clientY / this.nativeHeight) * 2 + 1;
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentMouseUp = function (event)
{
// event.preventDefault();
this.mouse.x = (event.clientX / this.nativeWidth) * 2 - 1;
this.mouse.y = -(event.clientY / this.nativeHeight) * 2 + 1;
}
//--------------------------------------------------------------------------------------------
APP.prototype.convertTouchEvents = function (touches)
{
this.touches = [];
for (var i = 0; i < event.touches.length; i++) {
this.touches.push(
new THREE.Vector2(
( touches[i].pageX / this.nativeWidth) * 2 - 1,
(-touches[i].pageY / this.nativeHeight) * 2 + 1));
}
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentTouchStart = function (event)
{
// event.preventDefault();
this.convertTouchEvents(event.touches);
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentTouchMove = function (event)
{
// event.preventDefault();
this.convertTouchEvents(event.touches);
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentTouchEnd = function (event)
{
// event.preventDefault();
this.convertTouchEvents(event.touches);
}
//--------------------------------------------------------------------------------------------
APP.prototype.onDocumentMouseWheel = function (event)
{
// event.preventDefault();
}
//--------------------------------------------------------------------------------------------
APP.prototype.onContextMenu = function (event)
{
// event.preventDefault();
}
//--------------------------------------------------------------------------------------------
APP.prototype.onWindowResize = function ()
{
this.nativeWidth = this.renderer.domElement.clientWidth;
this.nativeHeight = this.renderer.domElement.clientHeight;
this.screenWidth = window.innerWidth;
this.screenHeight = window.innerHeight;
if (this.camera) {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
}
if (this.renderer)
this.renderer.setSize(this.screenWidth, this.screenHeight);
this.render();
}
//--------------------------------------------------------------------------------------------
APP.prototype.update = function ()
{
var delta = this.clock.getDelta();
TWEEN.update();
if (this.stats)
this.stats.update();
if (this.labanotation != null)
this.labanotation.update(this.clock);
if (this.msrabot != null)
this.msrabot.update(this.clock);
}
//--------------------------------------------------------------------------------------------
APP.prototype.render = function ()
{
this.renderer.clear();
this.renderer.render(this.scene, this.camera);
}
//--------------------------------------------------------------------------------------------