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,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);
};