A hell of a lot cleaning

This commit is contained in:
Thomas FORGIONE
2015-07-01 15:03:11 +02:00
parent bb938e5342
commit 86f2094af6
45 changed files with 56 additions and 193 deletions

View File

@@ -0,0 +1,36 @@
var BouncingCube = function(size, style) {
Cube.call(this, size, style);
this.fixed_center = new THREE.Vector3();
this.center = new THREE.Vector3();
this.speed = new THREE.Vector3(0,0,300);
};
BouncingCube.prototype = Object.create(Cube.prototype);
BouncingCube.prototype.constructor = BouncingCube;
BouncingCube.prototype.update = function() {
// Compute new center
var speed_clone = this.speed.clone();
speed_clone.multiply(BouncingCube.DT);
this.speed.add(BouncingCube.G);
if (this.speed.dot(this.speed) > 100) {
this.center.add(speed_clone);
}
if (this.center.z < 0) {
this.speed.multiply(BouncingCube.FRICTION);
this.center.z = 0;
}
// Update the mesh
this.mesh.position.set(this.center.x, this.center.y, this.center.z);
};
// Static variables
BouncingCube.DT = new THREE.Vector3(0.1,0.1,0.1);
BouncingCube.FRICTION = new THREE.Vector3(1, 1, -0.5);
BouncingCube.G = new THREE.Vector3(0,0,-10);

View File

@@ -0,0 +1,100 @@
var renderer, scene, camera, controls, cube, container, plane, mouse= {x:0, y:0};
var raycaster;
var objects = [];
var container_size = {};
var previousTime;
container_size.width = 1067;
container_size.height = 600;
init();
animate();
function init() {
// on initialise le moteur de rendu
container = document.getElementById('container');
container.style.height = container_size.height + 'px';
container.style.width = container_size.width + 'px';
renderer = new THREE.WebGLRenderer({alpha:"true"});
renderer.setSize(container_size.width, container_size.height);
renderer.shadowMapEnabled = true;
document.getElementById('container').appendChild(renderer.domElement);
// on initialise la scène
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
// init light
var directional_light = new THREE.DirectionalLight(0xffffff);
directional_light.position.set(1, 0.5, 1).normalize();
directional_light.castShadow = true;
scene.add(directional_light);
var ambient_light = new THREE.AmbientLight(0x444444);
scene.add(ambient_light);
// on initialise la camera que lon place ensuite sur la scène
camera = new Camera(50, container_size.width / container_size.height, 1, 10000);
scene.add(camera);
window.addEventListener('resize', onWindowResize, false);
container.addEventListener('mousedown', click, false);
// on créé un cube au quel on définie un matériau puis on lajoute à la scène
cube = new BouncingCube(200, {color: "red"});
plane = new Plane(1000,1000);
plane.translate(0,0,-100);
cube.addToScene(scene);
plane.addToScene(scene);
objects.push(cube);
objects.push(plane);
}
function animate() {
// on appelle la fonction animate() récursivement à chaque frame
requestAnimationFrame(animate);
cube.update();
var currentTime = Date.now() - previousTime;
camera.update(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
camera.look();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.render(scene, camera);
}
function click(event) {
mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
// For this alternate method, set the canvas position *fixed*; set top > 0, set left > 0; padding must be 0; margin > 0 is OK
//mouse.x = ( ( event.clientX - container.offsetLeft ) / container.clientWidth ) * 2 - 1;
//mouse.y = - ( ( event.clientY - container.offsetTop ) / container.clientHeight ) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
vector.unproject(camera);
raycaster.set(camera.position, vector.sub(camera.position).normalize());
intersects = raycaster.intersectObjects(scene.children);
if ( intersects.length > 0 ) {
for (var i in intersects) {
if (intersects[i].object.id === cube.mesh.id) {
cube.speed.z = 300;
}
}
}
}

View File

@@ -0,0 +1,121 @@
var mesh_number = 25;
var renderer, scene, camera, controls, cube, container, plane, mouse= {x:0, y:0};
var raycaster;
var objects = [];
var spheres = new Array(mesh_number);
var visible = 0;
var loader, previousTime;
var container_size = {};
container_size.width = 1067;
container_size.height = 600;
init();
animate();
function loadSphere(i) {
loader.load('/static/data/spheres/' + (i+1) + '.obj', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh ) {
child.material.color.setHex(0xff0000);
child.up = new THREE.Vector3(0,0,1);
child.geometry.computeFaceNormals();
child.geometry.computeVertexNormals();
}
});
spheres[i] = object;
scene.add(object);
if (i !== 0)
hide(object);
});
}
function init() {
// on initialise le moteur de rendu
container = document.getElementById('container');
container.style.height = container_size.height + 'px';
container.style.width = container_size.width + 'px';
renderer = new THREE.WebGLRenderer({alpha:"true"});
renderer.setSize(container_size.width, container_size.height);
renderer.shadowMapEnabled = true;
document.getElementById('container').appendChild(renderer.domElement);
// on initialise la scène
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
// init light
var directional_light = new THREE.DirectionalLight(0xffffff);
directional_light.position.set(1, 0.5, 1).normalize();
directional_light.castShadow = true;
scene.add(directional_light);
var ambient_light = new THREE.AmbientLight(0x444444);
scene.add(ambient_light);
// on initialise la camera que lon place ensuite sur la scène
camera = new Camera(50, container_size.width / container_size.height, 1, 10000);
scene.add(camera);
window.addEventListener('resize', onWindowResize, false);
container.addEventListener('mousedown', click, false);
// Création d'un objloader
loader = new THREE.OBJLoader();
for (var i = 0; i < mesh_number; i++) {
loadSphere(i);
}
plane = new Plane(1000,1000);
plane.translate(0,0,-100);
plane.addToScene(scene);
}
function animate() {
// on appelle la fonction animate() récursivement à chaque frame
requestAnimationFrame(animate);
var currentTime = Date.now() - previousTime;
camera.update(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
camera.look();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.render(scene, camera);
}
function click(event) {
++visible;
visible %= spheres.length;
console.log('Mesh ', visible + 1, ' out of ', spheres.length, ' : ', spheres[visible].children[0].geometry.attributes.position.array.length, ' vertices (with duplication...)');
// hide everything except visible
for (var i in spheres)
{
hide(spheres[i]);
}
show(spheres[visible]);
}
function hide(object) {
object.traverse(function ( object ) { object.visible = false; } );
}
function show(object) {
object.traverse(function ( object ) { object.visible = true; } );
}

67
js/l3d/apps/prototype/ButtonManager.js vendored Normal file
View File

@@ -0,0 +1,67 @@
var ButtonManager = function(cameras, previewer) {
this.cameras = cameras;
this.previewer = previewer;
this.showArrows = true;
this.beenFullscreen = false;
this.fullscreenElement = document.getElementById('full');
this.fullElement = document.getElementById('fullarrow');
this.resetElement = document.getElementById('reset');
this.undoElement = document.getElementById('undo');
this.redoElement = document.getElementById('redo');
this.pointerLockElement = document.getElementById('lock');
this.showarrowsElement = document.getElementById('showarrows');
this.recommendationElement = document.getElementById('recommendation');
this.fullscreenElement.onclick = function() {fullscreen();};
(function(self) {
self.undoElement.onclick = function() {self.cameras.mainCamera().undo(); self.updateElements();};
self.redoElement.onclick = function() {self.cameras.mainCamera().redo(); self.updateElements();};
self.fullElement.onclick = function() {
self.cameras.map(function(camera) {
if (!(camera instanceof PointerCamera)) {
camera.fullArrow = self.fullElement.checked;
}
});
};
self.pointerLockElement.onchange = function() {
self.cameras.mainCamera().shouldLock = self.pointerLockElement.checked;
self.cameras.mainCamera().onPointerLockChange();
};
self.showarrowsElement.onchange = function() {self.showArrows = self.showarrowsElement.checked;};
self.resetElement.onclick = function() {
// Reinit camera
self.cameras.mainCamera().reset();
};
self.recommendationElement.onchange = function() {
previewer.fixedRecommendation(self.recommendationElement.checked);
};
})(this);
};
ButtonManager.prototype.updateElements = function() {
// Update icon
if (!this.cameras.mainCamera().undoable()) {
this.undoElement.className = "btn btn-default navbar-btn";
} else {
this.undoElement.className = "btn btn-primary navbar-btn";
}
if (!this.cameras.mainCamera().redoable()) {
this.redoElement.className = "btn btn-default navbar-btn";
} else {
this.redoElement.className = "btn btn-primary navbar-btn";
}
};

166
js/l3d/apps/prototype/Coin.js vendored Normal file
View File

@@ -0,0 +1,166 @@
var Coin = function(x,y,z, callback) {
this.ready = false;
this.got = false;
this.init(x,y,z);
if (callback) {
this.callback = callback;
this.rotating = true;
}
};
var _toto = new Audio();
Coin.extension = _toto.canPlayType("audio/x-vorbis") === "" ? ".ogg" : ".mp3";
Coin.domElement = document.createElement('canvas');
Coin.domElement.style.position = 'absolute';
Coin.domElement.style.cssFloat = 'top-left';
Coin.domElement.style.top = "0px";
Coin.domElement.style.left = "0px";
Coin.image = new Image();
Coin.image.src = '/static/img/redcoin.png';
Coin.initSize = function() {
try {
Coin.domElement.width = container_size.width();
Coin.domElement.height = container_size.height();
} catch (e) {
setTimeout(100, Coin.initSize);
return;
}
};
Coin.update = function() {
var x;
try {
x = container_size.width() * 4.25 / 5;
Coin.domElement.width = container_size.width();
Coin.domElement.height = container_size.height();
} catch (e) {
return;
}
Coin.domElement.width = Coin.domElement.width;
Coin.ctx.drawImage(Coin.image, x + 75,25,30,30);
Coin.ctx.fillStyle = 'red';
Coin.ctx.strokeStyle = 'black';
Coin.ctx.font = "30px Verdana";
Coin.ctx.lineWidth = 5;
Coin.ctx.strokeText(Coin.total - 1 + " / " + Coin.max, x, 50);
Coin.ctx.fillText(Coin.total - 1 + " / " + Coin.max, x, 50);
Coin.ctx.stroke();
Coin.ctx.fill();
};
Coin.image.onload = Coin.update;
Coin.total = 1;
Coin.ctx = Coin.domElement.getContext('2d');
Coin.update();
Coin.prototype.init = function(x,y,z) {
if (Coin.BASIC_MESH !== null) {
this.mesh = Coin.BASIC_MESH.clone();
this.mesh.position.x = x;
this.mesh.position.y = y;
this.mesh.position.z = z;
this.ready = true;
this.mesh.raycastable = true;
} else {
(function(self,x,y,z) {
setTimeout(function() {
self.init(x,y,z);
},1000);
})(this,x,y,z);
}
};
Coin.prototype.addToScene = function(scene) {
scene.add(this.mesh);
};
Coin.prototype.update = function() {
var self = this;
if (this.ready && this.rotating)
this.mesh.rotation.y += 0.1;
};
Coin.prototype.get = function() {
if (!this.got) {
this.got = true;
// Call the callback if any
if (this.callback)
this.callback();
if (this.mesh) {
this.mesh.visible = false;
this.mesh.raycastable = false;
}
Coin.total ++;
Coin.nextSound.play();
if (Coin.total === 9) {
// You got the last coin
var music = document.getElementById('music');
if (music !== null) {
var wasPlaying = !music.paused;
music.pause();
setTimeout(function() {
Coin.lastSound.play();
setTimeout(function() {
if (wasPlaying) {
music.play();
}
}, Coin.lastSound.duration*1000);
}, Coin.nextSound.duration*1000);
}
} else {
Coin.nextSound = new Audio('/static/data/music/redcoins/' + Coin.total + Coin.extension);
Coin.nextSound.preload = "auto";
}
Coin.update();
}
};
Coin.lastSound = new Audio('/static/data/music/starappears' + Coin.extension);
Coin.lastSound.preload = "auto";
Coin.total = 1;
Coin.BASIC_MESH = null;
Coin._loader = new THREE.OBJLoader();
Coin.init = function(scale) {
Coin.max = 8;
if (!Coin.initialized) {
Coin.initialized = true;
if (scale === undefined) {
scale = 0.005;
}
Coin._loader.load(
'/static/data/coin/Coin.obj',
function(object) {
object.traverse(function (mesh) {
if (mesh instanceof THREE.Mesh) {
mesh.scale.set(scale,scale,scale);
mesh.material.color.setHex(0xff0000);
mesh.geometry.computeVertexNormals();
mesh.raycastable = true;
Coin.BASIC_MESH = mesh;
}
});
}
);
Coin.nextSound = new Audio('/static/data/music/redcoins/1' + Coin.extension);
}
};

View File

@@ -0,0 +1,299 @@
var isFullscreen = false;
var beenFullscreen = false;
var main_section = document.getElementById('main-section');
// var container_size = {
// width: function() { if (!isFullscreen) return main_section.clientWidth; else return screen.width;},
// height: function() {
// if (!isFullscreen)
// return main_section.clientHeight
// - document.getElementById('nav').offsetHeight
// - document.getElementById('main-div').offsetHeight;
// else
// return screen.height;
// }
// };
var container_size = {
width: function() { return 1024; },
height: function() { return 768; }
};
var stats;
// Let's be sure we avoid using global variables
var onWindowResize = (function() {
// Disable scrolling
window.onscroll = function () { window.scrollTo(0, 0); };
var mesh_number = 25;
var renderer, scene, controls, cube, container, plane, mouse= {x:0, y:0};
var bigmesh;
var raycaster;
var objects = [];
var cameras, cameraSelecter;
var spheres = new Array(mesh_number);
var visible = 0;
// stats;
var previewer;
var camera1;
var loader;
var coins = [];
var previousTime;
window.onbeforeunload = function() {
if (initMainScene !== initPeach && initMainScene !== initSponza && Coin.total !== 9) {
return 'Warning : you are going to leave the page and abort the current test !';
}
};
init();
if (initMainScene !== initPeach && initMainScene !== initSponza)
logfps();
animate();
function logfps() {
// Log fps
if (stats !== undefined) {
var event = new BD.Event.Fps();
event.fps = stats.getFps();
event.send();
}
setTimeout(logfps, 1000);
}
function init() {
// Initialize scene
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({alpha:true, antialias:true});
// Collidable objects to prevent camera from traversing objects
var collidableObjects = [];
// Initialize renderer
container = document.getElementById('container');
container.style.height = container_size.height() + 'px';
container.style.width = container_size.width() + 'px';
renderer.setSize(container_size.width(), container_size.height());
// renderer.setSize(container_size.width(), container_size.height());
renderer.setClearColor(0x87ceeb);
// Initialize pointer camera
camera1 = new PointerCamera(50, container_size.width() / container_size.height(), 0.01, 100000, renderer, container);
// Initialize previewer
previewer = new Previewer(renderer, scene);
previewer.domElement.style.position ="absolute";
previewer.domElement.style.cssFloat = 'top-left';
previewer.domElement.width = container_size.width();
previewer.domElement.height = container_size.height();
// Initialize stats counter
stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.cssFloat = "top-left";
// Initialize pointer for pointer lock
var pointer = new MousePointer(camera1);
pointer.domElement.width = container_size.width();
pointer.domElement.height = container_size.height();
//
var startCanvas = new StartCanvas(camera1);
startCanvas.domElement.width = container_size.width();
startCanvas.domElement.height = container_size.height();
// Add elements to page
container.appendChild( stats.domElement );
container.appendChild(Coin.domElement);
container.appendChild(startCanvas.domElement);
container.appendChild(pointer.domElement);
container.appendChild(previewer.domElement);
container.appendChild(renderer.domElement);
startCanvas.render();
cameras = initMainScene(camera1, scene, coins);
// cameras = initPeach(camera1, scene, coins);
// cameras = initBobomb(camera1, scene, coins);
// cameras = initWhomp(camera1, scene, , coins);
// cameras = initMountain(camera1, scene, coins);
// cameras = initSponza(camera1, scene, coins);
// Add listeners
initListeners();
// Set interval on animate
setInterval(animate, 20);
}
function initListeners() {
window.addEventListener('resize', onWindowResize, false);
// Transmit click event to camera selecter
document.addEventListener('mousedown', function(event) {
if (event.which == 1)
cameraSelecter.clickPointer(event);
}, false
);
// Transmit click event to camera selecter
container.addEventListener('mousedown', function(event) {
if (event.which == 1)
cameraSelecter.click(event);
}, false
);
// Update camera selecter when mouse moved
container.addEventListener('mousemove', function(event) {
cameraSelecter.update(event);
});
// Escape key to exit fullscreen mode
document.addEventListener('keydown', function(event) { if (event.keyCode == 27) { stopFullscreen();} }, false);
// HTML Bootstrap buttons
buttonManager = new ButtonManager(cameras, previewer);
// Camera selecter for hover and clicking recommendations
cameraSelecter = new CameraSelecter(renderer, scene, cameras, coins, buttonManager);
}
function render() {
cameraSelecter.update();
// Update recommendations (set raycastable if shown)
var transform = buttonManager.showArrows ? show : hide;
cameras.map(function(camera) {
if (camera instanceof RecommendedCamera) {
transform(camera);
camera.traverse(function(elt) {
elt.raycastable = buttonManager.showArrows;
});
}
});
// Update coins
coins.forEach(function(coin) { coin.update(); });
// Update main camera
var currentTime = Date.now() - previousTime;
cameras.updateMainCamera(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
// Update the recommendations
cameras.update(cameras.mainCamera());
// Set current position of camera
cameras.look();
var left = 0, bottom = 0, width = container_size.width(), height = container_size.height();
renderer.setScissor(left, bottom, width, height);
renderer.enableScissorTest(true);
renderer.setViewport(left, bottom, width, height);
renderer.render(scene, cameras.mainCamera());
// Remove borders of preview
previewer.clear();
// Hide arrows in recommendation
cameras.map(function(camera) { if (camera instanceof RecommendedCamera) hide(camera); });
// Update transparent elements
THREEx.Transparency.update(cameras.mainCamera());
// Render preview
previewer.render(cameraSelecter.prev, container_size.width(), container_size.height());
}
function animate() {
// Render each frame
// requestAnimationFrame(animate);
// stats count the number of frames per second
stats.begin();
render();
stats.end();
}
function onWindowResize() {
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
previewer.domElement.width = container_size.width();
previewer.domElement.height = container_size.height();
renderer.setSize(container_size.width(), container_size.height());
cameras.forEach(function(camera) {camera.aspect = container_size.width() / container_size.height();});
cameras.forEach(function(camera) {camera.updateProjectionMatrix();});
render();
}
function hide(object) {
object.traverse(function(object) {object.visible = false;});
}
function show(object) {
object.traverse(function(object) {object.visible = true;});
}
// onWindowResize will be the only global function
return onWindowResize;
})();
function fullscreen() {
var container = document.getElementById('container');
isFullscreen = true;
if (!beenFullscreen) {
beenFullscreen = true;
alert('To quit fullscren mode, type ESC key');
}
container.style.position = "absolute";
container.style.cssFloat = "top-left";
container.style.top = "50px";
container.style.bottom = "0px";
container.style.left = "0px";
container.style.right = "0px";
container.style.width="";
container.style.height="";
container.style.overflow = "hidden";
onWindowResize();
}
function stopFullscreen() {
isFullscreen = false;
var container = document.getElementById('container');
container.style.position = "";
container.style.cssFloat = "";
container.style.top = "";
container.style.bottom = "";
container.style.left = "";
container.style.right = "";
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
onWindowResize();
}

237
js/l3d/apps/prototype/replay/main.js vendored Normal file
View File

@@ -0,0 +1,237 @@
var isFullscreen = false;
var beenFullscreen = false;
var main_section = document.getElementById('main-section');
// var container_size = {
// width: function() { if (!isFullscreen) return main_section.clientWidth; else return screen.width;},
// height: function() {
// if (!isFullscreen)
// return main_section.clientHeight
// - document.getElementById('nav').offsetHeight
// - document.getElementById('main-div').offsetHeight;
// else
// return screen.height;
// }
// };
var container_size = {
width: function() { return 1024; },
height: function() { return 768; }
};
var onWindowResize = (function() {
// Disable scrolling
window.onscroll = function () { window.scrollTo(0, 0); };
var mesh_number = 25;
var renderer, scene, controls, cube, container, plane, mouse= {x:0, y:0};
var bigmesh;
var raycaster;
var objects = [];
var cameras, cameraSelecter;
var spheres = new Array(mesh_number);
var visible = 0;
var stats;
var loader;
var coins = [];
var previousTime;
init();
animate();
function init() {
// Initialize scene
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({alpha:true, antialias:true});
// Collidable objects to prevent camera from traversing objects
var collidableObjects = [];
// Initialize renderer
container = document.getElementById('container');
container.style.height = container_size.height() + 'px';
container.style.width = container_size.width() + 'px';
renderer.setSize(container_size.width(), container_size.height());
// renderer.setSize(container_size.width(), container_size.height());
renderer.shadowMapEnabled = true;
renderer.setClearColor(0x87ceeb);
// Initialize stats counter
stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.cssFloat = "top-left";
// Add elements to page
container.appendChild( stats.domElement );
container.appendChild(renderer.domElement);
// Initialize pointer camera
var camera1 = new ReplayCamera(50, container_size.width() / container_size.height(), 0.01, 100000, coins);
cameras = initMainScene(camera1, scene, coins);
camera1.cameras = cameras;
// Add listeners
initListeners();
setInterval(animate, 20);
}
function initListeners() {
window.addEventListener('resize', onWindowResize, false);
// Transmit click event to camera selecter
// container.addEventListener('mousedown', function(event) {
// if (event.which == 1)
// cameraSelecter.click(event);
// }, false
// );
// Update camera selecter when mouse moved
// container.addEventListener('mousemove', function(event) {
// cameraSelecter.update(event);
// }, false
// );
// Escape key to exit fullscreen mode
// document.addEventListener('keydown', function(event) { if (event.keyCode == 27) { stopFullscreen();} }, false);
// HTML Bootstrap buttons
// buttonManager = new ButtonManager(cameras);
// Camera selecter for hover and clicking recommendations
// cameraSelecter = new CameraSelecter(renderer, scene, cameras, buttonManager);
}
function fullscreen() {
isFullscreen = true;
if (!beenFullscreen) {
beenFullscreen = true;
alert('To quit fullscren mode, type ESC key');
}
container.style.position = "absolute";
container.style.cssFloat = "top-left";
container.style.top = "50px";
container.style.bottom = "0px";
container.style.left = "0px";
container.style.right = "0px";
container.style.width="";
container.style.height="";
container.style.overflow = "hidden";
// canvas.style.position = "absolute";
// canvas.style.cssFloat = "top-left";
// canvas.style.top = "0px";
// canvas.style.bottom = "0px";
// canvas.style.left = "0px";
// canvas.style.right = "0px";
// canvas.width=window.innerWidth;
// canvas.height=window.innerHeight;
// canvas.style.overflow = "hidden";
onWindowResize();
}
function stopFullscreen() {
isFullscreen = false;
container.style.position = "";
container.style.cssFloat = "";
container.style.top = "";
container.style.bottom = "";
container.style.left = "";
container.style.right = "";
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
// canvas.style.position = "";
// canvas.style.cssFloat = "";
// canvas.style.top = "";
// canvas.style.bottom = "";
// canvas.style.left = "";
// canvas.style.right = "";
// canvas.width = container_size.width();
// canvas.height = container_size.height();
// canvas.style.overflow = "";
onWindowResize();
}
function render() {
// cameraSelecter.update();
// Update recommendations (set raycastable if shown)
// var transform = buttonManager.showArrows ? show : hide;
// cameras.map(function(camera) {
// if (camera instanceof RecommendedCamera) {
// transform(camera);
// camera.traverse(function(elt) {
// elt.raycastable = buttonManager.showArrows;
// });
// }
// });
// Update coins
coins.forEach(function(coin) { coin.update(); });
// Update main camera
var currentTime = Date.now() - previousTime;
cameras.updateMainCamera(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
// Update the recommendations
cameras.update(cameras.mainCamera());
// Set current position of camera
cameras.look();
var left = 0, bottom = 0, width = container_size.width(), height = container_size.height();
renderer.setScissor(left, bottom, width, height);
renderer.enableScissorTest(true);
renderer.setViewport(left, bottom, width, height);
renderer.render(scene, cameras.mainCamera());
// Hide arrows in recommendation
// cameras.map(function(camera) { if (camera instanceof RecommendedCamera) hide(camera); });
}
function animate() {
// Render each frame
// requestAnimationFrame(animate);
// stats count the number of frames per second
stats.begin();
render();
stats.end();
}
function onWindowResize() {
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
renderer.setSize(container_size.width(), container_size.height());
cameras.forEach(function(camera) {camera.aspect = container_size.width() / container_size.height();});
cameras.forEach(function(camera) {camera.updateProjectionMatrix();});
render();
}
function hide(object) {
object.traverse(function(object) {object.visible = false;});
}
function show(object) {
object.traverse(function(object) {object.visible = true;});
}
return onWindowResize;
})();

View File

@@ -0,0 +1,555 @@
// class camera extends THREE.PerspectiveCamera
var TutoCamera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
this.renderer = arguments[4];
this.onWindowResize = arguments[6];
var scene = arguments[5];
var container_size = arguments[7];
var coins = arguments[8];
if (arguments[9] === undefined)
listenerTarget = document;
else
listenerTarget = arguments[9];
// Set Position
this.theta = Math.PI;
this.phi = Math.PI;
// this.keyboard = undefined;
this.moving = false;
this.dragging = false;
this.mouse = {x: 0, y: 0};
this.mouseMove = {x: 0, y: 0};
// Stuff for rendering
this.position = new THREE.Vector3();
this.forward = new THREE.Vector3();
this.left = new THREE.Vector3();
this.target = new THREE.Vector3(0,1,0);
// Stuff for events
this.motion = {};
this.sensitivity = 0.05;
this.speed = 1;
// Raycaster for collisions
this.raycaster = new THREE.Raycaster();
// Create history object
this.history = new History();
// Set events from the document
var self = this;
var onKeyDown = function(event) {self.onKeyDown(event);};
var onKeyUp = function(event) {self.onKeyUp(event);};
var onMouseDown = function(event) {if (event.which === 1) self.onMouseDown(event); };
var onMouseUp = function(event) {if (event.which === 1) self.onMouseUp(event); };
var onMouseMove = function(event) {self.onMouseMove(event); };
document.addEventListener('keydown', onKeyDown, false);
document.addEventListener('keyup', onKeyUp, false);
document.addEventListener('pointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('mozpointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('webkitpointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('mousemove', function(event) {self.onMouseMovePointer(event);}, false);
listenerTarget.addEventListener('mousedown', function() {self.lockPointer();}, false);
listenerTarget.addEventListener('mousedown', onMouseDown, false);
listenerTarget.addEventListener('mousemove', onMouseMove, false);
listenerTarget.addEventListener('mouseup', onMouseUp, false);
listenerTarget.addEventListener('mouseout', onMouseUp, false);
document.getElementById('lock').addEventListener('change', function(e) {
if (self.tutorial.nextAction() === 'uncheck-lock') {
self.tutorial.nextStep();
}
});
this.collisions = true;
this.resetElements = resetBobombElements();
// Create tutorial
this.tutorial = new TutorialSteps(this, scene, coins, this.onWindowResize, container_size);
this.shouldLock = true;
};
TutoCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
TutoCamera.prototype.constructor = TutoCamera;
TutoCamera.prototype.lockPointer = function() {
if (this.shouldLock) {
this.renderer.domElement.requestPointerLock =
this.renderer.domElement.requestPointerLock ||
this.renderer.domElement.mozRequestPointerLock ||
this.renderer.domElement.webkitRequestPointerLock;
if (this.renderer.domElement.requestPointerLock) {
this.renderer.domElement.requestPointerLock();
}
}
};
TutoCamera.prototype.isLocked = function() {
var toto =
document.pointerLockElement === this.renderer.domElement ||
document.mozPointerLockElement === this.renderer.domElement ||
document.webkitPointerLockElement === this.renderer.domElement;
return toto;
};
TutoCamera.prototype.onPointerLockChange = function() {
if (this.isLocked()) {
// The pointer is locked : adapt the state of the camera
this.pointerLocked = true;
this.mousePointer.render();
this.mouse.x = this.renderer.domElement.width/2;
this.mouse.y = this.renderer.domElement.height/2;
// Remove start canvas
this.startCanvas.clear();
if (this.tutorial.nextAction() === 'lock-pointer') {
this.tutorial.nextStep();
}
} else {
this.pointerLocked = false;
this.mousePointer.clear();
this.theta = this.previousTheta;
this.phi = this.previousPhi;
this.mouseMove.x = 0;
this.mouseMove.y = 0;
// Draw start canvas only if should lock
if (this.shouldLock)
this.startCanvas.render();
else
this.startCanvas.clear();
if (this.tutorial.nextAction() === 'unlock-pointer') {
this.tutorial.nextStep();
}
}
};
// Update function
TutoCamera.prototype.update = function(time) {
if (this.moving) {
this.linearMotion(time);
} else if (this.movingHermite) {
this.hermiteMotion(time);
} else {
this.normalMotion(time);
}
};
TutoCamera.prototype.linearMotion = function(time) {
var position_direction = Tools.diff(this.new_position, this.position);
var target_direction = Tools.diff(this.new_target, this.target);
this.position.add(Tools.mul(position_direction, 0.05 * time / 20));
this.target.add(Tools.mul(target_direction, 0.05 * time / 20));
if (Tools.norm2(Tools.diff(this.position, this.new_position)) < 0.01 &&
Tools.norm2(Tools.diff(this.target, this.new_target)) < 0.01) {
this.moving = false;
this.anglesFromVectors();
}
};
TutoCamera.prototype.hermiteMotion = function(time) {
var e = this.hermitePosition.eval(this.t);
this.position.x = e.x;
this.position.y = e.y;
this.position.z = e.z;
this.target = Tools.sum(this.position, this.hermiteAngles.eval(this.t));
this.t += 0.01 * time / 20;
if (this.t > 1) {
this.movingHermite = false;
this.anglesFromVectors();
}
};
TutoCamera.prototype.normalMotion = function(time) {
// Update angles
if (this.motion.increasePhi) {this.phi += this.sensitivity; this.changed = true; }
if (this.motion.decreasePhi) {this.phi -= this.sensitivity; this.changed = true; }
if (this.motion.increaseTheta) {this.theta += this.sensitivity; this.changed = true; }
if (this.motion.decreaseTheta) {this.theta -= this.sensitivity; this.changed = true; }
if (this.isLocked() || this.dragging) {
this.theta += this.mouseMove.x;
this.phi -= this.mouseMove.y;
this.mouseMove.x = 0;
this.mouseMove.y = 0;
this.changed = true;
}
// Clamp phi and theta
this.phi = Math.min(Math.max(-(Math.PI/2-0.1),this.phi), Math.PI/2-0.1);
this.theta = ((this.theta - Math.PI) % (2*Math.PI)) + Math.PI;
// Compute vectors (position and target)
this.vectorsFromAngles();
// Update with events
var delta = 0.1;
var forward = this.forward.clone();
forward.multiplyScalar(400.0 * delta);
var left = this.up.clone();
left.cross(forward);
left.normalize();
left.multiplyScalar(400.0 * delta);
// Move only if no collisions
var speed = this.speed * time / 20;
var direction = new THREE.Vector3();
if (this.motion.boost) speed *= 10;
if (this.motion.moveForward) {direction.add(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveBackward) {direction.sub(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveLeft) {direction.add(Tools.mul(left, speed)); this.changed = true;}
if (this.motion.moveRight) {direction.sub(Tools.mul(left, speed)); this.changed = true;}
var collide = this.isColliding(direction);
if (this.collisions && collide) {
var face = collide.face;
var vertices = collide.object.geometry.vertices;
var normal = Tools.cross(Tools.diff(vertices[face.b], vertices[face.a]), Tools.diff(vertices[face.c], vertices[face.a])).normalize();
if (Tools.dot(normal, direction) > 0) {
normal.multiplyScalar(-1);
}
normal.multiplyScalar(0.01);
this.position.add(normal);
} else {
this.position.add(direction);
}
// Update angle
this.target = this.position.clone();
this.target.add(forward);
};
TutoCamera.prototype.reset = function() {
if (this.tutorial.nextAction() === 'reset-camera') {
this.tutorial.nextStep();
}
this.resetPosition();
this.moving = false;
this.movingHermite = false;
(new BD.Event.ResetClicked()).send();
this.previousTheta = this.theta;
this.previousPhi = this.phi;
};
TutoCamera.prototype.resetPosition = function() {
this.position.copy(this.resetElements.position);
this.target.copy(this.resetElements.target);
this.anglesFromVectors();
};
TutoCamera.prototype.vectorsFromAngles = function() {
// Update direction
this.forward.y = Math.sin(this.phi);
var cos = Math.cos(this.phi);
this.forward.z = cos * Math.cos(this.theta);
this.forward.x = cos * Math.sin(this.theta);
this.forward.normalize();
};
TutoCamera.prototype.anglesFromVectors = function() {
var forward = Tools.diff(this.target, this.position);
forward.normalize();
this.phi = Math.asin(forward.y);
// Don't know why this line works... But thanks Thierry-san and
// Bastien because it seems to work...
this.theta = Math.atan2(forward.x, forward.z);
};
TutoCamera.prototype.move = function(otherCamera, toSave) {
if (toSave === undefined)
toSave = true;
this.moving = true;
this.new_target = otherCamera.target.clone();
this.new_position = otherCamera.position.clone();
var t = [0,1];
var f = [this.position.clone(), this.new_position];
var fp = [Tools.diff(this.target, this.position), Tools.diff(this.new_target, this.new_position)];
this.hermite = new Hermite.Polynom(t,f,fp);
this.t = 0;
if (toSave) {
if (this.changed) {
this.save();
this.changed = false;
}
this.history.addState({position: otherCamera.position.clone(), target: otherCamera.target.clone()});
}
};
TutoCamera.prototype.moveHermite = function(otherCamera, toSave) {
if (this.tutorial.nextAction() === 'recommendation') {
this.tutorial.nextStep();
}
if (toSave === undefined)
toSave = true;
this.movingHermite = true;
this.t = 0;
this.hermitePosition = new Hermite.special.Polynom(
this.position.clone(),
otherCamera.position.clone(),
Tools.mul(Tools.diff(otherCamera.target, otherCamera.position).normalize(),4)
);
this.hermiteAngles = new Hermite.special.Polynom(
Tools.diff(this.target, this.position),
Tools.diff(otherCamera.target, otherCamera.position),
new THREE.Vector3()
);
if (toSave) {
if (this.changed) {
this.save();
this.changed = false;
}
this.history.addState({position: otherCamera.position.clone(), target: otherCamera.target.clone()});
}
};
TutoCamera.prototype.isColliding = function(direction) {
this.raycaster.set(this.position, direction.clone().normalize());
var intersects = this.raycaster.intersectObjects(this.collidableObjects, true);
for (var i in intersects) {
if (intersects[i].distance < Tools.norm(direction) + this.speed * 300 &&
intersects[i].object.raycastable) {
return intersects[i];
}
}
};
// Look function
TutoCamera.prototype.look = function() {
this.lookAt(this.target);
};
TutoCamera.prototype.addToScene = function(scene) {
scene.add(this);
};
TutoCamera.prototype.onKeyEvent = function(event, toSet) {
// Create copy of state
var motionJsonCopy = JSON.stringify(this.motion);
var moved;
if (this.allowed.keyboardTranslate) {
moved = true;
switch ( event.keyCode ) {
// Azerty keyboards
case 38: case 90: this.motion.moveForward = toSet; break; // up / z
case 37: case 81: this.motion.moveLeft = toSet; break; // left / q
case 40: case 83: this.motion.moveBackward = toSet; break; // down / s
case 39: case 68: this.motion.moveRight = toSet; break; // right / d
// Qwerty keyboards
case 38: case 87: this.motion.moveForward = toSet; break; // up / w
case 37: case 65: this.motion.moveLeft = toSet; break; // left / a
case 40: case 83: this.motion.moveBackward = toSet; break; // down / s
case 39: case 68: this.motion.moveRight = toSet; break; // right / d
case 32: this.motion.boost = toSet; moved = false; break;
default: moved = false; break;
}
if (moved && this.tutorial.nextAction() === 'translate-keyboard' && !toSet) {
this.tutorial.nextStep();
}
}
if (this.allowed.keyboardRotate) {
moved = true;
switch ( event.keyCode ) {
case 73: case 104: this.motion.increasePhi = toSet; break; // 8 Up for angle
case 75: case 98: this.motion.decreasePhi = toSet; break; // 2 Down for angle
case 74: case 100: this.motion.increaseTheta = toSet; break; // 4 Left for angle
case 76: case 102: this.motion.decreaseTheta = toSet; break; // 6 Right for angle
default: moved = false; break;
}
if (moved && this.tutorial.nextAction() === 'rotate-keyboard' && !toSet) {
this.tutorial.nextStep();
}
}
switch (event.keyCode) {
case 13: if (toSet) this.log(); break;
}
if (motionJsonCopy != JSON.stringify(this.motion)) {
// Log any change
var e = new BD.Event.KeyboardEvent();
e.camera = this;
e.send();
}
};
TutoCamera.prototype.onKeyDown = function(event) {
this.onKeyEvent(event, true);
};
TutoCamera.prototype.onKeyUp = function(event) {
this.onKeyEvent(event, false);
};
TutoCamera.prototype.onMouseDown = function(event) {
this.mouse.x = ( ( event.clientX - this.renderer.domElement.offsetLeft ) / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - this.renderer.domElement.offsetTop ) / this.renderer.domElement.height ) * 2 + 1;
if (this.allowed.mouseRotate) {
this.dragging = true;
this.mouseMoved = false;
}
};
TutoCamera.prototype.onMouseMove = function(event) {
if (!this.shouldLock && this.dragging) {
this.previousTheta = this.theta;
this.previousPhi = this.phi;
var mouse = {x: this.mouse.x, y: this.mouse.y};
this.mouse.x = ( ( event.clientX - this.renderer.domElement.offsetLeft ) / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - this.renderer.domElement.offsetTop ) / this.renderer.domElement.height ) * 2 + 1;
this.mouseMove.x = this.mouse.x - mouse.x;
this.mouseMove.y = this.mouse.y - mouse.y;
this.mouseMoved = true;
if (this.tutorial.nextAction() === 'rotate-mouse') {
this.tutorial.nextStep();
}
}
};
TutoCamera.prototype.onMouseMovePointer = function(e) {
if (this.isLocked()) {
// Backup theta and phi
this.previousTheta = this.theta;
this.previousPhi = this.phi;
this.mouseMove.x = e.movementX || e.mozMovementX || e.webkitMovementX || 0;
this.mouseMove.y = e.movementY || e.mozMovementY || e.webkitMovementY || 0;
this.mouseMove.x *= -(this.sensitivity/10);
this.mouseMove.y *= (this.sensitivity/10);
this.mouseMoved = true;
}
};
TutoCamera.prototype.onMouseUp = function(event) {
this.onMouseMove(event);
// Send log to DB
if (this.dragging && this.mouseMoved && !this.moving && !this.movingHermite) {
var e = new BD.Event.KeyboardEvent();
e.camera = this;
e.send();
}
this.dragging = false;
};
TutoCamera.prototype.log = function() {
console.log("createCamera(\nnew THREE.Vector3(" + this.position.x + "," + this.position.y + ',' + this.position.z + '),\n' +
"new THREE.Vector3(" + this.target.x + "," + this.target.y + ',' + this.target.z + ')\n)');
};
TutoCamera.prototype.save = function() {
var backup = {};
backup.position = this.position.clone();
backup.target = this.target.clone();
this.history.addState(backup);
};
TutoCamera.prototype.undo = function() {
var move = this.history.undo();
if (move !== undefined) {
var event = new BD.Event.PreviousNextClicked();
event.previous = true;
event.camera = move;
event.send();
this.move(move, false);
}
};
TutoCamera.prototype.redo = function() {
var move = this.history.redo();
if (move !== undefined) {
var event = new BD.Event.PreviousNextClicked();
event.previous = false;
event.camera = move;
event.send();
this.move(move, false);
}
};
TutoCamera.prototype.undoable = function() {
return this.history.undoable();
};
TutoCamera.prototype.redoable = function() {
return this.history.redoable();
};

View File

@@ -0,0 +1,225 @@
var nextStep;
var TutorialSteps = function(tutoCamera, scene, coins, onWindowResize, container_size) {
this.camera = tutoCamera;
this.step = 0;
this.coinNumber = 0;
this.camera.allowed = {};
this.onWindowResize = onWindowResize;
this.container_size = container_size;
this.coins = coins;
this.instructions = [
{
text:"Welcome to this tutorial ! Click on the canvas to go start !",
justclick:false
},
{
text: "You can use your mouse to move around, and press the escape key to unlock the pointer",
justclick: false
},
{
text: "You can also uncheck the <em>lock pointer</em> otion at the bottom of the page to rotate the camera via drag'n'drop !",
justclick: false
},
{
text:"You can use your mouse (drag'n'drop) to rotate the camera",
justclick:false
},
{
text:"Nice ! You can also use (2,4,6 and 8) keys or (k,j,l and i)",
justclick: true
},
{
text: "Here is a red coin, click on it !",
justclick: false
},
{
text: "Nice, there are a 3 more red coins around you, try to get them ! Check the coin counter !",
justclick: false
},
{
text: "Two more ! Feel free to select the pointer lock option you prefer",
justclick: false
},
{
text: "One more !",
justclick: false
},
{
text:"Nice ! You will now learn to translate the camera",
justclick: true
},
{
text: "Try pressing an arrow key on your keyboard to translate the camera !",
justclick: false
},
{
text: "There is a red coin on the top of the castle, just if front of you ! Go and get it !",
justclick: false
},
{
text: "You got it ! Try to click on reset camera !",
justclick: false
},
{
text: "Nice ! Let me introduce you to <emp>recommendations</em>",
justclick: true
},
{
text: "This is a recommendation, by hovering it, you should see a preview, and by clicking on it, you should go to the recommended viewpoint",
justclick: false
},
{
text: "The recommendation will change color once you clicked on it, just like a web link",
justclick:true
},
{
text: "Here are some more recommendations, try to browse the scene and find the missing red coins (5/8)",
justclick:false
},
{
text:"Tip : you can use the arrow buttons in the bar at the bottom of the screen to go to the previous / next position",
justclick: false
},
{
text: "Tip : if you find that the previews take too much place, you can put them at the bottom of the screen (use the checkbox options below) !",
justclick: false
},
{
text: "Congratulations ! You've successfully finished the tutorial !",
justclick: false
}
];
var self = this;
nextStep = function() {self.nextStep();};
this.scene = scene;
Coin.domElement.style.display = "none";
};
TutorialSteps.prototype.setCameras = function(cameras) {
this.cameras = cameras;
};
TutorialSteps.prototype.nextStep = function() {
console.log(this.step);
if (this.step < this.instructions.length) {
this.alert(this.instructions[this.step].text, this.instructions[this.step].justclick);
var callback = function() {self.coinNumber++; self.nextStep();};
var self = this;
switch (this.step) {
case 0: break;
case 3: this.camera.allowed.mouseRotate = true; break;
case 4: this.camera.allowed.keyboardRotate = true; break;
case 5:
Coin.domElement.style.display = "";
Coin.max = 1;
Coin.update();
this.camera.allowed.keyboardRotate = true;
this.coins.push(new Coin(0.4911245636058468,1.225621525492101,-5.11526684540265, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
document.getElementById('container').appendChild(Coin.domElement);
break;
case 6:
Coin.max = 4;
Coin.update();
this.coins.push(new Coin(1.4074130964382279,0.6458319586843252,-6.75244526999632, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
this.coins.push(new Coin(-4.2701659473968965,0.6745750513698942,-0.484545726832743, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
this.coins.push(new Coin(-4.336597108439718,0.4203578350484251,-8.447211342176862, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
break;
case 9:
this.camera.move(this.camera.resetElements);
break;
case 10:
this.camera.allowed.keyboardTranslate = true;
break;
case 11:
Coin.max = 5;
Coin.update();
this.coins.push(new Coin(2.7378029903574026,2.953347730618792,-11.550836282321221, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
this.camera.move({
position: new THREE.Vector3(-0.3528994281499122,-0.026355227893303856,-0.2766844454377826),
target: new THREE.Vector3(13.645394042405439,12.337463485871524,-35.64876053273249)
});
break;
case 14:
var cam = createPeachCameras(this.container_size.width(), this.container_size.height())[2];
this.cameras.push(cam);
cam.addToScene(this.scene);
this.camera.move({
position: new THREE.Vector3(0.24120226734236713,0.2009624547018851,-0.5998422840047036),
target: new THREE.Vector3(24.021711452218575,7.072419314071788,-32.020702608601745)
});
break;
case 16:
var cams = createPeachCameras(this.container_size.width(), this.container_size.height());
for (var i = 0; i < cams.length; i == 1 ? i+=2 : i++) {
this.cameras.push(cams[i]);
cams[i].addToScene(this.scene);
}
Coin.max = 8;
Coin.update();
this.coins.push(new Coin(3.701112872561801,-0.4620393514856378,-3.3373375945128085, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
this.coins.push(new Coin(6.694675339780243,-1.2480369397526456,-1.992336719279164, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
this.coins.push(new Coin(-2.458336118265302,-1.549510268763568,-11.186153614421212, callback));
this.coins[this.coins.length-1].addToScene(this.scene);
break;
}
this.step++;
}
};
TutorialSteps.prototype.nextAction = function() {
switch (this.step) {
case 1: return 'lock-pointer';
case 2: return 'unlock-pointer';
case 3: return 'uncheck-lock';
case 4: return 'rotate-mouse';
case 5: return 'rotate-keyboard';
case 11: return 'translate-keyboard';
case 13: return 'reset-camera';
case 15: return 'recommendation';
}
};
TutorialSteps.prototype.tryFinish = function() {
if (this.coinNumber === 8) {
console.log("Finished");
}
};
TutorialSteps.prototype.alert = function(myString, justclicked) {
this.notify(myString, justclicked);
this.onWindowResize();
};
TutorialSteps.prototype.notify = function(myString, justclick) {
$('#alert-placeholder').html(
'<div id="toto" class="alert alert-warning alert-dismissable">' +
(justclick ?
'<button type="button" class="close" aria-hidden="true"' +
'onclick="setTimeout(onWindowResize, 100); nextStep();' + '">' +
'<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>' +
'</button>' : '') +
'<span><strong>' +
myString +
(justclick ?
' <a href="#" onclick="setTimeout(onWindowResize, 100); nextStep();"><em>(next)</em></span>' : '' ) +
'</strong></span>' +
'</div>'
);
$('#toto').removeClass('alert-info').addClass('alert-danger');
setTimeout(function() {
$('#toto').removeClass('alert-danger').addClass('alert-warning');
}, 500);
};

247
js/l3d/apps/prototype/tutorial/main.js vendored Normal file
View File

@@ -0,0 +1,247 @@
var beenFullscreen = false;
var isFullscreen = false;
var main_section = document.getElementById('main-section');
var container_size = {
width: function() { return 1024; },
height: function() { return 768; }
};
var onWindowResize = (function() {
// Disable scrolling
window.onscroll = function () { window.scrollTo(0, 0); };
var mesh_number = 25;
var renderer, scene, controls, cube, container, plane, mouse= {x:0, y:0};
var bigmesh;
var raycaster;
var objects = [];
var cameras, cameraSelecter;
var spheres = new Array(mesh_number);
var visible = 0;
var stats;
var previewer;
var loader;
var coins = [];
var previousTime;
var tutorial;
init();
animate();
function init() {
// Initialize scene
scene = new THREE.Scene();
// Disable log for this time
BD.disable();
// Collidable objects to prevent camera from traversing objects
var collidableObjects = [];
// Initialize renderer
container = document.getElementById('container');
container.style.height = container_size.height() + 'px';
container.style.width = container_size.width() + 'px';
renderer = new THREE.WebGLRenderer({alpha:true, antialias:true});
renderer.setSize(container_size.width(), container_size.height());
// renderer.setSize(container_size.width(), container_size.height());
renderer.shadowMapEnabled = true;
renderer.setClearColor(0x87ceeb);
// Initialize previewer
previewer = new Previewer(renderer, scene);
previewer.domElement.style.position ="absolute";
previewer.domElement.style.cssFloat = 'top-left';
previewer.domElement.width = container_size.width();
previewer.domElement.height = container_size.height();
// Initialize stats counter
stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.cssFloat = "top-left";
var camera1 = new TutoCamera(50, container_size.width() / container_size.height(), 0.01, 100000, renderer, scene, onWindowResize, container_size, coins, container);
// Initialize pointer for pointer lock
var pointer = new MousePointer(camera1);
pointer.domElement.width = container_size.width();
pointer.domElement.height = container_size.height();
//
var startCanvas = new StartCanvas(camera1);
startCanvas.domElement.width = container_size.width();
startCanvas.domElement.height = container_size.height();
startCanvas.render();
// Add elements to page
container.appendChild( stats.domElement );
container.appendChild(Coin.domElement);
container.appendChild(startCanvas.domElement);
container.appendChild(pointer.domElement);
container.appendChild(previewer.domElement);
container.appendChild(renderer.domElement);
// Initialize pointer camera
tutorial = camera1.tutorial;
cameras = new CameraContainer(camera1, []);
tutorial.setCameras(cameras);
// Load peach scene
initPeach(camera1, scene);
initListeners();
tutorial.nextStep();
setInterval(animate, 20);
}
function initListeners() {
window.addEventListener('resize', onWindowResize, false);
// Transmit click event to camera selecter
container.addEventListener('mousedown', function(event) {
if (event.which == 1)
cameraSelecter.click(event);
}, false
);
// Update camera selecter when mouse moved
container.addEventListener('mousemove', function(event) {
cameraSelecter.update(event);
}, false
);
// Escape key to exit fullscreen mode
document.addEventListener('keydown', function(event) { if (event.keyCode == 27) { stopFullscreen();} }, false);
// HTML Bootstrap buttons
buttonManager = new ButtonManager(cameras, previewer);
// Camera selecter for hover and clicking recommendations
cameraSelecter = new CameraSelecter(renderer, scene, cameras, coins, buttonManager);
}
function render() {
cameraSelecter.update();
// Update recommendations (set raycastable if shown)
var transform = buttonManager.showArrows ? show : hide;
cameras.map(function(camera) {
if (camera instanceof RecommendedCamera) {
transform(camera);
camera.traverse(function(elt) {
elt.raycastable = buttonManager.showArrows;
});
}
});
// Update coins
coins.forEach(function(coin) { coin.update(); });
// Update main camera
var currentTime = Date.now() - previousTime;
cameras.updateMainCamera(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
// Update the recommendations
cameras.update(cameras.mainCamera());
// Set current position of camera
cameras.look();
var left = 0, bottom = 0, width = container_size.width(), height = container_size.height();
renderer.setScissor(left, bottom, width, height);
renderer.enableScissorTest(true);
renderer.setViewport(left, bottom, width, height);
THREEx.Transparency.update(cameras.mainCamera());
renderer.render(scene, cameras.mainCamera());
// Remove borders of preview
previewer.clear();
// Hide arrows in recommendation
cameras.map(function(camera) { if (camera instanceof RecommendedCamera) hide(camera); });
// Render preview
previewer.render(cameraSelecter.prev, container_size.width(), container_size.height());
}
function animate() {
// Render each frame
// requestAnimationFrame(animate);
// stats count the number of frames per second
stats.begin();
render();
stats.end();
}
function onWindowResize() {
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
previewer.domElement.width = container_size.width();
previewer.domElement.height = container_size.height();
renderer.setSize(container_size.width(), container_size.height());
cameras.forEach(function(camera) {camera.aspect = container_size.width() / container_size.height();});
cameras.forEach(function(camera) {camera.updateProjectionMatrix();});
render();
}
function hide(object) {
object.traverse(function(object) {object.visible = false;});
}
function show(object) {
object.traverse(function(object) {object.visible = true;});
}
return onWindowResize;
})();
function fullscreen() {
isFullscreen = true;
if (!beenFullscreen) {
beenFullscreen = true;
alert('To quit fullscren mode, type ESC key');
}
container.style.position = "absolute";
container.style.cssFloat = "top-left";
container.style.top = "50px";
container.style.bottom = "0px";
container.style.left = "0px";
container.style.right = "0px";
container.style.width="";
container.style.height="";
container.style.overflow = "hidden";
onWindowResize();
}
function stopFullscreen() {
isFullscreen = false;
container.style.position = "";
container.style.cssFloat = "";
container.style.top = "";
container.style.bottom = "";
container.style.left = "";
container.style.right = "";
container.style.width = container_size.width() + "px";
container.style.height = container_size.height() + "px";
onWindowResize();
}

View File

@@ -0,0 +1,91 @@
var mesh_number = 25;
var renderer, scene, controls, cube, container, plane, mouse= {x:0, y:0}, sphere, sphereLoader;
var bigmesh;
var raycaster;
var objects = [];
var spheres = new Array(mesh_number);
var visible = 0;
var previousTime;
var loader;
var container_size = {width: 1067, height: 600};
init();
animate();
function init() {
// on initialise le moteur de rendu
container = document.getElementById('container');
container.style.height = container_size.height + 'px';
container.style.width = container_size.width + 'px';
renderer = new THREE.WebGLRenderer({alpha:"true"});
renderer.setSize(container_size.width, container_size.height);
renderer.shadowMapEnabled = true;
// renderer.setClearColor(0x000000);
document.getElementById('container').appendChild(renderer.domElement);
// on initialise la scène
scene = new THREE.Scene();
raycaster = new THREE.Raycaster();
// init light
var directional_light = new THREE.DirectionalLight(0x999999);
directional_light.position.set(1, 0.5, 1).normalize();
directional_light.castShadow = true;
scene.add(directional_light);
var ambient_light = new THREE.AmbientLight(0x333333);
scene.add(ambient_light);
// on initialise la camera que lon place ensuite sur la scène
camera = new Camera(50, container_size.width / container_size.height, 1, 100000);
scene.add(camera);
window.addEventListener('resize', onWindowResize, false);
// Load the scene
// loader = new THREE.OBJLoader();
sphereLoader = new ProgressiveLoaderGeometry('/static/data/spheres/' + params.get.res + '.obj', scene, null);
sphereLoader.load();
sphere = sphereLoader.obj;
plane = new Plane(1000,1000);
plane.translate(0,0,-100);
plane.addToScene(scene);
setInterval(animate, 20);
}
function animate() {
// requestAnimationFrame(animate);
var currentTime = Date.now() - previousTime;
camera.update(isNaN(currentTime) ? 20 : currentTime);
previousTime = Date.now();
camera.look();
// sphere.addFace();
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = container.offsetWidth / container.offsetHeight;
camera.updateProjectionMatrix();
renderer.setSize(container.offsetWidth, container.offsetHeight);
renderer.render(scene, camera);
}
function hide(object) {
object.traverse(function(object) {object.visible = false;});
}
function show(object) {
object.traverse(function(object) {object.visible = true;});
}
function click(event) {
// Nope
}

View File

@@ -0,0 +1,31 @@
// class camera extends THREE.PerspectiveCamera
var Camera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
this.theta = 0;
this.position.x = Camera.DISTANCE_X;
this.position.z = Camera.DISTANCE_Z;
this.up = new THREE.Vector3(0,0,1);
this.target = new THREE.Vector3();
};
Camera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
// Update function
Camera.prototype.update = function(time) {
if (time === undefined) {
time = 20;
}
this.theta += 0.01 * time / 20;
this.position.x = Camera.DISTANCE_X*Math.cos(this.theta);
this.position.y = Camera.DISTANCE_X*Math.sin(this.theta);
};
// Look function
Camera.prototype.look = function() {
this.lookAt(this.target);
};
// Static members
Camera.DISTANCE_X = 1000;
Camera.DISTANCE_Z = 300;

View File

@@ -0,0 +1,77 @@
var CameraContainer = function (pointerCamera, cameras) {
if (cameras !== undefined) {
this.cameras = cameras;
} else {
this.cameras = [];
}
if (pointerCamera !== undefined) {
this.push(pointerCamera);
}
};
CameraContainer.prototype.mainCamera = function(id) {
if (id === undefined) {
return this.pointerCamera;
}
if (id >= cameras.length || id < 0) {
console.log('Warning : this camera does not exist');
return;
}
this.current_camera = id;
};
CameraContainer.prototype.forEach = function(callback) {
callback(this.pointerCamera);
this.cameras.forEach(callback);
};
CameraContainer.prototype.look = function() {
this.mainCamera().look();
};
CameraContainer.prototype.updateMainCamera = function(time) {
this.pointerCamera.update(time);
};
CameraContainer.prototype.update = function(position) {
this.cameras.map(function (elt) { elt.update(position); });
};
CameraContainer.prototype.push = function(camera) {
this.pointerCamera = camera;
this.push = function(camera) {
this.cameras.push(camera);
};
};
CameraContainer.prototype.get = function(i) {
return this.cameras[i];
};
CameraContainer.prototype.getByObject = function(object) {
for (var i in this.cameras) {
if (this.cameras[i].containsObject(object)) {
return this.get(i);
}
}
};
CameraContainer.prototype.setById = function(id) {
var i = this.getById(id);
if (i !== -1)
this.current_camera = i;
};
CameraContainer.prototype.nextCamera = function() {
if (this.cameras.length !== 0) {
this.current_camera++;
this.current_camera%=this.cameras.length;
}
};
CameraContainer.prototype.map = function(callback) {
this.cameras.map(callback);
};

View File

@@ -0,0 +1,743 @@
/**
* Represents a camera that can be used easily
* @constructor
* @augments THREE.PerspectiveCamera
*/
var PointerCamera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
/**
* A reference to the renderer
* @type {THREE.Renderer}
*/
this.renderer = arguments[4];
if (arguments[5] === undefined)
listenerTarget = document;
else
listenerTarget = arguments[5];
/**
* Theta angle of the camera
* @type {Number}
*/
this.theta = Math.PI;
/**
* Phi angle of the camera
* @type {Number}
*/
this.phi = Math.PI;
/**
* Indicates if the camera is following a linear motion
* @type {Boolean}
*/
this.moving = false;
/**
* Indicates if the user is dragging the camera
* @type {Boolean}
*/
this.dragging = false;
/**
* Current position of the cursor
* @type {Object}
*/
this.mouse = {x: 0, y: 0};
/**
* Current movement of the cursor
* @type {Object}
*/
this.mouseMove = {x: 0, y: 0};
/**
* Current position of the camera (optical center)
* @type {THREE.Vector}
*/
this.position = new THREE.Vector3();
/**
* Current direction of the camera
* @type {THREE.Vector}
*/
this.forward = new THREE.Vector3();
/**
* Vector pointing to the left of the camera
* @type {THREE.Vector}
*/
this.left = new THREE.Vector3();
/**
* Point that the camera is targeting
* @type {THREE.Vector}
*/
this.target = new THREE.Vector3(0,1,0);
/**
* Indicates the different motions that the camera should have according to the keyboard events
* @type {Object}
* @description Contains the following booleans
* <ul>
* <li>increasePhi</li>
* <li>decreasePhi</li>
* <li>increaseTheta</li>
* <li>decreaseTheta</li>
* <li>boost</li>
* <li>moveForward</li>
* <li>moveBackward</li>
* <li>moveLeft</li>
* <li>moveRight</li>
* </ul>
*/
this.motion = {};
/**
* Sentitivity of the mouse
* @type {Number}
*/
this.sensitivity = 0.05;
/**
* Speed of the camera
* @type {Number}
*/
this.speed = 1;
/**
* Raycaster used to compute collisions
* @type {THREE.Raycaster}
*/
this.raycaster = new THREE.Raycaster();
/**
* History of the moves of the camera
* @type {History}
*/
this.history = new History();
/**
* Option to enable or disable the pointer lock
* @type {Boolean}
*/
this.shouldLock = true;
/**
* Current state of the pointer (locked or not)
* @type {Boolean}
*/
this.pointerLocked = false;
/**
*
*/
this.listenerTarget = listenerTarget;
// Set events from the document
var self = this;
var onKeyDown = function(event) {self.onKeyDown(event);};
var onKeyUp = function(event) {self.onKeyUp(event);};
var onMouseDown = function(event) {if (event.which === 1) self.onMouseDown(event); };
var onMouseUp = function(event) {if (event.which === 1) self.onMouseUp(event); };
var onMouseMove = function(event) {self.onMouseMove(event); };
document.addEventListener('keydown', onKeyDown, false);
document.addEventListener('keyup', onKeyUp, false);
document.addEventListener('pointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('mozpointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('webkitpointerlockchange', function(event) { self.onPointerLockChange(event); }, false);
document.addEventListener('mousemove', function(event) {self.onMouseMovePointer(event);}, false);
listenerTarget.addEventListener('mousedown', function() {self.lockPointer();}, false);
listenerTarget.addEventListener('mousedown', onMouseDown, false);
listenerTarget.addEventListener('mousemove', onMouseMove, false);
listenerTarget.addEventListener('mouseup', onMouseUp, false);
listenerTarget.addEventListener('mouseout', onMouseUp, false);
/**
* Option to enable or disable the collisions
* @type {Boolean}
*/
this.collisions = true;
/**
* Is true when we should log the camera angles. It will be set to false
* once is done, and reset to true after a certain period of time
* @param {Boolean}
*/
this.shouldLogCameraAngles = true;
/**
* The camera we will move to when we'll reset the camera
* @param {Object}
*/
this.resetElements = resetBobombElements();
};
PointerCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
PointerCamera.prototype.constructor = PointerCamera;
/**
* Locks the pointer inside the canvas, and displays a gun sight at the middle of the renderer
* This method works only if the browser supports requestPointerLock
*/
PointerCamera.prototype.lockPointer = function() {
if (this.shouldLock) {
this.renderer.domElement.requestPointerLock =
this.renderer.domElement.requestPointerLock ||
this.renderer.domElement.mozRequestPointerLock ||
this.renderer.domElement.webkitRequestPointerLock;
if (this.renderer.domElement.requestPointerLock) {
this.renderer.domElement.requestPointerLock();
}
}
};
/**
* Check that the pointer is locked or not, and updated locked attribute
* @returns true if the pointer is locked, false otherwise
*/
PointerCamera.prototype.isLocked = function() {
var toto =
document.pointerLockElement === this.renderer.domElement ||
document.mozPointerLockElement === this.renderer.domElement ||
document.webkitPointerLockElement === this.renderer.domElement;
return toto;
};
/**
* Update the camera when the pointer lock changes state
*/
PointerCamera.prototype.onPointerLockChange = function() {
if (this.isLocked()) {
// The pointer is locked : adapt the state of the camera
this.pointerLocked = true;
this.mousePointer.render();
this.mouse.x = this.renderer.domElement.width/2;
this.mouse.y = this.renderer.domElement.height/2;
// Remove start canvas
this.startCanvas.clear();
} else {
this.pointerLocked = false;
this.mousePointer.clear();
this.theta = this.previousTheta;
this.phi = this.previousPhi;
this.mouseMove.x = 0;
this.mouseMove.y = 0;
// Draw start canvas only if should lock
if (this.shouldLock)
this.startCanvas.render();
else
this.startCanvas.clear();
}
};
/**
* Update the position of the camera
* @param {Number} time number of milliseconds between the previous and the next frame
*/
PointerCamera.prototype.update = function(time) {
if (this.moving) {
this.linearMotion(time);
} else if (this.movingHermite) {
this.hermiteMotion(time);
} else {
this.normalMotion(time);
}
};
/**
* Update the camera according to its linear motion
* @param {Number} time number of milliseconds between the previous and the next frame
*/
PointerCamera.prototype.linearMotion = function(time) {
var position_direction = Tools.diff(this.new_position, this.position);
var target_direction = Tools.diff(this.new_target, this.target);
this.position.add(Tools.mul(position_direction, 0.05 * time / 20));
this.target.add(Tools.mul(target_direction, 0.05 * time / 20));
if (Tools.norm2(Tools.diff(this.position, this.new_position)) < 0.01 &&
Tools.norm2(Tools.diff(this.target, this.new_target)) < 0.01) {
this.moving = false;
this.anglesFromVectors();
}
};
/**
* Update the camera according to its hermite motion
* @param {Number} time number of milliseconds between the previous and the next frame
*/
PointerCamera.prototype.hermiteMotion = function(time) {
var e = this.hermitePosition.eval(this.t);
this.position.x = e.x;
this.position.y = e.y;
this.position.z = e.z;
this.target = Tools.sum(this.position, this.hermiteAngles.eval(this.t));
this.t += 0.01 * time / 20;
if (this.t > 1) {
this.movingHermite = false;
this.anglesFromVectors();
}
};
/**
* Update the camera according to the user's input
* @param {Number} time number of milliseconds between the previous and the next frame
*/
PointerCamera.prototype.normalMotion = function(time) {
// Update angles
if (this.motion.increasePhi) {this.phi += this.sensitivity * time / 20; this.changed = true; }
if (this.motion.decreasePhi) {this.phi -= this.sensitivity * time / 20; this.changed = true; }
if (this.motion.increaseTheta) {this.theta += this.sensitivity * time / 20; this.changed = true; }
if (this.motion.decreaseTheta) {this.theta -= this.sensitivity * time / 20; this.changed = true; }
if ( this.isLocked() || this.dragging) {
this.theta += (this.mouseMove.x * 20 / time);
this.phi -= (this.mouseMove.y * 20 / time);
this.mouseMove.x = 0;
this.mouseMove.y = 0;
this.vectorsFromAngles();
this.changed = true;
if (this.shouldLogCameraAngles) {
this.shouldLogCameraAngles = false;
var self = this;
setTimeout(function() {
self.shouldLogCameraAngles = true;
}, 100);
var event = new BD.Event.KeyboardEvent();
event.camera = this;
}
}
// Clamp phi and theta
this.phi = Math.min(Math.max(-(Math.PI/2-0.1),this.phi), Math.PI/2-0.1);
this.theta = ((this.theta - Math.PI) % (2*Math.PI)) + Math.PI;
// Compute vectors (position and target)
this.vectorsFromAngles();
// Update with events
var delta = 0.1;
var forward = this.forward.clone();
forward.multiplyScalar(400.0 * delta);
var left = this.up.clone();
left.cross(forward);
left.normalize();
left.multiplyScalar(400.0 * delta);
// Move only if no collisions
var speed = this.speed * time / 20;
var direction = new THREE.Vector3();
if (this.motion.boost) speed *= 10;
if (this.motion.moveForward) {direction.add(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveBackward) {direction.sub(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveLeft) {direction.add(Tools.mul(left, speed)); this.changed = true;}
if (this.motion.moveRight) {direction.sub(Tools.mul(left, speed)); this.changed = true;}
if (!this.collisions || !this.isColliding(direction)) {
this.position.add(direction);
}
// Update angle
this.target = this.position.clone();
this.target.add(forward);
};
/**
* Reset the camera to its resetElements, and finishes any motion
*/
PointerCamera.prototype.reset = function() {
this.resetPosition();
this.moving = false;
this.movingHermite = false;
(new BD.Event.ResetClicked()).send();
};
/**
* Reset the position of th camera
*/
PointerCamera.prototype.resetPosition = function() {
this.position.copy(this.resetElements.position);
this.target.copy(this.resetElements.target);
this.anglesFromVectors();
};
/**
* Computes the vectors (forward, left, ...) according to theta and phi
*/
PointerCamera.prototype.vectorsFromAngles = function() {
// Update direction
this.forward.y = Math.sin(this.phi);
var cos = Math.cos(this.phi);
this.forward.z = cos * Math.cos(this.theta);
this.forward.x = cos * Math.sin(this.theta);
this.forward.normalize();
};
/**
* Computes theta and phi according to the vectors (forward, left, ...)
*/
PointerCamera.prototype.anglesFromVectors = function() {
var forward = Tools.diff(this.target, this.position);
forward.normalize();
this.phi = Math.asin(forward.y);
// Don't know why this line works... But thanks Thierry-san and
// Bastien because it seems to work...
this.theta = Math.atan2(forward.x, forward.z);
};
/**
* Creates a linear motion to another camera
* @param {Camera} camera Camera to move to
* @param {Boolean} [toSave=true] true if you want to save the current state of the camera
*/
PointerCamera.prototype.move = function(otherCamera, toSave) {
if (toSave === undefined)
toSave = true;
this.moving = true;
this.new_target = otherCamera.target.clone();
this.new_position = otherCamera.position.clone();
var t = [0,1];
var f = [this.position.clone(), this.new_position];
var fp = [Tools.diff(this.target, this.position), Tools.diff(this.new_target, this.new_position)];
this.hermite = new Hermite.Polynom(t,f,fp);
this.t = 0;
if (toSave) {
if (this.changed) {
this.save();
this.changed = false;
}
this.history.addState({position: otherCamera.position.clone(), target: otherCamera.target.clone()});
}
};
/**
* Creates a hermite motion to another camera
* @param {Camera} camera Camera to move to
* @param {Boolean} [toSave=true] true if you want to save the current state of the camera
*/
PointerCamera.prototype.moveHermite = function(otherCamera, toSave) {
if (toSave === undefined)
toSave = true;
this.movingHermite = true;
this.t = 0;
this.hermitePosition = new Hermite.special.Polynom(
this.position.clone(),
otherCamera.position.clone(),
Tools.mul(Tools.diff(otherCamera.target, otherCamera.position).normalize(),4)
);
this.hermiteAngles = new Hermite.special.Polynom(
Tools.diff(this.target, this.position),
Tools.diff(otherCamera.target, otherCamera.position),
new THREE.Vector3()
);
if (toSave) {
if (this.changed) {
this.save();
this.changed = false;
}
this.history.addState({position: otherCamera.position.clone(), target: otherCamera.target.clone()});
}
};
/**
* Checks the collisions between the collidables objects and the camera
* @param {THREE.Vector3} direction the direction of the camera
* @returns {Boolean} true if there is a collision, false otherwise
*/
PointerCamera.prototype.isColliding = function(direction) {
this.raycaster.set(this.position, direction.clone().normalize());
var intersects = this.raycaster.intersectObjects(this.collidableObjects, true);
for (var i in intersects) {
if (intersects[i].distance < Tools.norm(direction) + this.speed * 300 &&
intersects[i].object.raycastable) {
return true;
}
}
return false;
};
/**
* Look method. Equivalent to gluLookAt for the current camera
*/
PointerCamera.prototype.look = function() {
this.lookAt(this.target);
};
/**
* Adds the camera to the scene
*/
PointerCamera.prototype.addToScene = function(scene) {
scene.add(this);
};
/**
* Manages keyboard events
* @param {event} event the event that happened
* @param {Booelean} toSet true if the key was pressed, false if released
*/
PointerCamera.prototype.onKeyEvent = function(event, toSet) {
// Create copy of state
var motionJsonCopy = JSON.stringify(this.motion);
switch ( event.keyCode ) {
// Azerty keyboards
case 38: case 90: this.motion.moveForward = toSet; break; // up / z
case 37: case 81: this.motion.moveLeft = toSet; break; // left / q
case 40: case 83: this.motion.moveBackward = toSet; break; // down / s
case 39: case 68: this.motion.moveRight = toSet; break; // right / d
case 32: this.motion.boost = toSet; break;
// Qwerty keyboards
case 38: case 87: this.motion.moveForward = toSet; break; // up / w
case 37: case 65: this.motion.moveLeft = toSet; break; // left / a
case 40: case 83: this.motion.moveBackward = toSet; break; // down / s
case 39: case 68: this.motion.moveRight = toSet; break; // right / d
case 73: case 104: this.motion.increasePhi = toSet; break; // 8 Up for angle
case 75: case 98: this.motion.decreasePhi = toSet; break; // 2 Down for angle
case 74: case 100: this.motion.increaseTheta = toSet; break; // 4 Left for angle
case 76: case 102: this.motion.decreaseTheta = toSet; break; // 6 Right for angle
case 13: if (toSet) this.log(); break;
}
if (motionJsonCopy != JSON.stringify(this.motion)) {
// Log any change
var e = new BD.Event.KeyboardEvent();
e.camera = this;
e.send();
}
};
/**
* Manages the key pressed events
* @param {event} event the event to manage
*/
PointerCamera.prototype.onKeyDown = function(event) {
this.onKeyEvent(event, true);
};
/**
* Manages the key released events
* @param {event} event the event to manage
*/
PointerCamera.prototype.onKeyUp = function(event) {
this.onKeyEvent(event, false);
};
/**
* Manages the mouse down events. Start drag'n'dropping if the options are set to drag'n'drop
* @param {event} event the event to manage
*/
PointerCamera.prototype.onMouseDown = function(event) {
if (!this.shouldLock) {
this.mouse.x = ( ( event.clientX - this.renderer.domElement.offsetLeft ) / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - this.renderer.domElement.offsetTop ) / this.renderer.domElement.height ) * 2 + 1;
this.dragging = true;
this.mouseMoved = false;
}
};
/**
* Manages the mouse move events. Modifies the target of the camera according to the drag'n'drop motion
* @param {event} event the event to manage
*/
PointerCamera.prototype.onMouseMove = function(event) {
if (!this.shouldLock && this.dragging) {
var mouse = {x: this.mouse.x, y: this.mouse.y};
this.mouse.x = ( ( event.clientX - this.renderer.domElement.offsetLeft ) / this.renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - this.renderer.domElement.offsetTop ) / this.renderer.domElement.height ) * 2 + 1;
this.mouseMove.x = this.mouse.x - mouse.x;
this.mouseMove.y = this.mouse.y - mouse.y;
this.mouseMoved = true;
}
};
/**
* Manages the mouse move envent in case of pointer lock
* @param {event} event the event to manage
*/
PointerCamera.prototype.onMouseMovePointer = function(e) {
if (this.isLocked()) {
// Backup theta and phi
this.previousTheta = this.theta;
this.previousPhi = this.phi;
this.mouseMove.x = e.movementX || e.mozMovementX || e.webkitMovementX || 0;
this.mouseMove.y = e.movementY || e.mozMovementY || e.webkitMovementY || 0;
this.mouseMove.x *= -(this.sensitivity/5);
this.mouseMove.y *= (this.sensitivity/5);
this.mouseMoved = true;
}
};
/**
* Manages the mouse up event. Stops the dragging
* @param {event} event the event to manage
*/
PointerCamera.prototype.onMouseUp = function(event) {
this.onMouseMove(event);
// Send log to DB
if (this.dragging && this.mouseMoved && !this.moving && !this.movingHermite) {
var e = new BD.Event.KeyboardEvent();
e.camera = this;
e.send();
}
this.dragging = false;
};
/**
* Logs the camera to the terminal (pratical to create recommended views)
*/
PointerCamera.prototype.log = function() {
console.log("createCamera(\nnew THREE.Vector3(" + this.position.x + "," + this.position.y + ',' + this.position.z + '),\n' +
"new THREE.Vector3(" + this.target.x + "," + this.target.y + ',' + this.target.z + ')\n)');
};
/**
* Save the current state of the camera in the history
*/
PointerCamera.prototype.save = function() {
var backup = {};
backup.position = this.position.clone();
backup.target = this.target.clone();
this.history.addState(backup);
};
/**
* Undo last motion according to the history
*/
PointerCamera.prototype.undo = function() {
var move = this.history.undo();
if (move !== undefined) {
var event = new BD.Event.PreviousNextClicked();
event.previous = true;
event.camera = move;
event.send();
this.move(move, false);
}
};
/**
* Redo last motion according to the history
*/
PointerCamera.prototype.redo = function() {
var move = this.history.redo();
if (move !== undefined) {
var event = new BD.Event.PreviousNextClicked();
event.previous = false;
event.camera = move;
event.send();
this.move(move, false);
}
};
/**
* Checks if there is a undo possibility in the history
* @returns {Boolean} true if undo is possible, false otherwise
*/
PointerCamera.prototype.undoable = function() {
return this.history.undoable();
};
/**
* Checks if there is a redo possibility in the history
* @returns {Boolean} true if redo is possible, false otherwise
*/
PointerCamera.prototype.redoable = function() {
return this.history.redoable();
};
PointerCamera.prototype.toList = function() {
this.updateMatrix();
this.updateMatrixWorld();
var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices(this.projectionMatrix, this.matrixWorldInverse);
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(this.projectionMatrix, this.matrixWorldInverse));
var ret =
[[this.position.x, this.position.y, this.position.z],
[this.target.x, this.target.y, this.target.z]];
for (var i = 0; i < frustum.planes.length; i++) {
var p = frustum.planes[i];
ret.push([
p.normal.x, p.normal.y, p.normal.z, p.constant
]);
}
return ret;
};

View File

@@ -0,0 +1,202 @@
// class camera extends THREE.PerspectiveCamera
var ReplayCamera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
this.coins = arguments[4];
this.started = false;
this.counter = 0;
this.position = new THREE.Vector3();
this.target = new THREE.Vector3();
this.new_position = new THREE.Vector3();
this.new_target = new THREE.Vector3();
var id = params.get.id;
var xhr = new XMLHttpRequest();
xhr.open("GET", "/prototype/replay_info/" + id, true);
var self = this;
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
self.path = JSON.parse(xhr.responseText);
self.started = true;
self.nextEvent();
}
};
xhr.send();
// Set Position
this.theta = Math.PI;
this.phi = Math.PI;
this.resetElements = resetBobombElements();
};
ReplayCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
ReplayCamera.prototype.constructor = ReplayCamera;
ReplayCamera.prototype.look = function() {
this.lookAt(this.target);
};
// Update function
ReplayCamera.prototype.update = function(time) {
if (this.started) {
if (this.event.type == 'camera') {
this.cameraMotion(time);
} else if (this.event.type == 'previousnext') {
this.linearMotion(time / 5);
} else if (this.event.type == 'arrow') {
this.hermiteMotion(time);
}
// } else if (this.event.type == 'coin') {
// // Nothing to do
// } else if (this.event.type == 'reset') {
// // Nothing to do
// }
}
};
ReplayCamera.prototype.linearMotion = function(time) {
var tmp = Tools.sum(Tools.mul(this.old_position, 1-this.t), Tools.mul(this.new_position, this.t));
this.position.x = tmp.x;
this.position.y = tmp.y;
this.position.z = tmp.z;
this.t += 0.1 * time / 20;
if (this.t > 1) {
this.nextEvent();
}
};
ReplayCamera.prototype.cameraMotion = function(time) {
var tmp = Tools.sum(Tools.mul(this.old_position, 1-this.t), Tools.mul(this.new_position, this.t));
this.position.x = tmp.x;
this.position.y = tmp.y;
this.position.z = tmp.z;
this.target = Tools.sum(Tools.mul(this.old_target, 1-this.t), Tools.mul(this.new_target, this.t));
this.t += 1 / (((new Date(this.path[this.counter].time)).getTime() - (new Date(this.path[this.counter-1].time)).getTime()) / 20);
if (this.t > 1) {
this.nextEvent();
}
};
ReplayCamera.prototype.hermiteMotion = function(time) {
var e = this.hermitePosition.eval(this.t);
this.position.x = e.x;
this.position.y = e.y;
this.position.z = e.z;
this.target = Tools.sum(this.position, this.hermiteAngles.eval(this.t));
this.t += 0.01 * time / 20;
if (this.t > 1) {
this.nextEvent();
}
};
ReplayCamera.prototype.nextEvent = function() {
this.counter++;
// Finished
if (this.counter >= this.path.length) {
this.started = false;
return;
}
this.event = this.path[this.counter];
if (this.event.type == 'camera') {
this.move(this.event);
} else if (this.event.type == 'coin') {
this.coins[this.event.id].get();
// Wait a little before launching nextEvent
(function(self) {
setTimeout(function() {
self.nextEvent();
},500);
})(this);
} else if (this.event.type == 'arrow') {
this.moveHermite(this.cameras.cameras[this.event.id]);
} else if (this.event.type == 'reset') {
this.reset();
(function (self) {
setTimeout(function() {
self.nextEvent();
},500);
})(this);
} else if (this.event.type == 'previousnext') {
this.move(this.event);
} else if (this.event.type == 'hovered') {
this.nextEvent();
}
};
ReplayCamera.prototype.reset = function() {
this.resetPosition();
this.moving = false;
this.movingHermite = false;
};
ReplayCamera.prototype.resetPosition = function() {
this.position.copy(this.resetElements.position);
this.target.copy(this.resetElements.target);
this.anglesFromVectors();
};
ReplayCamera.prototype.vectorsFromAngles = function() {
// Update direction
this.forward.y = Math.sin(this.phi);
var cos = Math.cos(this.phi);
this.forward.z = cos * Math.cos(this.theta);
this.forward.x = cos * Math.sin(this.theta);
this.forward.normalize();
};
ReplayCamera.prototype.anglesFromVectors = function() {
// Update phi and theta so that return to reality does not hurt
var forward = Tools.diff(this.target, this.position);
forward.normalize();
this.phi = Math.asin(forward.y);
// Don't know why this line works... But thanks Thierry-san and
// Bastien because it seems to work...
this.theta = Math.atan2(forward.x, forward.z);
};
ReplayCamera.prototype.move = function(otherCamera) {
this.moving = true;
this.old_target = this.target.clone();
this.old_position = this.position.clone();
this.new_target = new THREE.Vector3(otherCamera.target.x, otherCamera.target.y, otherCamera.target.z);
this.new_position = new THREE.Vector3(otherCamera.position.x, otherCamera.position.y, otherCamera.position.z);
this.t = 0;
};
ReplayCamera.prototype.moveHermite = function(otherCamera) {
this.movingHermite = true;
this.t = 0;
this.hermitePosition = new Hermite.special.Polynom(
this.position.clone(),
otherCamera.position.clone(),
Tools.mul(Tools.diff(otherCamera.target, otherCamera.position).normalize(),4)
);
this.hermiteAngles = new Hermite.special.Polynom(
Tools.diff(this.target, this.position),
Tools.diff(otherCamera.target, otherCamera.position),
new THREE.Vector3()
);
};
ReplayCamera.prototype.save = function() {};

View File

@@ -0,0 +1,82 @@
var MousePointer = function(camera) {
this.domElement = document.createElement('canvas');
this.domElement.style.position = 'absolute';
this.domElement.style.cssFloat = 'top-left';
this.ctx = this.domElement.getContext('2d');
this.size = 10;
this.drawn = false;
camera.mousePointer = this;
this.style = MousePointer.NONE;
};
MousePointer.NONE = 0;
MousePointer.BLACK = 1;
MousePointer.RED = 2;
MousePointer.toColor = function(style) {
switch (style) {
case MousePointer.NONE:
return null;
case MousePointer.BLACK:
return '#000000';
case MousePointer.RED:
return '#ff0000';
}
};
MousePointer.prototype.render = function(style) {
if (this.style !== style) {
if (style === MousePointer.NONE) {
// Clear canvas
this.domElement.width = this.domElement.width;
this.style = MousePointer.NONE;
} else {
this.domElement.width = this.domElement.width;
var i = container_size.width() / 2;
var imin = i - this.size;
var imax = i + this.size;
var j = container_size.height() / 2;
var jmin = j - this.size;
var jmax = j + this.size;
this.ctx.beginPath();
this.ctx.moveTo(imin, j);
this.ctx.lineTo(imax, j);
this.ctx.moveTo(i, jmin);
this.ctx.lineTo(i, jmax);
this.ctx.closePath();
this.ctx.lineWidth = 5;
this.ctx.strokeStyle = '#ffffff';
this.ctx.stroke();
this.ctx.lineWidth = 2;
this.ctx.strokeStyle = MousePointer.toColor(style);
this.ctx.stroke();
this.style = style;
}
}
};
MousePointer.prototype.clear = function() {
this.render(MousePointer.NONE);
};

View File

@@ -0,0 +1,96 @@
Math.clamp = Math.clamp || function(number, min, max) {
return Math.max(Math.min(number, max), min);
};
var Previewer = function(renderer, scene) {
this.domElement = document.createElement('canvas');
this.ctx = this.domElement.getContext('2d');
this.renderer = renderer;
this.fixed = false;
this.scene = scene;
this.drawn = false;
this.drawnBefore = false;
};
Previewer.prototype.render = function(prev, container_width, container_height) {
var width, height, left, bottom;
if (prev.go) {
width = Math.floor(container_width / 5);
height = Math.floor(container_height / 5);
if (!this.fixed) {
left = Math.floor(prev.x - width/2);
bottom = Math.floor(this.renderer.domElement.height - prev.y + height/5);
// Translate box if too high
if (bottom + height > this.renderer.domElement.height) {
bottom -= 7 * height / 5;
}
// Translate box if too on the side
left = Math.clamp(left, width / 5, this.renderer.domElement.width - 6 * width / 5);
} else {
left = 0;
bottom = 0;
}
// Draw border
var can_bottom = container_height - bottom - height ;
this.ctx.strokeStyle = "#ffffff";
this.ctx.beginPath();
this.ctx.moveTo(left-1, can_bottom);
this.ctx.lineTo(left-1, can_bottom + height);
this.ctx.lineTo(left + width-1, can_bottom + height);
this.ctx.lineTo(left + width-1, can_bottom);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.strokeStyle = "#000000";
this.ctx.beginPath();
this.ctx.moveTo(left, can_bottom + 1);
this.ctx.lineTo(left, can_bottom + height - 1);
this.ctx.lineTo(left + width - 2 , can_bottom + height-1);
this.ctx.lineTo(left + width - 2, can_bottom+1);
this.ctx.closePath();
this.ctx.stroke();
// Do render in previsualization
prev.camera.look();
this.renderer.setScissor(left, bottom, width, height);
this.renderer.enableScissorTest(true);
this.renderer.setViewport(left, bottom, width, height);
this.renderer.render(this.scene, prev.camera);
this.update(true);
if (this.prevCamera !== prev.camera) {
this.clearNeeded = true;
}
this.prevCamera = prev.camera;
} else {
this.update(false);
}
if (this.drawnBefore && !this.drawn) {
this.clearNeeded = true;
}
};
Previewer.prototype.clear = function() {
if (this.clearNeeded) {
this.domElement.width = this.domElement.width;
this.clearNeeded = false;
}
};
Previewer.prototype.fixedRecommendation = function(bool) {
this.fixed = bool;
};
Previewer.prototype.update = function(arg) {
this.drawnBefore = this.drawn;
this.drawn = arg;
};

View File

@@ -0,0 +1,44 @@
var StartCanvas = function(camera) {
this.domElement = document.createElement('canvas');
this.domElement.style.position = 'absolute';
this.domElement.style.cssFloat = 'top-left';
this.ctx = this.domElement.getContext('2d');
this.shown = false;
camera.startCanvas = this;
};
StartCanvas.prototype.render = function() {
if (!this.shown) {
this.ctx.fillStyle = 'white';
this.ctx.globalAlpha = 0.7;
this.ctx.fillRect(0,0,this.domElement.width, this.domElement.height);
this.ctx.font = '30px Verdana';
this.ctx.globalAlpha = 1;
this.ctx.fillStyle = 'black';
this.ctx.fillText('Click here to lock the pointer !', container_size.width()/3.25, container_size.height()/2-10);
this.shown = true;
}
};
StartCanvas.prototype.clear = function() {
if (this.shown) {
// Clear canvas
this.domElement.width = this.domElement.width;
this.shown = false;
}
};

View File

@@ -0,0 +1,286 @@
var _parseList = function(arr) {
var ret = {};
ret.index = arr[1];
if (arr[0] === 'v') {
ret.type = 'vertex';
ret.x = arr[2];
ret.y = arr[3];
ret.z = arr[4];
} else if (arr[0] === 'vt') {
ret.type = 'texCoord';
ret.x = arr[2];
ret.y = arr[3];
} else if (arr[0] === 'f') {
ret.type = 'face';
// Only Face3 are allowed
vertexIndices = arr[2];
textureIndices = arr[3];
normalIndices = arr[4];
// Vertex indices
ret.a = vertexIndices[0];
ret.b = vertexIndices[1];
ret.c = vertexIndices[2];
// Texutre indices (if they exist)
if (textureIndices.length > 0) {
ret.aTexture = textureIndices[0];
ret.bTexture = textureIndices[1];
ret.cTexture = textureIndices[2];
}
// Normal indices (if they exist)
if (normalIndices.length > 0) {
ret.aNormal = normalIndices[0];
ret.bNormal = normalIndices[1];
ret.cNormal = normalIndices[2];
}
} else if (arr[0] === 'vn') {
// Normal
ret.type = "normal";
ret.x = arr[2];
ret.y = arr[3];
ret.z = arr[4];
} else if (arr[0] === 'u') {
// usemtl
ret.index = -1;
ret.type = 'usemtl';
ret.materialName = arr[1];
ret.vLength = arr[2];
ret.fLength = arr[3];
ret.texCoordsExist = arr[4];
ret.normalsExist = arr[5];
}
return ret;
};
var ProgressiveLoader = function(path, scene, camera, callback) {
// Init attributes
this.objPath = path.substring(1, path.length);
this.texturesPath = path.substring(0, path.lastIndexOf('/')) + '/';
this.mtlPath = path.replace('.obj', '.mtl');
this.scene = scene;
this.callback = callback;
this.counter = 0;
this.obj = new THREE.Object3D();
scene.add(this.obj);
this.vertices = [];
this.texCoords = [];
this.normals = [];
// Init MTLLoader
this.loader = new THREE.MTLLoader(this.texturesPath);
// Init io stuff
this.socket = io();
this.initIOCallbacks();
this.camera = camera;
};
ProgressiveLoader.prototype.load = function() {
var self = this;
this.loader.load(self.mtlPath, function(materialCreator) {
self.materialCreator = materialCreator;
materialCreator.preload();
self.start();
});
};
ProgressiveLoader.prototype.initIOCallbacks = function() {
var self = this;
this.socket.on('ok', function() {
console.log('ok');
self.socket.emit('next');
});
this.socket.on('elements', function(arr) {
// console.log("Received elements for the " + (++self.counter) + "th time !");
for (var i = 0; i < arr.length; i++) {
var elt = _parseList(arr[i]);
// console.log(elts);
if (elt.type === 'vertex') {
// New vertex arrived
self.vertices[elt.index] = [elt.x, elt.y, elt.z];
} else if (elt.type === 'texCoord') {
// New texCoord arrived
self.texCoords[elt.index] = [elt.x, elt.y];
} else if (elt.type === 'normal') {
// New normal arrived
self.normals[elt.index] = [elt.x, elt.y, elt.z];
} else if (elt.type === 'usemtl') {
if (self.currentMesh !== undefined) {
self.currentMesh.geometry.computeBoundingSphere();
if (self.currentMesh.geometry.attributes.normal === undefined) {
self.currentMesh.geometry.computeVertexNormals();
}
}
// Must create new mesh
// console.log("New mesh arrived : " + elt.materialName);
// Create mesh material
var material;
if (elt.materialName === null) {
// If no material, create a default material
material = new THREE.MeshLambertMaterial({color: 'red'});
} else {
// If material name exists, load if from material, and do a couple of settings
material = self.materialCreator.materials[elt.materialName.trim()];
material.side = THREE.DoubleSide;
if (material.map)
material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;
}
// Create mesh geometry
var geometry = new THREE.BufferGeometry();
geometry.dynamic = true;
var positionArray = new Float32Array(elt.fLength * 3 * 3);
var positionAttribute = new THREE.BufferAttribute(positionArray, 3);
geometry.addAttribute('position', positionAttribute);
// Add other attributes if necessary
if (elt.texCoordsExist) {
// console.log("Mesh with textures");
var uvArray = new Float32Array(elt.fLength * 3 * 2);
var uvAttribute = new THREE.BufferAttribute(uvArray, 2);
geometry.addAttribute('uv', uvAttribute);
}
if (elt.normalsExist) {
// console.log("Mesh with normals");
var normalArray = new Float32Array(elt.fLength * 3 * 3);
var normalAttribute = new THREE.BufferAttribute(normalArray, 3);
geometry.addAttribute('normal', normalAttribute);
}
// Create mesh
var mesh = new THREE.Mesh(geometry, material);
self.currentMesh = mesh;
self.obj.add(mesh);
if (typeof self.callback === 'function') {
self.callback(mesh);
}
} else if (elt.type === 'face') {
// New face arrived : add it into current mesh
self.currentMesh.geometry.attributes.position.array[elt.index * 9 ] = self.vertices[elt.a][0];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 1] = self.vertices[elt.a][1];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 2] = self.vertices[elt.a][2];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 3] = self.vertices[elt.b][0];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 4] = self.vertices[elt.b][1];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 5] = self.vertices[elt.b][2];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 6] = self.vertices[elt.c][0];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 7] = self.vertices[elt.c][1];
self.currentMesh.geometry.attributes.position.array[elt.index * 9 + 8] = self.vertices[elt.c][2];
self.currentMesh.geometry.attributes.position.needsUpdate = true;
// If normals
if (elt.aNormal !== undefined) {
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 ] = self.normals[elt.aNormal][0];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 1] = self.normals[elt.aNormal][1];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 2] = self.normals[elt.aNormal][2];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 3] = self.normals[elt.bNormal][0];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 4] = self.normals[elt.bNormal][1];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 5] = self.normals[elt.bNormal][2];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 6] = self.normals[elt.cNormal][0];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 7] = self.normals[elt.cNormal][1];
self.currentMesh.geometry.attributes.normal.array[elt.index * 9 + 8] = self.normals[elt.cNormal][2];
self.currentMesh.geometry.attributes.normal.needsUpdate = true;
}
if (elt.aTexture !== undefined) {
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 ] = self.texCoords[elt.aTexture][0];
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 + 1] = self.texCoords[elt.aTexture][1];
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 + 2] = self.texCoords[elt.bTexture][0];
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 + 3] = self.texCoords[elt.bTexture][1];
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 + 4] = self.texCoords[elt.cTexture][0];
self.currentMesh.geometry.attributes.uv.array[elt.index * 6 + 5] = self.texCoords[elt.cTexture][1];
self.currentMesh.geometry.attributes.uv.needsUpdate = true;
}
}
}
// Ask for next elements
self.socket.emit('next');
});
this.socket.on('disconnect', function() {
console.log('Finished !');
self.finished = true;
});
};
ProgressiveLoader.prototype.start = function() {
this.socket.emit('request', this.objPath);
};

View File

@@ -0,0 +1,377 @@
/**
* Parse a list as it is sent by the server and gives a slightly more comprehensible result
* @private
*/
var _parseList2 = function(arr) {
var ret = {};
ret.index = arr[1];
if (arr[0] === 'v') {
ret.type = 'vertex';
ret.x = arr[2];
ret.y = arr[3];
ret.z = arr[4];
} else if (arr[0] === 'vt') {
ret.type = 'texCoord';
ret.x = arr[2];
ret.y = arr[3];
} else if (arr[0] === 'f') {
ret.type = 'face';
ret.mesh = arr[2];
// Only Face3 are allowed
vertexIndices = arr[3];
textureIndices = arr[4];
normalIndices = arr[5];
// Vertex indices
ret.a = vertexIndices[0];
ret.b = vertexIndices[1];
ret.c = vertexIndices[2];
// Texutre indices (if they exist)
if (textureIndices.length > 0) {
ret.aTexture = textureIndices[0];
ret.bTexture = textureIndices[1];
ret.cTexture = textureIndices[2];
}
// Normal indices (if they exist)
if (normalIndices.length > 0) {
ret.aNormal = normalIndices[0];
ret.bNormal = normalIndices[1];
ret.cNormal = normalIndices[2];
}
} else if (arr[0] === 'vn') {
// Normal
ret.type = "normal";
ret.x = arr[2];
ret.y = arr[3];
ret.z = arr[4];
} else if (arr[0] === 'u') {
// usemtl
ret.index = -1;
ret.type = 'usemtl';
ret.materialName = arr[1];
ret.vLength = arr[2];
ret.fLength = arr[3];
ret.texCoordsExist = arr[4];
ret.normalsExist = arr[5];
}
return ret;
};
/**
* Loads a mesh from socket.io
* @param {string} path path to the .obj file
* @param {THREE.Scene} scene to add the object
* @param {PointerCamera} camera the camera that will be sent to server for smart
* streaming (can be null, then the server will stream the mesh in the .obj
* order)
* @param {function} callback callback to call on the objects when they're created
* @constructor
*/
var ProgressiveLoaderGeometry = function(path, scene, camera, callback) {
/**
* Path to the .obj file
* @type {string}
*/
this.objPath = path;
/**
* Path to the folder where the textures are
* @type {string}
*/
this.texturesPath = path.substring(0, path.lastIndexOf('/')) + '/';
/**
* Path to the .mtl file
* @type {string}
*/
this.mtlPath = path.replace('.obj', '.mtl');
/**
* Reference to the scene in which the object should be added
*/
this.scene = scene;
/**
* Callback to call on the object when they're created
*/
this.callback = callback;
/**
* Counter (not used)
* @private
*/
this.counter = 0;
/**
* Group where the sub-objects will be added
* @type {THREE.Object3D}
*/
this.obj = new THREE.Object3D();
scene.add(this.obj);
/**
* Array of the vertices of the mesh
* @type {THREE.Vector3[]}
*/
this.vertices = [];
/**
* Array of the texture coordinates of the mesh
* @type {THREE.Vector2[]}
*/
this.texCoords = [];
/**
* Array of the normal of the mesh
* @type {THREE.Vector3[]}
*/
this.normals = [];
/**
* Array of the UV mapping
* @description Each element is an array of 3 elements that are the indices
* of the element in <code>this.texCoords</code> that should be
* used as texture coordinates for the current vertex of the face
* @type {Number[][]}
*/
this.uvs = [];
/**
* Array of all the meshes that will be added to the main object
* @type {THREE.Mesh[]}
*/
this.meshes = [];
/**
* Loader for the material file
* @type {THREE.MTLLoader}
*/
this.loader = new THREE.MTLLoader(this.texturesPath);
/**
* Socket to connect to get the mesh
* @type {socket}
*/
this.socket = io();
this.initIOCallbacks();
/**
* Reference to the camera
* @type {PointerCamera}
*/
this.camera = camera;
};
/**
* Starts the loading of the mesh
*/
ProgressiveLoaderGeometry.prototype.load = function() {
var self = this;
this.loader.load(self.mtlPath, function(materialCreator) {
self.materialCreator = materialCreator;
materialCreator.preload();
self.start();
});
};
/**
* Will return a list representation of the camera (to be sent to the server)
*/
ProgressiveLoaderGeometry.prototype.getCamera = function() {
if (this.camera === null)
return null;
return this.toList();
};
/**
* Initializes the socket.io functions so that it can discuss with the server
*/
ProgressiveLoaderGeometry.prototype.initIOCallbacks = function() {
var self = this;
this.socket.on('ok', function() {
console.log('ok');
self.socket.emit('materials');
});
this.socket.on('elements', function(arr) {
if (arr.length === 0) {
console.log("Empty array");
} else {
console.log("Stuff received");
}
// console.log("Received elements for the " + (++self.counter) + "th time !");
for (var i = 0; i < arr.length; i++) {
var elt = _parseList2(arr[i]);
// console.log(elts);
if (elt.type === 'vertex') {
// New vertex arrived
// Fill the array of vertices with null vector (to avoid undefined)
while (elt.index > self.vertices.length) {
self.vertices.push(new THREE.Vector3());
}
self.vertices[elt.index] = new THREE.Vector3(elt.x, elt.y, elt.z);
self.currentMesh.geometry.verticesNeedUpdate = true;
} else if (elt.type === 'texCoord') {
// New texCoord arrived
self.texCoords[elt.index] = new THREE.Vector2(elt.x, elt.y);
self.currentMesh.geometry.uvsNeedUpdate = true;
} else if (elt.type === 'normal') {
// New normal arrived
self.normals[elt.index] = new THREE.Vector3(elt.x, elt.y, elt.z);
} else if (elt.type === 'usemtl') {
if (self.currentMesh !== undefined) {
// if (self.currentMesh.geometry.attributes.normal === undefined) {
// self.currentMesh.geometry.computeVertexNormals();
// }
}
// Must create new mesh
// console.log("New mesh arrived : " + elt.materialName);
// Create mesh material
var material;
if (elt.materialName === null) {
// If no material, create a default material
material = new THREE.MeshLambertMaterial({color: 'red'});
} else {
// If material name exists, load if from material, and do a couple of settings
material = self.materialCreator.materials[elt.materialName.trim()];
material.side = THREE.DoubleSide;
if (material.map)
material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;
}
// Create mesh geometry
self.uvs = [];
var geometry = new THREE.Geometry();
geometry.vertices = self.vertices;
geometry.faces = [];
// If texture coords, init faceVertexUvs attribute
if (elt.texCoordsExist) {
geometry.faceVertexUvs = [self.uvs];
}
geometry.dynamic = true;
// Create mesh
var mesh = new THREE.Mesh(geometry, material);
mesh.faceNumber = elt.fLength;
self.meshes.push(mesh);
self.currentMesh = mesh;
if (typeof self.callback === 'function') {
self.callback(mesh);
}
} else if (elt.type === 'face') {
if (!self.meshes[elt.mesh].added) {
self.meshes[elt.mesh].added = true;
self.obj.add(self.meshes[elt.mesh]);
}
if (elt.aNormal !== undefined) {
self.meshes[elt.mesh].geometry.faces.push(new THREE.Face3(elt.a, elt.b, elt.c, [self.normals[elt.aNormal], self.normals[elt.bNormal], self.normals[elt.cNormal]]));
} else {
self.meshes[elt.mesh].geometry.faces.push(new THREE.Face3(elt.a, elt.b, elt.c));
self.meshes[elt.mesh].geometry.computeFaceNormals();
self.meshes[elt.mesh].geometry.computeVertexNormals();
}
if (elt.aTexture !== undefined) {
self.meshes[elt.mesh].geometry.faceVertexUvs[0].push([self.texCoords[elt.aTexture], self.texCoords[elt.bTexture], self.texCoords[elt.cTexture]]);
}
self.meshes[elt.mesh].geometry.verticesNeedUpdate = true;
self.meshes[elt.mesh].geometry.uvsNeedUpdate = true;
self.meshes[elt.mesh].geometry.normalsNeedUpdate = true;
self.meshes[elt.mesh].geometry.groupsNeedUpdate = true;
if (self.meshes[elt.mesh].faceNumber === self.meshes[elt.mesh].geometry.faces.length) {
self.meshes[elt.mesh].geometry.computeBoundingSphere();
}
}
}
// Ask for next elements
self.socket.emit('next', self.getCamera());
});
this.socket.on('disconnect', function() {
console.log('Finished !');
self.finished = true;
});
};
/**
* Starts the communication with the server
*/
ProgressiveLoaderGeometry.prototype.start = function() {
this.socket.emit('request', this.objPath);
};

201
js/l3d/src/math/Hermite.js Normal file
View File

@@ -0,0 +1,201 @@
var Hermite = {};
Hermite.Polynom = function(t, f, fp) {
this.times = t;
this.evals = f;
this.primes = fp;
this.baseFunctions = [];
for (var i in this.times) {
this.baseFunctions.push(new Hermite.BaseFunction(i, this.times));
}
// Let's do something at least a little reusable
this.tools = {};
if (f[0] instanceof THREE.Vector3) {
this.tools.whatType = 'THREE.Vector3';
this.tools.sum = Tools.sum;
this.tools.prod = Tools.mul;
} else {
this.tools.whatType = 'number';
this.tools.sum = function(a, b) { return a + b; };
this.tools.prod = function(a, b) { return a * b; };
}
};
Hermite.Polynom.prototype.eval = function(t) {
var ret;
if (this.tools.whatType === 'THREE.Vector3') {
ret = new THREE.Vector3();
} else {
ret = 0;
}
for (var i in this.times) {
var ti = this.times[i];
var qi_t = this.baseFunctions[i].eval(t);
// var qi_ti = this.baseFunctions[i].eval(ti);
var qip_ti = this.baseFunctions[i].prime(ti);
var f_ti = this.evals[i];
var fp_ti = this.primes[i];
// This is the wikipedia formula
// ret += (qi_t / qi_ti) * ((1 - (t - ti) * (qip_ti / qi_ti)) * f_ti + (t - ti) * fp_ti);
// Let's not forget that qi_ti = 1
// This is the final formula
// ret += (qi_t) * ((1 - (t - ti) * (qip_ti)) * f_ti + (t - ti) * fp_ti);
// This is the implementation working with THREE.Vector3
// In terms of disgusting code, we're quite good there
ret =
this.tools.sum(
ret,
this.tools.prod(
this.tools.sum(
this.tools.prod(f_ti, 1 - (t - ti) * (qip_ti)),
this.tools.prod(fp_ti, t - ti)
),
qi_t
)
);
}
return ret;
};
Hermite.Polynom.prototype.prime = function(t) {
var ret;
if (this.tools.whatType === 'THREE.Vector3') {
ret = new THREE.Vector3();
} else {
ret = 0;
}
for (var i in this.times) {
var ti = this.times[i];
var qi_t = this.baseFunctions[i].eval(t);
// var qi_ti = this.baseFunctions[i].eval(ti);
var qip_t = this.baseFunctions[i].prime(t );
var qip_ti = this.baseFunctions[i].prime(ti);
var f_ti = this.evals[i];
var fp_ti = this.primes[i];
// The return of the disgusting code...
// First part is the same that the eval function, but changing qi_t by qip_t
// (first part of the derivative)
ret =
this.tools.sum(
ret,
this.tools.prod(
this.tools.sum(
this.tools.prod(f_ti, 1 - (t - ti) * (qip_ti)),
this.tools.prod(fp_ti, t - ti)
),
qip_t
)
);
// Here, we just add
// ret += qi_t * (-qip_t * f_ti + fp_ti);
ret =
this.tools.sum(
ret,
this.tools.prod(
this.tools.sum(
this.tools.prod(
f_ti,
-qip_t
),
fp_ti
),
qi_t
)
);
// Now the following code is the same as the precedent affectation
// However it doesn't work, and I can't see the difference between
// this and the previous one... so I keep it here, to find the
// mistate later
// ret =
// this.tools.sum(
// ret,
// this.tools.prod(
// this.tools.sum(
// fp_ti,
// this.tools.prod(
// f_ti,
// -qip_ti
// )
// ),
// qi_t
// )
// );
}
return ret;
};
Hermite.BaseFunction = function(index, times) {
this.index = index;
this.times = times;
};
Hermite.BaseFunction.prototype.eval = function(t) {
var ret = 1;
for (var i in this.times) {
if (i !== this.index) {
ret *= (t - this.times[i]) / (this.times[this.index] - this.times[i]);
}
}
return ret * ret;
};
Hermite.BaseFunction.prototype.prime = function(t) {
var ret = 0;
for (var i in this.times) {
if (i !== this.index) {
ret += 2 / (t - this.times[i]);
}
}
return this.eval(t) * ret;
};
Hermite.special = {};
// This polynom interpolates with two coords and one derivative
// t = [0,1]
Hermite.special.Polynom = function(P0, P1, PP1) {
this.tools = {};
if (P0 instanceof THREE.Vector3) {
this.tools.sum = Tools.sum;
this.tools.mul = Tools.mul;
this.tools.diff = Tools.diff;
this.c = P0.clone();
} else {
this.tools.sum = function(a,b) { return a+b; };
this.tools.mul = function(a,b) { return a*b; };
this.tools.diff = function(a,b) { return a-b; };
this.c = P0;
}
this.a = this.tools.sum(PP1, this.tools.diff(P0, P1));
this.b = this.tools.diff(this.tools.mul(this.tools.diff(P1,P0), 2), PP1);
};
Hermite.special.Polynom.prototype.eval = function(t) {
return this.tools.sum(this.tools.mul(this.a, t*t), this.tools.sum(this.tools.mul(this.b, t), this.c));
};
Hermite.special.Polynom.prototype.prime = function(t) {
return this.tools.sum(this.tools.mul(this.a,2*t), this.b);
};

View File

@@ -0,0 +1,44 @@
var container = document.getElementById('content');
function print(text) {
var content = document.createTextNode(text);
var new_line = document.createElement('br');
container.appendChild(content);
container.appendChild(new_line);
}
function toString(variable) {
if (variable instanceof THREE.Vector3) {
return variable.x + ', ' + variable.y + ', ' + variable.z;
} else {
return variable;
}
}
// Test with THREE.Vector3
// t = [0,1];
// f = [new THREE.Vector3(0,0,0), new THREE.Vector3(1,1,1)];
// fp = [new THREE.Vector3(0,1,2), new THREE.Vector3(0,0,0)];
// Test with doubles
t = [0,1];
f = [0,1];
fp = [-1,-1];
var hermite = new Hermite.special.Polynom(0, 1, -1);
print('M = [');
for (var t = 0; t < 1; t += 0.01) {
var res = hermite.eval(t);
print("\t" + t + ',' + toString(res) + ';');
}
print('];');
print('MP = [');
for (var t = 0; t < 1; t += 0.01) {
var res = hermite.prime(t);
print("\t" + t + ',' + toString(res) + ';');
}
print('];');

37
js/l3d/src/math/Tools.js Normal file
View File

@@ -0,0 +1,37 @@
var Tools = {version : "1.0" };
Tools.sum = function(v1, v2) {
return new THREE.Vector3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
};
Tools.diff = function(v1, v2) {
return new THREE.Vector3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
};
Tools.dot = function(v1, v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
};
Tools.cross = function(v1, v2) {
return new THREE.Vector3(
v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x
);
};
Tools.mul = function(v1, lambda) {
return new THREE.Vector3(v1.x * lambda, v1.y * lambda, v1.z * lambda);
};
Tools.equals = function(v1, v2) {
return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
};
Tools.norm2 = function(v) {
return v.x * v.x + v.y * v.y + v.z * v.z;
};
Tools.norm = function(v) {
return Math.sqrt(Tools.norm2(v));
};

View File

@@ -0,0 +1,81 @@
// We will be doing a lot of document.write, so let's remove jshint warnings
/* jshint evil:true */
function test(b) {
if (b)
document.write("<li style='color: #008800'>Success !</li>");
else
document.write("<li style='color: red'>Failure !</li>");
}
function main() {
document.write("<h1>Starting test !</h1>");
var v1 = new THREE.Vector3(1,2,3);
var v2 = new THREE.Vector3(2,3,4);
var v1Bak = v1.clone();
var v2Bak = v2.clone();
// First tests
document.write("<ol>");
var v3 = Tools.sum(v1,v2);
test(v3.x == v1.x + v2.x && v3.y == v1.y + v2.y && v3.z == v1.z + v2.z);
test(Tools.equals(v1, v1Bak));
test(Tools.equals(v2, v2Bak));
document.write('</ol>');
// Clear v1, v2
v1 = v1Bak.clone();
v2 = v2Bak.clone();
document.write("<ol>");
var v4 = Tools.diff(v1,v2);
test(v4.x == v1.x - v2.x && v4.y == v1.y - v2.y && v4.z == v1.z - v2.z);
test(Tools.equals(v1, v1Bak));
test(Tools.equals(v2, v2Bak));
document.write('</ol>');
v1 = v1Bak.clone();
v2 = v2Bak.clone();
document.write("<ol>");
var v5 = Tools.dot(v1,v2);
test(v5 == v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
test(Tools.equals(v1, v1Bak));
test(Tools.equals(v2, v2Bak));
document.write('</ol>');
v1 = v1Bak.clone();
v2 = v2Bak.clone();
document.write("<ol>");
var v6 = Tools.cross(new THREE.Vector3(1,0,0), new THREE.Vector3(0,1,0));
test(Tools.equals(v6, new THREE.Vector3(0,0,1)));
test(Tools.equals(v1, v1Bak));
test(Tools.equals(v2, v2Bak));
document.write('</ol>');
v1 = v1Bak.clone();
v2 = v2Bak.clone();
document.write("<ol>");
for (var lambda = 0; lambda < 5; lambda += 0.5)
{
var v7 = Tools.mul(v1, lambda);
test(Tools.equals(v7, new THREE.Vector3(v1Bak.x*lambda, v1Bak.y*lambda, v1Bak.z*lambda)));
v1 = v1Bak.clone();
v2 = v2Bak.clone();
var v8 = Tools.mul(v1, lambda);
test(Tools.equals(v8, new THREE.Vector3(v1Bak.x*lambda, v1Bak.y*lambda, v1Bak.z*lambda)));
v1 = v1Bak.clone();
v2 = v2Bak.clone();
// Try into v1
v1 = Tools.mul(v1, lambda);
test(Tools.equals(v1, new THREE.Vector3(v1Bak.x*lambda, v1Bak.y*lambda, v1Bak.z*lambda)));
v1 = v1Bak.clone();
v2 = v2Bak.clone();
}
}
main();

View File

@@ -0,0 +1,285 @@
// Initialization
// class camera extends THREE.PerspectiveCamera
var ArrowCamera = function(arg1, arg2, arg3, arg4, position, target) {
THREE.PerspectiveCamera.apply(this, arguments);
// Set Position
if (position === undefined) {
this.position = new THREE.Vector3(0,0,5);
} else {
this.position.x = position.x;
this.position.y = position.y;
this.position.z = position.z;
}
if (target === undefined)
target = new THREE.Vector3(0,0,0);
var direction = target.clone();
direction.sub(this.position);
direction.normalize();
this.center = this.position.clone();
this.center.sub(direction);
this.target = this.position.clone();
this.target.add(Tools.mul(direction,20));
this.arrow = new THREE.Mesh(new THREE.Geometry(), new THREE.MeshLambertMaterial({color: 0x0000ff, side:THREE.BackSide}));
this.size = 0.4;
this.object3D = new THREE.Object3D();
this.object3D.add(this.initExtremity());
this.object3D.add(this.arrow);
this.fullArrow = false;
};
ArrowCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
ArrowCamera.prototype.constructor = ArrowCamera;
ArrowCamera.prototype.check = function() {
this.object3D.traverse(function(obj) {
if (obj instanceof THREE.Mesh)
obj.material.color.setHex(0x663366);
});
};
ArrowCamera.prototype.initExtremity = function() {
var geometry = new THREE.Geometry();
var direction = this.target.clone();
direction.sub(this.position);
direction.normalize();
var left = Tools.cross(direction, this.up);
var other = Tools.cross(direction, left);
left.normalize();
other.normalize();
left = Tools.mul(left, this.size);
other = Tools.mul(other, this.size);
geometry.vertices.push(Tools.sum( Tools.sum( this.position, left), other),
Tools.diff(Tools.sum( this.position, other), left),
Tools.diff(Tools.diff(this.position, left), other),
Tools.sum( Tools.diff(this.position, other), left),
Tools.sum(this.position, direction)
);
geometry.faces.push(new THREE.Face3(0,2,1), // new THREE.Face3(0,2,1),
new THREE.Face3(0,3,2), // new THREE.Face3(0,3,2)
new THREE.Face3(4,1,2),
new THREE.Face3(4,0,1),
new THREE.Face3(4,3,0),
new THREE.Face3(4,2,3)
);
geometry.computeFaceNormals();
var material = new THREE.MeshLambertMaterial({
color : 0x0000ff,
transparent : true,
opacity : 0.5,
side: THREE.FrontSide
});
this.mesh = new THREE.Mesh(geometry, material);
return this.mesh;
};
ArrowCamera.prototype.updateExtremity = function() {
var direction = this.target.clone();
direction.sub(this.position);
direction.normalize();
var left = Tools.cross(direction, this.up);
var other = Tools.cross(direction, left);
left.normalize();
other.normalize();
left = Tools.mul(left, this.size);
other = Tools.mul(other, this.size);
this.mesh.geometry.vertices = [
Tools.sum( Tools.sum( this.position, left), other),
Tools.diff(Tools.sum( this.position, other), left),
Tools.diff(Tools.diff(this.position, left), other),
Tools.sum( Tools.diff(this.position, other), left),
Tools.sum(this.position, direction)
];
this.mesh.geometry.computeFaceNormals();
this.mesh.geometry.verticesNeedUpdate = true;
};
ArrowCamera.prototype.setSize = function(size) {
this.size = size;
this.updateExtremity();
};
// Update function
ArrowCamera.prototype.update = function(mainCamera) {
// Compute distance between center of camera and position
dist = Tools.norm2(Tools.diff(mainCamera.position, this.center));
var low_bound = 1;
var high_bound = 5;
var new_value;
if (dist < low_bound) {
new_value = 0;
}
else if (dist > high_bound) {
new_value = 1;
}
else {
new_value = (dist - low_bound)/(high_bound - low_bound);
}
// Update opacity
this.object3D.traverse(function(elt) {
if (elt instanceof THREE.Mesh) {
elt.material.transparent = new_value < 0.9;
elt.material.opacity = new_value;
if (new_value < 0.1)
elt.material.transparent = elt.visible = false;
}
});
this.regenerateArrow(mainCamera);
};
ArrowCamera.prototype.regenerateArrow = function(mainCamera) {
var i;
var vertices = [];
// First point of curve
var f0 = mainCamera.position.clone();
f0.add(Tools.mul(Tools.sum(new THREE.Vector3(0,-0.5,0), Tools.diff(this.target, this.position).normalize()),2));
// Last point of curve
var f1 = this.position.clone();
// Last derivative of curve
var fp1 = Tools.diff(this.target, this.position);
fp1.normalize();
fp1.multiplyScalar(2);
// Camera direction
var dir = Tools.diff(this.position, mainCamera.position);
dir.normalize();
if (fp1.dot(dir) < -0.5) {
// Regen polynom with better stuff
// var new_dir = Tools.cross(Tools.diff(this.position, mainCamera.position).normalize(), mainCamera.up);
// new_dir.multiplyScalar(new_dir.dot(fp1) < 0 ? 1 : -1);
// new_dir.add(dir);
// new_dir.add(dir);
// new_dir.multiplyScalar(2);
// f0.add(new_dir);
if (mainCamera.position.y > this.position.y) {
f0.add(new THREE.Vector3(0,2,0));
} else {
f0.add(new THREE.Vector3(0,-2,0));
}
}
fp1.multiplyScalar(4);
var hermite = new Hermite.special.Polynom(f0, f1, fp1);
var up = this.up.clone();
var point;
var deriv;
var limit = this.fullArrow ? 0.1 : 0.3;
// for (var i = this.fullArrow ? 0 : 0.5; i <= 1.001; i += 0.05) {
for (i = 1; i > limit; i -= 0.1) {
point = hermite.eval(i);
deriv = hermite.prime(i);
up.cross(deriv);
up.cross(deriv);
up.multiplyScalar(-1);
up.normalize();
var coeff = this.size / 2;
var left = Tools.cross(up, deriv); left.normalize(); left.multiplyScalar(coeff);
var other = Tools.cross(deriv, left); other.normalize(); other.multiplyScalar(coeff);
vertices.push(
Tools.sum(Tools.sum(point, left), other),
Tools.sum(Tools.diff(point, left), other),
Tools.diff(point, Tools.sum(other,left)),
Tools.sum(Tools.diff(point, other), left)
);
}
this.arrow.geometry.vertices = vertices;
if (this.arrow.geometry.faces.length === 0) {
var faces = [];
for (i = 0; i < vertices.length - 4; i+= 4) {
faces.push(new THREE.Face3(i,i+1,i+5),new THREE.Face3(i,i+5,i+4),
new THREE.Face3(i+1,i+2,i+6),new THREE.Face3(i+1,i+6,i+5),
new THREE.Face3(i+2,i+3,i+7),new THREE.Face3(i+2,i+7,i+6),
new THREE.Face3(i,i+7,i+3), new THREE.Face3(i,i+4,i+7));
}
var len = vertices.length;
faces.push(new THREE.Face3(len-4,len-3,len-2), new THREE.Face3(len-4,len-2,len-1));
// var max = 0;
// for (var i = 0; i < faces.length; i++) {
// max = Math.max(max, faces[i].a, faces[i].b, faces[i].c);
// }
// console.log(max + '/' + len);
this.arrow.geometry.faces = faces;
this.arrow.geometry.groupsNeedUpdate = true;
this.arrow.geometry.elementsNeedUpdate = true;
}
// this.arrow.geometry.mergeVertices();
this.arrow.geometry.computeFaceNormals();
// this.arrow.geometry.computeVertexNormals();
this.arrow.geometry.computeBoundingSphere();
// this.arrow.geometry.vertices[0] = new THREE.Vector3(); // mainCamera.position.clone();
// this.arrow.geometry.vertices[1] = this.position.clone();
this.arrow.geometry.dynamic = true;
this.arrow.geometry.verticesNeedUpdate = true;
// this.arrow.geometry.elementsNeedUpdate = true;
// this.arrow.geometry.groupsNeedUpdate = true;
this.arrow.geometry.normalsNeedUpdate = true;
};
// Look function
ArrowCamera.prototype.look = function() {
this.lookAt(this.target);
};
ArrowCamera.prototype.addToScene = function(scene) {
scene.add(this);
scene.add(this.object3D);
};
ArrowCamera.prototype.traverse = function(callback) {
this.object3D.traverse(callback);
};
ArrowCamera.prototype.containsObject = function(object) {
return object.parent === this.object3D;
};

View File

@@ -0,0 +1,9 @@
// Initialization
// class camera extends THREE.PerspectiveCamera
var FixedCamera = function(arg1, arg2, arg3, arg4, position, target) {
ArrowCamera.apply(this, arguments);
};
FixedCamera.prototype = Object.create(ArrowCamera.prototype);
FixedCamera.prototype.constructor = FixedCamera;

View File

@@ -0,0 +1,195 @@
// Initialization
// class camera extends THREE.PerspectiveCamera
var OldFixedCamera = function(arg1, arg2, arg3, arg4, position, target) {
THREE.PerspectiveCamera.apply(this, arguments);
// Set Position
if (position === undefined) {
this.position = new THREE.Vector3(0,0,5);
} else {
this.position.x = position.x;
this.position.y = position.y;
this.position.z = position.z;
}
if (target === undefined)
target = new THREE.Vector3(0,0,0);
var direction = target.clone();
direction.sub(this.position);
direction.normalize();
this.target = this.position.clone();
this.target.add(Tools.mul(direction,10));
// this.up = new THREE.Vector3(0,0,1);
// Compute corners
// Create the mesh to draw
var geometry = new THREE.Geometry();
var left = Tools.cross(direction, this.up);
var other = Tools.cross(direction, left);
left.normalize();
other.normalize();
left = Tools.mul(left, 1);
other = Tools.mul(other, 1);
geometry.vertices.push(Tools.sum(Tools.sum(this.position, left), other),
Tools.diff(Tools.sum(this.position, other),left),
Tools.diff(Tools.diff(this.position, left),other),
Tools.sum(Tools.diff(this.position, other), left)
);
geometry.faces.push(new THREE.Face3(0,1,2), // new THREE.Face3(0,2,1),
new THREE.Face3(0,2,3) // new THREE.Face3(0,3,2)
);
(function(self, direction, left, other) {
var material = new THREE.LineBasicMaterial({ color: '0x000000'});
var geometry = new THREE.Geometry();
var tmp_direction = Tools.mul(direction, -2);
var target = Tools.sum(self.position, tmp_direction);
// geometry.vertices.push(self.position, target);
geometry.vertices.push(
Tools.sum(Tools.sum(self.position, left), other),
Tools.diff(Tools.sum(self.position, other),left),
Tools.diff(Tools.diff(self.position, left),other),
Tools.sum(Tools.diff(self.position, other), left),
Tools.sum(Tools.sum(self.position, left), other),
Tools.sum(Tools.diff(self.position, other), left),
Tools.sum(self.position, tmp_direction),
Tools.sum(Tools.sum(self.position, left), other),
Tools.sum(self.position, tmp_direction),
Tools.diff(Tools.sum(self.position, other),left),
Tools.sum(self.position, tmp_direction),
Tools.diff(Tools.diff(self.position, left),other),
Tools.sum(self.position, tmp_direction),
Tools.sum(Tools.diff(self.position, other), left)
);
self.line = new THREE.Line(geometry, material);
})(this, direction, left, other);
var material = new THREE.MeshBasicMaterial({
color : 0x0000ff,
transparent : true,
opacity : 1,
side: THREE.DoubleSide
});
this.mesh = new THREE.Mesh(geometry, material);
this.mesh.raycastable = true;
};
OldFixedCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
OldFixedCamera.prototype.constructor = OldFixedCamera;
OldFixedCamera.prototype.check = function() {
this.mesh.material.color.setHex(0x663366);
};
// Update function
OldFixedCamera.prototype.update = function(position) {
// Compute distance between center of camera and position
dist = Tools.norm2(Tools.diff(position.position, this.position));
var low_bound = 1;
var high_bound = 5;
var new_value;
var max_value = 0.5;
if (dist < low_bound)
new_value = 0;
else if (dist > high_bound)
new_value = max_value;
else
new_value = max_value * (dist - low_bound)/(high_bound - low_bound);
this.mesh.material.transparent = new_value < 0.9;
this.mesh.material.opacity = new_value;
if (new_value < 0.1)
this.mesh.material.transparent = this.mesh.visible = false;
};
// Look function
OldFixedCamera.prototype.look = function() {
this.lookAt(this.target);
};
OldFixedCamera.prototype.addToScene = function(scene) {
scene.add(this);
scene.add(this.mesh);
scene.add(this.line);
};
OldFixedCamera.prototype.traverse = function(callback) {
callback(this.mesh);
callback(this.line);
};
OldFixedCamera.prototype.containsObject = function(object) {
return object === this.mesh;
};
OldFixedCamera.prototype.setSize = function(size) {
var direction = this.target.clone();
direction.sub(this.position);
direction.normalize();
var left = Tools.cross(direction, this.up);
var other = Tools.cross(direction, left);
left.normalize();
other.normalize();
left = Tools.mul(left, size);
other = Tools.mul(other, size);
this.mesh.geometry.vertices = [
Tools.sum(Tools.sum(this.position, left), other),
Tools.diff(Tools.sum(this.position, other),left),
Tools.diff(Tools.diff(this.position, left),other),
Tools.sum(Tools.diff(this.position, other), left)
];
this.mesh.geometry.verticesNeedUpdate = true;
(function(self, direction, left, other, size) {
var tmp_direction = Tools.mul(direction, -2 * size);
var target = Tools.sum(self.position, tmp_direction);
var vertices = [
Tools.sum(Tools.sum(self.position, left), other),
Tools.diff(Tools.sum(self.position, other),left),
Tools.diff(Tools.diff(self.position, left),other),
Tools.sum(Tools.diff(self.position, other), left),
Tools.sum(Tools.sum(self.position, left), other),
Tools.sum(Tools.diff(self.position, other), left),
Tools.sum(self.position, tmp_direction),
Tools.sum(Tools.sum(self.position, left), other),
Tools.sum(self.position, tmp_direction),
Tools.diff(Tools.sum(self.position, other),left),
Tools.sum(self.position, tmp_direction),
Tools.diff(Tools.diff(self.position, left),other),
Tools.sum(self.position, tmp_direction),
Tools.sum(Tools.diff(self.position, other), left)
];
self.line.geometry.vertices = vertices;
self.line.geometry.verticesNeedUpdate = true;
})(this, direction, left, other, size);
};

View File

@@ -0,0 +1,181 @@
// Initialization
// class camera extends THREE.PerspectiveCamera
var ReverseCamera = function(arg1, arg2, arg3, arg4, position, target) {
ArrowCamera.apply(this, arguments);
};
ReverseCamera.prototype = Object.create(ArrowCamera.prototype);
ReverseCamera.prototype.constructor = ReverseCamera;
// Overload init
ReverseCamera.prototype.initExtremity = function() {
var geometry = new THREE.Geometry();
var direction = this.target.clone();
direction.sub(this.position);
direction.normalize();
var left = Tools.cross(direction, this.up);
var other = Tools.cross(direction, left);
left.normalize();
other.normalize();
left = Tools.mul(left, this.size / 2 );
other = Tools.mul(other, this.size / 2);
var pyramidCenter = Tools.diff(this.position, Tools.mul(direction,0.25));
geometry.vertices.push(
Tools.sum( Tools.sum( this.position, left), other),
Tools.diff(Tools.sum( this.position, other), left),
Tools.diff(Tools.diff(this.position, left), other),
Tools.sum( Tools.diff(this.position, other), left),
Tools.sum( Tools.sum( this.position, left), other),
Tools.diff(Tools.sum( this.position, other), left),
Tools.diff(Tools.diff(this.position, left), other),
Tools.sum( Tools.diff(this.position, other), left)
// Tools.diff(this.position, direction)
);
var lambda = 0.6;
for (var i = 0; i < 4; i++)
geometry.vertices[i] = Tools.mul(Tools.diff(geometry.vertices[i], Tools.mul(pyramidCenter,lambda)), 1/(1-lambda));
geometry.faces.push(new THREE.Face3(2,0,1), // new THREE.Face3(0,2,1),
new THREE.Face3(3,0,2), // new THREE.Face3(0,3,2)
new THREE.Face3(1,0,4),
new THREE.Face3(1,4,5),
new THREE.Face3(2,1,5),
new THREE.Face3(2,5,6),
new THREE.Face3(7,2,6),
new THREE.Face3(7,3,2),
new THREE.Face3(3,7,4),
new THREE.Face3(3,4,0)
);
geometry.computeFaceNormals();
var material = new THREE.MeshLambertMaterial({
color : 0x0000ff,
transparent : true,
opacity : 0.5,
side: THREE.FrontSide
});
this.mesh = new THREE.Mesh(geometry, material);
return this.mesh;
};
ReverseCamera.prototype.regenerateArrow = function(mainCamera) {
var i;
var vertices = [];
// First point of curve
var f0 = mainCamera.position.clone();
f0.add(Tools.mul(Tools.sum(new THREE.Vector3(0,-0.5,0), Tools.diff(this.target, this.position).normalize()),2));
// Last point of curve
var f1 = this.position.clone();
// Last derivative of curve
var fp1 = Tools.diff(this.target, this.position);
fp1.normalize();
fp1.multiplyScalar(2);
// Camera direction
var dir = Tools.diff(this.position, mainCamera.position);
dir.normalize();
if (fp1.dot(dir) < -0.5) {
// Regen polynom with better stuff
// var new_dir = Tools.cross(Tools.diff(this.position, mainCamera.position).normalize(), mainCamera.up);
// new_dir.multiplyScalar(new_dir.dot(fp1) < 0 ? 1 : -1);
// new_dir.add(dir);
// new_dir.add(dir);
// new_dir.multiplyScalar(2);
// f0.add(new_dir);
if (mainCamera.position.y > this.position.y) {
f0.add(new THREE.Vector3(0,2,0));
} else {
f0.add(new THREE.Vector3(0,-2,0));
}
}
fp1.multiplyScalar(4);
var hermite = new Hermite.special.Polynom(f0, f1, fp1);
var up = this.up.clone();
var point;
var deriv;
var limit = this.fullArrow ? 0.1 : 0.3;
// for (var i = this.fullArrow ? 0 : 0.5; i <= 1.001; i += 0.05) {
for (i = 1; i > limit; i -= 0.1) {
point = hermite.eval(i);
deriv = hermite.prime(i);
up.cross(deriv);
up.cross(deriv);
up.multiplyScalar(-1);
up.normalize();
var coeff = i * i * this.size / 2;
var left = Tools.cross(up, deriv); left.normalize(); left.multiplyScalar(coeff);
var other = Tools.cross(deriv, left); other.normalize(); other.multiplyScalar(coeff);
vertices.push(
Tools.sum(Tools.sum(point, left), other),
Tools.sum(Tools.diff(point, left), other),
Tools.diff(point, Tools.sum(other,left)),
Tools.sum(Tools.diff(point, other), left)
);
}
this.arrow.geometry.vertices = vertices;
if (this.arrow.geometry.faces.length === 0) {
var faces = [];
for (i = 0; i < vertices.length - 4; i+= 4) {
faces.push(new THREE.Face3(i,i+1,i+5),new THREE.Face3(i,i+5,i+4),
new THREE.Face3(i+1,i+2,i+6),new THREE.Face3(i+1,i+6,i+5),
new THREE.Face3(i+2,i+3,i+7),new THREE.Face3(i+2,i+7,i+6),
new THREE.Face3(i,i+7,i+3), new THREE.Face3(i,i+4,i+7));
}
var len = vertices.length;
faces.push(new THREE.Face3(len-4,len-3,len-2), new THREE.Face3(len-4,len-2,len-1));
var max = 0;
for (i = 0; i < faces.length; i++) {
max = Math.max(max, faces[i].a, faces[i].b, faces[i].c);
}
console.log(max + '/' + len);
this.arrow.geometry.faces = faces;
this.arrow.geometry.groupsNeedUpdate = true;
this.arrow.geometry.elementsNeedUpdate = true;
}
// this.arrow.geometry.mergeVertices();
this.arrow.geometry.computeFaceNormals();
// this.arrow.geometry.computeVertexNormals();
this.arrow.geometry.computeBoundingSphere();
// this.arrow.geometry.vertices[0] = new THREE.Vector3(); // mainCamera.position.clone();
// this.arrow.geometry.vertices[1] = this.position.clone();
this.arrow.geometry.dynamic = true;
this.arrow.geometry.verticesNeedUpdate = true;
};

View File

@@ -0,0 +1,736 @@
// Define RecommendedCamera if not defined
var RecommendedCamera = RecommendedCamera || FixedCamera;
function addLight(scene) {
var directional_light = new THREE.DirectionalLight(0xdddddd);
directional_light.position.set(1, 2.5, 1).normalize();
directional_light.castShadow = false;
scene.add(directional_light);
var ambient_light = new THREE.AmbientLight(0x555555);
scene.add(ambient_light);
}
function initPeachCastle(scene, collidableObjects, camera) {
var loader = new ProgressiveLoaderGeometry(
'/static/data/castle/princess peaches castle (outside).obj',
scene,
null,
function(object) {
object.raycastable = true;
if (object.material.name === 'Material.103_princess_peaches_cast') {
THREEx.Transparency.push(object);
} else if (object.material.name === 'Material.136_princess_peaches_cast' ||
object.material.name === 'Material.135_princess_peaches_cast') {
THREEx.Transparency.push(object);
object.material.opacity = 0.5;
object.raycastable = false;
object.material.side = THREE.FrontSide;
}
}
);
loader.load();
collidableObjects.push(loader.obj);
loader.obj.raycastable = true;
}
function resetPeachElements() {
return {
position: new THREE.Vector3(0.24120226734236713,0.2009624547018851,-0.5998422840047036),
target: new THREE.Vector3(0.24120226734232672,0.20096245470190008,-40.5998422840047)
};
}
function initPeach(camera, scene, coins) {
addLight(scene);
var collidableObjects = [];
initPeachCastle(scene, collidableObjects, camera);
camera.resetElements = resetPeachElements();
camera.collidableObjects = collidableObjects;
camera.speed = 0.001;
camera.reset();
camera.save();
scene.add(camera);
Coin.init(0.001);
var otherCams = [];
var cameras = new CameraContainer(camera, otherCams);
return cameras;
}
function initZeldaScene(scene, collidableObjects, loader) {
// Create loader if not already done
if (loader === undefined) {
loader = new THREE.OBJMTLLoader();
}
loader.load(
'/static/data/zelda/Island.obj',
'/static/data/zelda/Island.mtl',
function ( object ) {
collidableObjects.push(object);
object.scale.set(0.01,0.01,0.01);
object.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.geometry.mergeVertices();
object.geometry.computeVertexNormals();
object.material.side = THREE.DoubleSide;
object.raycastable = true;
if (object.material.name === 'm0') {
THREEx.Transparency.push(object);
}
}
});
}
);
}
function createPeachCameras(width, height) {
var cams = [];
var createCamera = function(position, target) {
return new RecommendedCamera(
50,
width / height,
1,
100000,
position,
target
);
};
cams.push(createCamera(
new THREE.Vector3(-3.349895207953063, 5.148106346852601, 0.3365943929701533),
new THREE.Vector3(13.114421714865292, -7.783476327687569, -33.74713248359852)
));
cams.push(createCamera(
new THREE.Vector3(4.659399030971226, 1.018674883050052597, -2.578139604982815),
new THREE.Vector3(-16.08800293200113, -28.8795632312717, -19.165379404919797)
));
cams.push(createCamera(
new THREE.Vector3(2.625389073616235, 1.2252620948239699, -4.818718135555419),
new THREE.Vector3(-19.756833131355208, -16.20027570329664, -33.02132017177813)
));ader = new THREE.MTLLoader('/static/data/bobomb/');
// loader.
// cams.push(createCamera(
// new THREE.Vector3(1.3304975149911331, 0.4836093721106701, -8.60618907952783),
// new THREE.Vector3(-1.7713635815431914, 6.271997833695163, -48.06341930106774)
// ));
// cams.push(createCamera(
// new THREE.Vector3(1.2976081760482443, 1.1520399813234647, -10.258148122402845),
// new THREE.Vector3(-26.00651734173549, -9.19681009597505, -37.596510029925945)
// ));
cams.push(createCamera(
new THREE.Vector3(0.15727187830660858, 2.7251137440572855, -5.84333603646124),
new THREE.Vector3(19.33738702531091, -13.614383891308975, -36.91010284556961)
));
cams.push(createCamera(
new THREE.Vector3(-3.912436457101955,1.4571795397310319,-7.361700012948173),
new THREE.Vector3(26.60153755572943,-12.280244389383581,-29.274722938506393)
));
cams.push(createCamera(
new THREE.Vector3(4.734058048040269,0.9171350442568073,0.12604632828978296),
new THREE.Vector3(25.163187055614348,-27.08137327531798,-19.842284094421995)
));
cams.forEach(function(cam) {cam.setSize(0.2);});
return cams;
}
function initBobombScene(scene, collidableObjects, camera) {
var loader = new ProgressiveLoaderGeometry(
'/static/data/bobomb/bobomb battlefeild.obj',
scene,
null,
function(object) {
object.raycastable = true;
if (object.material.name === 'Material.071_574B138E_c.bmp' ||
object.material.name === 'Material.070_41A41EE3_c.bmp') {
THREEx.Transparency.push(object);
}
}
);
loader.load();
var theta = 0.27;
loader.obj.rotation.y = Math.PI - theta;
loader.obj.up = new THREE.Vector3(0,0,1);
collidableObjects.push(loader.obj);
}
function resetBobombElements() {
return {
position: new THREE.Vector3(38.115627509754646,10.829803024792419,-19.862035691341315),
target: new THREE.Vector3(-1.4518898576752122,5.048214777643772,-18.869661407832535)
};
}
function createBobombCoins() {
var coins = [];
coins.push(
new Coin(-1.6204001515660262,12.245208850063094,-24.871861611322934),
new Coin(23.509767766131876,13.6929075780209,-6.1716274892265615),
new Coin(34.797219873325524,13.088500612704706,-2.1784858128827413),
new Coin(-23.255456493345882,15.763954882327724,-11.08029248078497),
new Coin(-7.238094745133173,12.95460420281499,-3.1009487490121885),
new Coin(-17.10578612221326,24.17871082944758,-11.574224169812915),
new Coin(-12.418656949661646,17.09780294217035,32.472022253887665),
new Coin(7.132802719121488,8.802400710545713,22.258165594421055)
);
return coins;
}
function createBobombCameras(width, height) {
var cams = [];
var createCamera = function(position, target) {
return new RecommendedCamera(
50,
width / height,
1,
100000,
position,
target
);
};
cams.push(
createCamera(
new THREE.Vector3(37.24445046448742,17.56004329173052,-13.432945825465112),
new THREE.Vector3(15.446296842638255,0.7142524861838169,15.568085721947512)
),
createCamera(
new THREE.Vector3(-24.10987782946019,26.75997424452833,-24.7814217620827),
new THREE.Vector3(-13.724964120740987,14.939165978074758,11.993869660150779)
),
createCamera(
new THREE.Vector3(7.162458619916293,18.414234017280627,-10.871480453809644),
new THREE.Vector3(-27.47061192698706,3.9199238382137196,2.9294396939998144)
),
createCamera(
new THREE.Vector3(19.741775033926334,14.132046557015727,-25.338452829449857),
new THREE.Vector3(-18.0898892760213,1.5191520612050162,-28.449733590966297)
),
createCamera(
new THREE.Vector3(-13.484471970922971,20.25938194278451,-30.850247430073622),
new THREE.Vector3(-42.04654352929252,-7.608886431102082,-28.099304657929874)
),
createCamera(
new THREE.Vector3(23.58849177613168,18.628351213754488,31.516769692916675),
new THREE.Vector3(8.319765065757787,-0.5486703304136178,-0.09189730426033549)
),
createCamera(
new THREE.Vector3(5.068708131530766,11.201320390433953,9.77462743108436),
new THREE.Vector3(9.20744154720096,3.8549750522404134,48.87580511010085)
),
createCamera(
new THREE.Vector3(4.18086580540298,16.54831275414988,29.96253548469186),
new THREE.Vector3(-17.059296481928556,3.408610856102113,-1.2817238286325505)
),
createCamera(
new THREE.Vector3(-44.56340663230823,22.567957426093283,14.856920056929788),
new THREE.Vector3(-20.052660826451827,7.556450599683849,42.67558290835663)
),
createCamera(
new THREE.Vector3(11.29580093093769,15.03666008708929,31.377195488571406),
new THREE.Vector3(-28.288314738873957,13.648654387264967,25.794075678265735)
),
createCamera(
new THREE.Vector3(28.438969076366728,18.888756501203087,26.694456000440766),
new THREE.Vector3(-5.369166248035665,2.54925886583683,12.909289954623416)
)
);
return cams;
}
function initBobomb(camera, scene, coins) {
addLight(scene);
var collidableObjects = [];
initBobombScene(scene, collidableObjects, camera);
camera.resetElements = resetBobombElements();
camera.collidableObjects = collidableObjects;
camera.speed = 0.005;
camera.reset();
camera.save();
scene.add(camera);
Coin.init();
var tmp = createBobombCoins();
for (var i in tmp) {
coins.push(tmp[i]);
}
var otherCams = createBobombCameras(container_size.width(), container_size.height());
var cameras = new CameraContainer(camera, otherCams);
otherCams.forEach(function(cam) {cam.addToScene(scene);});
setTimeout(function() { coins.forEach(function(coin) { coin.addToScene(scene); });}, 1000);
return cameras;
}
function initWhompScene(scene, collidableObjects, camera) {
var loader = new ProgressiveLoaderGeometry(
'/static/data/whomp/Whomps Fortress.obj',
scene,
null,
function(object) {
object.raycastable = true;
if (object.material.name === 'Shape_088' ||
object.material.name === 'Shape_089') {
object.raycastable = false;
THREEx.Transparency.push(object);
} else if (object.material.name === 'Shape_113') {
THREEx.Transparency.push(object);
object.material.opacity = 0.5;
} else if (object.material.name === 'Shape_076' ||
object.material.name === 'Shape_098' ||
object.material.name === 'Shape_092') {
object.visible = false;
}
}
);
loader.load();
loader.obj.rotation.x = -Math.PI/2;
loader.obj.rotation.z = Math.PI/2;
loader.obj.scale.set(0.1,0.1,0.1);
// loader.getCamera = function() {
// var ret = loader.camera.toList();
// ret[0][0] *= 10;
// ret[0][1] *= 10;
// ret[0][2] *= 10;
// ret[1][0] *= 10;
// ret[1][1] *= 10;
// ret[1][2] *= 10;
// // Planes
// for (var i = 2; i < ret.length; i++) {
// ret[i][3] *= 10;
// }
// return ret;
// };
collidableObjects.push(loader.obj);
loader.obj.raycastable = true;
}
function createWhompCameras(width, height) {
var cams = [];
var createCamera = function(position, target) {
return new RecommendedCamera(
50,
width / height,
1,
100000,
position,
target
);
};
cams.push(
createCamera(
new THREE.Vector3(-5.4336754204569345,3.1392444908865986,-2.5523620854280967),
new THREE.Vector3(-5.284005453263061, 2.9591143163290674, 1.440776031533807)
),
createCamera(
new THREE.Vector3(-6.1753139246999424,3.1460450777755153, 8.89776989593906),
new THREE.Vector3(-2.7026837603414037,3.365743354536376, 6.924809579871983)
),
createCamera(
new THREE.Vector3(-5.4975217973818246,7.726911253355844, 2.805487210952553),
new THREE.Vector3(-2.262483559754942, 5.4847179687372005, 2.0933798626524435)
),
createCamera(
new THREE.Vector3(767.5978415761134, 3.641765617950047, -6.734909128840316),
new THREE.Vector3(800.1643232028776, 2.192334600043356, -3.0210038861375168)
),
createCamera(
new THREE.Vector3(-4.521868295112849, 4.598285007581405, -7.186164895937964),
new THREE.Vector3(-1.2890361546656827,2.964335244044779, -5.489401941978159)
),
createCamera(
new THREE.Vector3(7.669185389234946,3.470810613964853,-7.254996785427332),
new THREE.Vector3(11.103044107444248,-8.414196017364398,30.78386796730468)
),
createCamera(
new THREE.Vector3(-5.00642950829277,7.5887626003253095,-5.785306379113327),
new THREE.Vector3(30.922081744183423,1.5447833064028265,10.725671589357493)
),
createCamera(
new THREE.Vector3(10.73348160390988,7.384861575888838,-5.156956944727774),
new THREE.Vector3(-17.904597948771446,1.3408822819663548,22.107135078094704)
),
createCamera(
new THREE.Vector3(6.571383420547652,6.592495890455599,8.530692470963302),
new THREE.Vector3(-17.04673536396069,6.525278678835147,-23.752119471730232)
),
createCamera(
new THREE.Vector3(-2.658378348430724,9.934059833300438,4.832483419920441),
new THREE.Vector3(31.687909225501116,1.921420479172772,-14.038927244612823)
),
createCamera(
new THREE.Vector3(0.32263636932421563,14.77110426329107,-4.846281929349468),
new THREE.Vector3(13.444429209246985,-2.688018079059324,28.664874417470223)
)
);
cams.forEach(function(cam) {cam.setSize(0.2);});
return cams;
}
function createWhompCoins() {
return [
new Coin(-5.529176900669821,2.886514571524507,4.127968972716147),
new Coin(-3.336263561768484,9.341710952326468,1.0230063543998414),
new Coin(1.985057515492925,12.151756532082196,1.3355674703297925),
new Coin(8.100383890535953,4.6489182333624335,1.9132972963126775),
new Coin(0.6049016864458896,6.2498603432959584,3.6272087520336264),
new Coin(-1.4497656612870164,6.263594147452652,-4.0488101538390694),
new Coin(6.753883218882444,2.019245026490682,-7.001046531863012),
new Coin(3.4354286209455246,3.487313067990168,-4.091947594995703)
];
}
function resetWhompElements() {
return {
position : new THREE.Vector3(-6.725817925071645,1.4993570618328055,-10.356480813212423),
target : new THREE.Vector3(-4.8541705829784604,1.3192268872752742,-6.825972443720941)
};
}
function initWhomp(camera, scene, coins) {
addLight(scene);
var collidableObjects = [];
initWhompScene(scene, collidableObjects, camera);
camera.resetElements = resetWhompElements();
camera.collidableObjects = collidableObjects;
camera.speed = 0.002;
camera.reset();
camera.save();
scene.add(camera);
Coin.init(0.002);
var tmp = createWhompCoins();
for (var i in tmp) {
coins.push(tmp[i]);
}
var otherCams = createWhompCameras(container_size.width(), container_size.height());
var cameras = new CameraContainer(camera, otherCams);
otherCams.forEach(function(cam) {cam.addToScene(scene);});
setTimeout(function() { coins.forEach(function(coin) { coin.addToScene(scene); });}, 1000);
return cameras;
}
function initMountainScene(scene, collidableObjects, camera) {
var loader = new ProgressiveLoaderGeometry(
'/static/data/mountain/coocoolmountain.obj',
scene,
null,
function(object) {
// object.rotation.x = -Math.PI/2;
// object.rotation.z = Math.PI/2;
object.raycastable = true;
if (object.material.name === 'Material.070_13F025D5_c2.png' ||
object.material.name === 'Material.068_5972FC88_c.bmp' ||
object.material.name === 'Material.073_76F611AD_c.bmp' ||
object.material.name === 'Material.071_76F611AD_c.bmp' ||
object.material.name === 'Material.072_1723CCC7_c.bmp' ||
object.material.name === 'Material.069_78B64DC7_c.bmp' ||
object.material.name === 'Material.070_13F025D5_c.bmp' ||
object.material.name === 'Material.078_3165B23A_c.bmp' ||
object.material.name === 'Material.067_1723CCC7_c.bmp' ||
object.material.name === 'Material.066_36DB292F_c.bmp') {
THREEx.Transparency.push(object);
} else if (object.material.name === 'Material.082_6DAF90F6_c.bmp') {
THREEx.Transparency.push(object);
object.material.opacity = 0.5;
}
}
);
loader.load();
collidableObjects.push(loader.obj);
}
function createMountainCoins() {
return [
new Coin(-18.766484229298513,-6.174512332611151,16.379061147364553),
new Coin(-22.48878786991581,-17.698282433679474,1.6030258853572397),
new Coin(-8.604868977581164,-17.3348862459467,-11.923191659094416),
new Coin(24.81563047462934,-12.174170400556296,5.612049952487652),
new Coin(-6.4854226987006305,0.34787283214634307,-17.2093293607182),
new Coin(-14.50190371481413,20.88721463986533,7.923724946536855),
new Coin(-13.980787439949077,-0.10719616576499978,22.24889144136683),
new Coin(4.491305202472262,3.6813420775366277,10.03229664467681)
];
}
function createMountainCameras(width, height) {
var cams = [];
var createCamera = function(position, target) {
return new RecommendedCamera(
50,
width / height,
1,
100000,
position,
target
);
};
cams.push(
createCamera(
new THREE.Vector3(6.390950470631724,17.280677948120072,-10.027673035476619),
new THREE.Vector3(3.407145269707846,3.751012364771242,27.496253407869986)
),
createCamera(
new THREE.Vector3(1.8218030281265742,12.868464705566172,23.225042509186405),
new THREE.Vector3(-35.819191507045865,-0.6612008777826581,22.903049332448994)
),
createCamera(
new THREE.Vector3(-16.540494685269973,13.110251646113246,22.542769963619342),
new THREE.Vector3(-27.881799604553773,-2.2838398465862237,-12.59121287126898)
),
createCamera(
new THREE.Vector3(-22.09255502589394,7.505905597711714,-15.23412829383532),
new THREE.Vector3(14.823279525934556,-4.1255169584417315,-5.138031589552474)
),
createCamera(
new THREE.Vector3(-21.665778251110755,4.241815926756635,40.76683432842355),
new THREE.Vector3(2.62922954212112,-7.389606629396811,11.19552043054259)
),
createCamera(
new THREE.Vector3(14.384899444452842,4.759647095537105,30.122662109900055),
new THREE.Vector3(25.246471433793317,-6.871775460616339,-6.575243324069596)
),
createCamera(
new THREE.Vector3(20.6728438093429,-14.408979127185429,18.889993476410144),
new THREE.Vector3(-13.929780518638935,-26.04040168333887,35.241397053374556)
),
createCamera(
new THREE.Vector3(-26.825730322260814,-17.21406097233303,33.188195206615795),
new THREE.Vector3(-12.326126408723896,-17.015972902810617,-4.090783420316271)
),
createCamera(
new THREE.Vector3(-41.2311561559715,-11.714721125315961,2.070220579408691),
new THREE.Vector3(-2.2066012462800373,-15.510910369724881,9.986852522420207)
),
createCamera(
new THREE.Vector3(24.92926976320075,-11.374119469227288,-21.440813349326792),
new THREE.Vector3(-7.328902834025087,-24.90378505257612,-2.040853300647978)
),
createCamera(
new THREE.Vector3(-18.733128013636136,-12.129585933653297,-31.983290996466735),
new THREE.Vector3(-1.6636179852017818,-25.659251517002126,1.566373332583197)
),
createCamera(
new THREE.Vector3(-20.627345017019206,22.028686074349515,20.541790520954777),
new THREE.Vector3(14.150384161446272,11.731784408247087,3.6751557271398525)
)
);
return cams;
}
function resetMountainElements() {
return {
position : new THREE.Vector3(-20.558328115300082,23.601312087942762,-10.220633604814038),
target : new THREE.Vector3(11.025356711105232,11.969889531789319,11.393733425161644)
};
}
function initMountain(camera, scene, coins) {
addLight(scene);
var collidableObjects = [];
initMountainScene(scene, collidableObjects, camera);
camera.resetElements = resetMountainElements();
camera.collidableObjects = collidableObjects;
camera.speed = 0.005;
camera.reset();
camera.save();
scene.add(camera);
Coin.init();
var tmp = createMountainCoins();
for (var i in tmp) {
coins.push(tmp[i]);
}
var otherCams = createMountainCameras(container_size.width(), container_size.height());
var cameras = new CameraContainer(camera, otherCams);
otherCams.forEach(function(cam) {cam.addToScene(scene);});
setTimeout(function() { coins.forEach(function(coin) { coin.addToScene(scene); });}, 1000);
return cameras;
}
function initSponzaScene(scene, collidableObjects, camera) {
var loader = new ProgressiveLoaderGeometry('/static/data/sponza/sponza.obj', scene, camera, function(obj) {
if (obj.material.name === 'chain' ||
obj.material.name === 'leaf' ||
obj.material.name === 'Material__57') {
THREEx.Transparency.push(obj);
}
obj.raycastable = true;
});
l = loader;
loader.load();
loader.getCamera = function() {
var ret = loader.camera.toList();
ret[0][0] *= 10;
ret[0][1] *= 10;
ret[0][2] *= 10;
ret[1][0] *= 10;
ret[1][1] *= 10;
ret[1][2] *= 10;
// Planes
for (var i = 2; i < ret.length; i++) {
ret[i][3] *= 10;
}
return ret;
};
loader.obj.scale.set(0.1,0.1,0.1);
collidableObjects.push(loader.obj);
loader.obj.raycastable = true;
// ProgressiveLoader('/static/data/sponza/sponza.obj', scene,
// function(obj) {
// obj.scale.set(0.1,0.1,0.1);
// collidableObjects.push(obj);
// obj.raycastable = true;
// if (obj.material.name === 'chain' ||
// obj.material.name === 'leaf' ||
// obj.material.name === 'Material__57') {
// THREEx.Transparency.push(obj);
// }
// }
// );
}
function createSponzaCoins() {
return [];
}
function createSponzaCameras() {
return [];
}
function resetSponzaElements() {
return {
position: new THREE.Vector3(92.98373669520107,60.8877777990862,11.130138641670737),
target: new THREE.Vector3(53.76696417668598,56.09739213575453,4.877382575136091)
};
}
function initSponza(camera, scene, coins) {
addLight(scene);
var collidableObjects = [];
initSponzaScene(scene, collidableObjects, camera);
camera.resetElements = resetSponzaElements();
camera.collidableObjects = collidableObjects;
camera.speed = 0.05;
camera.reset();
camera.save();
scene.add(camera);
Coin.init();
var tmp = createSponzaCoins();
for (var i in tmp) {
coins.push(tmp[i]);
}
var otherCams = createSponzaCameras(container_size.width(), container_size.height());
var cameras = new CameraContainer(camera, otherCams);
otherCams.forEach(function(cam) {cam.addToScene(scene);});
setTimeout(function() { coins.forEach(function(coin) { coin.addToScene(scene); });}, 1000);
return cameras;
}

View File

@@ -0,0 +1,169 @@
var CameraSelecter = function(renderer, scene, cameras, coins, buttonManager) {
this.raycaster = new THREE.Raycaster();
this.renderer = renderer;
this.mouse = {};
this.cameras = cameras;
this.prev = {};
this.buttonManager = buttonManager;
this.scene = scene;
this.coins = coins;
};
CameraSelecter.prototype.pointedCamera = function() {
var returnCamera;
var x = ( this.mouse.x / this.renderer.domElement.width ) * 2 - 1;
var y = - (this.mouse.y / this.renderer.domElement.height) * 2 + 1;
var camera = this.cameras.mainCamera();
if (camera.pointerLocked) {
this.mouse.x = this.renderer.domElement.width/2 ;
this.mouse.y = this.renderer.domElement.height/2 ;
x = 0;
y = 0;
}
var vector = new THREE.Vector3(x, y, 0.5);
vector.unproject(camera);
this.raycaster.set(camera.position, vector.sub(camera.position).normalize());
var intersects = this.raycaster.intersectObjects(this.scene.children, true);
if ( intersects.length > 0 ) {
var minDistance;
var bestIndex;
// Looking for cameras
for (var i in intersects) {
if (intersects[i].object.raycastable && !(intersects[i].object instanceof THREE.Line)) {
if ((intersects[i].distance > 0.5 && minDistance === undefined) || (intersects[i].distance < minDistance )) {
if (!(intersects[i].object instanceof THREE.Mesh && intersects[i].object.material.opacity < 0.1)) {
minDistance = intersects[i].distance;
bestIndex = i;
}
}
}
}
if (bestIndex !== undefined) {
// if (this.cameras.getById(intersects[bestIndex].object.parent.id) !== undefined) {
var obj = intersects[bestIndex].object;
for (var coin in this.coins) {
if (obj === this.coins[coin].mesh) {
return this.coins[coin];
}
}
this.currentPointedCamera = this.cameras.getByObject(intersects[bestIndex].object);
return this.currentPointedCamera;
// }
}
}
this.currentPointedCamera = null;
};
CameraSelecter.prototype.update = function(event, y) {
var e;
if (event !== undefined) {
this.mouse.x = event.offsetX === undefined ? event.layerX : event.offsetX;
this.mouse.y = event.offsetY === undefined ? event.layerY : event.offsetY;
}
if (y !== undefined) {
this.mouse.x = this.renderer.domElement.width/2;
this.mouse.y = this.renderer.domElement.height/2;
}
var previousCamera = this.currentPointedCamera;
var hovered = this.pointedCamera();
if (hovered !== undefined && !(hovered instanceof Coin)) {
if (hovered !== previousCamera) {
// log it
e = new BD.Event.Hovered();
e.start = true;
e.arrow_id = this.cameras.cameras.indexOf(this.currentPointedCamera);
e.send();
this.prev.x = this.mouse.x;
this.prev.y = this.mouse.y;
}
this.prev.camera = hovered;
this.prev.go = true;
} else {
if (this.prev.go) {
// Log if previous was not null
e = new BD.Event.Hovered();
e.start = false;
e.arrow_id = null;
e.send();
}
this.prev.go = false;
}
document.getElementById('container').style.cursor = hovered ? "pointer" : "auto";
if (this.cameras.mainCamera().pointerLocked)
this.cameras.mainCamera().mousePointer.render(hovered ? MousePointer.RED : MousePointer.BLACK);
};
CameraSelecter.prototype.click = function(event) {
var e;
var newCamera = this.pointedCamera();
if (newCamera !== undefined && !(newCamera instanceof Coin)) {
e = new BD.Event.ArrowClicked();
e.arrow_id = this.cameras.cameras.indexOf(newCamera);
e.send();
newCamera.check();
this.cameras.mainCamera().moveHermite(newCamera);
buttonManager.updateElements();
} else if (newCamera instanceof Coin) {
// Coin found, notify server
e = new BD.Event.CoinClicked();
e.coin_id = this.coins.indexOf(newCamera);
e.send();
newCamera.get();
}
};
CameraSelecter.prototype.clickPointer = function(event) {
var e;
if (this.cameras.mainCamera().pointerLocked) {
var newCamera = this.pointedCamera();
if (newCamera !== undefined && !(newCamera instanceof Coin)) {
e = new BD.Event.ArrowClicked();
e.arrow_id = this.cameras.cameras.indexOf(newCamera);
e.send();
newCamera.check();
this.cameras.mainCamera().moveHermite(newCamera);
buttonManager.updateElements();
} else if (newCamera instanceof Coin) {
// Coin found, notify server
e = new BD.Event.CoinClicked();
e.coin_id = this.coins.indexOf(newCamera);
e.send();
newCamera.get();
}
}
};

View File

@@ -0,0 +1,77 @@
/**
* Represents the history of an object
* @constructor
*/
var History = function() {
/**
* Stores the different states of the object
* @type {Object[]}
*/
this.states = [];
/**
* Represents the position in the history we're at
* @type {Number}
*/
this.index = -1;
/**
* Represents the number of elements in the history
* @type {Number}
*/
this.size = 0;
};
/**
* Appends a new state at the end of the history
* @param {Object} state the state to append
*/
History.prototype.addState = function(state) {
++this.index;
this.size = this.index + 1;
this.states[this.size-1] = state;
};
/**
* Returns the previous state and change the index to the previous state (so you can redo)
*/
History.prototype.undo = function() {
if (this.undoable()) {
this.index--;
return this.currentState();
}
};
/**
* Returns the next state and change the index to the next state (so you can re-undo)
*/
History.prototype.redo = function() {
if (this.redoable()) {
this.index++;
return this.currentState();
}
};
/**
* Checks if there is a undo possibility
* @returns {Boolean} true if undo is possible, false otherwise
*/
History.prototype.undoable = function() {
return this.index > 0;
};
/**
* Checks if there is a redo possibility
* @returns {Boolean} true if redo is possible, false otherwise
*/
History.prototype.redoable = function() {
return this.index < this.size - 1;
};
/**
* Returns the current state in the history
* @returns {Object} the current state in the history
*/
History.prototype.currentState = function() {
return this.states[this.index];
};

242
js/l3d/src/utils/List.js Normal file
View File

@@ -0,0 +1,242 @@
var utils = (function() {
var utils = {};
// Defines a double linked-list class
utils.List = function() {
this._size = 0;
this._begin = null;
this._end = null;
};
// Returns the number of element of a list
utils.List.prototype.size = function() {
return this._size;
};
// Pushes an element to the end of a class
utils.List.prototype.push = function(element) {
if (this._size === 0) {
this._begin = { data : element, next: null, prev: null };
this._end = this._begin;
this._size = 1;
} else {
var newObject = { data: element, next: null, prev: this._end };
this._end.next = newObject;
this._end = newObject;
this._size++;
}
};
// Sort the list
utils.List.prototype.sort = function(comparator) {
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
var array = [];
this.forEach(function(elt) {
array.push(elt);
});
array.sort(function(a, b) {
return comparator(a, b);
});
var size = this.size();
this.clear();
for (var i = 0; i < size; i++) {
this.push(array[i]);
}
};
// Remove last element and returns it
utils.List.prototype.pop = function() {
var tmp = this._end;
this._end = null;
return tmp.data;
};
// Apply a function to each element of the list
utils.List.prototype.forEach = function(callback) {
var chain = this._begin;
while (chain !== null) {
callback(chain.data);
chain = chain.next;
}
};
// Apply a function to each element of the list (starting from the end)
utils.List.prototype.forEachInverse = function(callback) {
var chain = this._end;
while (chain !== null) {
callback(chain.data);
chain = chain.prev;
}
};
// Get ith element of the list
utils.List.prototype.at = function(ith) {
if (ith < 0 || ith >= this.size()) {
return null;
}
var chain = this._begin;
for (var i = 0; i < ith; i++) {
chain = chain.next;
}
return chain.data;
};
// Clear the list
utils.List.prototype.clear = function() {
this._begin = null;
this._end = null;
this._size = 0;
};
// Insert an element at the right place in the list
// Precondition : list must be sorted
utils.List.prototype.insertSorted = function(elt, comparator) {
var newElement;
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
if (this._begin === null) {
// Inserted in front (empty list)
this.push(elt);
} else if (comparator(this._begin.data, elt) > 0) {
// Inserted in front (smallest element)
newElement = {prev: null, next: this._begin, data: elt};
this._begin.prev = newElement;
this._begin = newElement;
this._size ++;
} else if (comparator(this._end.data, elt) < 0) {
// Inserted in end
this.push(elt);
} else {
// Inserted in the middle
var chain = this._begin;
while (chain.next !== null) {
// If chain < elt < chain.next
if (comparator(chain.next.data, elt) > 0) {
newElement = {data: elt, next: chain.next, prev: chain};
if (chain.next) {
chain.next.prev = newElement;
}
chain.next = newElement;
this._size ++;
return;
}
// Next step
chain = chain.next;
}
}
};
// Check if a list is sorted of not
utils.List.prototype.isSorted = function(comparator) {
var chain = this._begin;
if (comparator === undefined) {
comparator = priv.defaultComparator;
}
while (chain.next !== null) {
if (comparator(chain.data, chain.next.data) > 0) {
return false;
}
chain = chain.next;
}
return true;
};
// Gives an iterator to the begin of the list
utils.List.prototype.begin = function() {
return new utils.List.Iterator(this._begin, 0);
};
// Gives an iterator to the end of the list
utils.List.prototype.end = function() {
return new utils.List.Iterator(this._end, this.size() - 1);
};
// Class iterator
utils.List.Iterator = function(chain, counter) {
this._chain = chain;
this._counter = counter;
};
// Go to the next element
utils.List.Iterator.prototype.next = function() {
this._chain = this._chain.next;
this._counter ++;
};
// Go to the previous element
utils.List.Iterator.prototype.prev = function() {
this._chain = this._chain.prev;
this._counter --;
};
// Return the current element
utils.List.Iterator.prototype.get = function() {
return this._chain.data;
};
// Check if there is another element next
utils.List.Iterator.prototype.hasNext = function() {
return this._chain.next !== null;
};
// Check if there is another element before
utils.List.Iterator.prototype.hasPrev = function() {
return this._chain.prev !== null;
};
// Compares to another iterator of the same list
utils.List.Iterator.prototype.lowerThan = function(it2) {
return utils.distance(this, it2) > 0;
};
// Compares to another iterator of the same list
utils.List.Iterator.prototype.greaterThan = function(it2) {
return utils.distance(this, it2) < 0;
};
// Returns the distance between two iterators of the same list
utils.distance = function(it1, it2) {
return it2._counter - it1._counter;
};
priv = {};
priv.defaultComparator = function(a,b) {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
};
// Support for NodeJs
if (typeof module !== 'undefined' && module.exports) {
module.exports = utils;
} else {
return utils;
}
})();

View File

@@ -0,0 +1,17 @@
var list = new utils.List();
var size = 100;
for (var i = 0; i < size; i++) {
list.push(Math.random());
}
// For with C++-style iterator
// for (var it = list.begin(); it.lowerThan(list.end()); it.next()) {
// console.log(it.get());
// }
console.log(false === list.isSorted());
list.sort();
console.log(list.isSorted());
console.log(size === list.size());

116
js/l3d/src/utils/Logger.js Normal file
View File

@@ -0,0 +1,116 @@
var BD = {};
BD.Private = {};
BD.Private.sendData = function(url, data) {
if (BD.Private.enabled) {
// Append time to data
data.time = Date.now() / 1000;
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/json;charset=UTF-8");
// xhr.onreadystatechange = function() {
// if(xhr.readyState == 4 && xhr.status == 200) {
// console.log("Done : " + xhr.responseText);
// }
// }
xhr.send(JSON.stringify(data));
}
};
BD.Private.enabled = true;
BD.enable = function() {
BD.Private.enabled = true;
};
BD.disable = function() {
BD.Private.enabled = false;
};
BD.Private.compactCamera = function(camera) {
return {
position: {
x: camera.position.x,
y: camera.position.y,
z: camera.position.z
},
target: {
x: camera.target.x,
y: camera.target.y,
z: camera.target.z
}
};
};
BD.Event = {};
BD.Event.ArrowClicked = function() {};
BD.Event.ArrowClicked.prototype.send = function() {
var url = "/arrow-clicked";
var data = {arrow_id: this.arrow_id};
BD.Private.sendData(url, data);
};
BD.Event.CoinClicked = function() {};
BD.Event.CoinClicked.prototype.send = function() {
var url = "/coin-clicked";
var data = {coin_id: this.coin_id};
BD.Private.sendData(url, data);
};
BD.Event.KeyboardEvent = function() {};
BD.Event.KeyboardEvent.prototype.send = function() {
var url = "/keyboard-event";
var data = {
camera: BD.Private.compactCamera(this.camera)
};
BD.Private.sendData(url, data);
};
BD.Event.ResetClicked = function() {};
BD.Event.ResetClicked.prototype.send = function() {
var url = "/reset-clicked";
var data = {};
BD.Private.sendData(url, data);
};
BD.Event.PreviousNextClicked = function() {};
BD.Event.PreviousNextClicked.prototype.send = function() {
var url = "/previous-next-clicked";
var data = {
// casts previous to boolean
previous: this.previous,
camera: BD.Private.compactCamera(this.camera)
};
BD.Private.sendData(url, data);
};
BD.Event.Hovered = function() {};
BD.Event.Hovered.prototype.send = function() {
var url = "/hovered";
var data = {
start: this.start,
arrow_id: this.arrow_id
};
BD.Private.sendData(url, data);
};
BD.Event.Fps = function() {};
BD.Event.Fps.prototype.send = function() {
var url = "/fps";
var data = {
fps: this.fps
};
BD.Private.sendData(url, data);
};

View File

@@ -0,0 +1,49 @@
var Displayable = function() {
// Nothing to do here
};
Displayable.prototype.addToScene = function(scene) {
scene.add(this.mesh);
};
Displayable.prototype.translate = function(x,y,z) {
this.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(x,y,z));
};
// class Cube extends Displayable
var Cube = function(size, style) {
// Super constructor call
Displayable.call(this);
if (size === undefined) size = 100;
if (style === undefined) style = {};
this.geometry = new THREE.BoxGeometry(size, size, size);
this.material = new THREE.MeshLambertMaterial(style);
this.mesh = new THREE.Mesh(this.geometry, this.material);
this.mesh.castShadow = false;
};
Cube.prototype = Object.create(Displayable.prototype);
Cube.prototype.constructor = Cube;
// class Plane extends Displayable
var Plane = function(size1, size2, style) {
Displayable.call(this);
if (style === undefined) style = {};
this.geometry = new THREE.PlaneBufferGeometry(size1, size2);
this.material = new THREE.MeshLambertMaterial(style);
this.material.side = THREE.DoubleSide;
this.mesh = new THREE.Mesh(this.geometry, this.material);
this.mesh.receiveShadow = true;
};
Plane.prototype = Object.create(Displayable.prototype);
Plane.prototype.constructor = Plane;
Plane.prototype.addToScene = function(scene) {
scene.add(this.mesh);
};