A lot of cleaning, and compilation of the js code

This commit is contained in:
Thomas FORGIONE
2015-05-22 16:59:33 +02:00
parent fe34290802
commit a6a6c3521c
45 changed files with 100 additions and 41 deletions

36
js/BouncingCube.js Normal file
View File

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

View File

@@ -0,0 +1,32 @@
var Converter = {};
Converter.toGeometry = function (bg) {
// The following snippet is from Mattatz - Masatatsu Nakamura http://mattatz.org
var attrib = bg.getAttribute('position');
if(attrib === undefined) {
throw new Error('a given BufferGeometry object must have a position attribute.');
}
var positions = attrib.array;
var vertices = [];
for(var i = 0, n = positions.length; i < n; i += 3) {
var x = positions[i];
var y = positions[i + 1];
var z = positions[i + 2];
vertices.push(new THREE.Vector3(x, y, z));
}
var faces = [];
for(var i = 0, n = vertices.length; i < n; i += 3) {
faces.push(new THREE.Face3(i, i + 1, i + 2));
}
var geometry = new THREE.Geometry();
geometry.vertices = vertices;
geometry.faces = faces;
geometry.computeFaceNormals();
return geometry;
}

28
js/Camera.js Normal file
View File

@@ -0,0 +1,28 @@
// 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() {
this.theta += 0.01;
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;

77
js/CameraContainer.js Normal file
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);
}

50
js/Cube.js Normal file
View File

@@ -0,0 +1,50 @@
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.geometry.computeVertexNormals();
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);
}

201
js/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 = new Array();
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('];');

91
js/Logger.js Normal file
View File

@@ -0,0 +1,91 @@
var BD = {};
BD.Private = {};
BD.Private.sendData = function(url, data) {
// 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(xhr.responseText);
// }
// }
xhr.send(JSON.stringify(data));
}
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);
}

78
js/Makefile Normal file
View File

@@ -0,0 +1,78 @@
OPT=--compilation_level SIMPLE_OPTIMIZATIONS
CLOSURE=java -jar /usr/share/java/closure-compiler/closure-compiler.jar
all: Three Stats ThreeTools Bouncing Multisphere StreamingSimulator PrototypeTools PrototypeReplay PrototypeInteractive
Three:
cp three/three.min.js ../static/js/
Stats:
cp three/stats.min.js ../static/js/
ThreeTools:
$(CLOSURE) $(OPT) \
--js three/DDSLoader.js \
--js three/MTLLoader.js \
--js three/OBJMTLLoader.js \
--js three/OBJLoader.js \
--js three/OrbitControls.js \
--js Tools.js \
--js_output_file ../static/js/threetools.min.js
Bouncing:
$(CLOSURE) $(OPT) \
--js Camera.js \
--js Cube.js \
--js BouncingCube.js \
--js bouncing/BouncingMain.js \
--js_output_file ../static/js/bouncing.min.js
Multisphere:
$(CLOSURE) $(OPT) \
--js StaticPath.js \
--js Camera.js \
--js Cube.js \
--js multisphere/MultiSphere.js \
--js_output_file ../static/js/multisphere.min.js
StreamingSimulator:
$(CLOSURE) $(OPT) \
--js StaticPath.js \
--js Camera.js \
--js Cube.js \
--js ProgressiveSphere.js \
--js stream/main.js \
--js_output_file ../static/js/streamingsimulator.min.js
PrototypeTools:
$(CLOSURE) $(OPT) \
--js StaticPath.js \
--js Hermite.js \
--js Camera.js \
--js PointerCamera.js \
--js CameraContainer.js \
--js prototype/ArrowCamera.js \
--js prototype/FixedCamera.js \
--js prototype/OldFixedCamera.js \
--js prototype/ReverseCamera.js \
--js prototype/ReplayCamera.js \
--js prototype/initScene.js \
--js prototype/raycasterTools.js \
--js prototype/Previewer.js \
--js prototype/ButtonManager.js \
--js prototype/Coin.js \
--js Logger.js \
--js_output_file ../static/js/prototypetools.min.js
PrototypeInteractive:
$(CLOSURE) $(OPT) \
--js prototype/main.js \
--js_output_file ../static/js/prototypeinteractive.min.js
PrototypeReplay:
$(CLOSURE) $(OPT) \
--js prototype/replay.js \
--js_output_file ../static/js/replay.min.js
clean:
rm -ri ../static/js/*

422
js/PointerCamera.js Normal file
View File

@@ -0,0 +1,422 @@
// class camera extends THREE.PerspectiveCamera
var PointerCamera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
if (arguments[4] === undefined)
listenerTarget = document;
else
listenerTarget = arguments[4];
// Set Position
this.theta = Math.PI;
this.phi = Math.PI;
// this.keyboard = undefined;
this.moving = false;
this.dragging = false;
this.mouse = {x: 0, y: 0};
this.mouseMove = {x: 0, y: 0};
// Stuff for rendering
this.position = new THREE.Vector3();
this.forward = new THREE.Vector3();
this.left = new THREE.Vector3();
this.target = new THREE.Vector3(0,1,0);
// Stuff for events
this.motion = {};
this.sensitivity = 0.05;
this.speed = 1;
// Raycaster for collisions
this.raycaster = new THREE.Raycaster();
// Create history object
this.history = new History();
// Set events from the document
var self = this;
var onKeyDown = function(event) {self.onKeyDown(event);};
var onKeyUp = function(event) {self.onKeyUp(event);};
var onMouseDown = function(event) {self.onMouseDown(event); };
var onMouseMove = function(event) {self.onMouseMove(event); };
var onMouseUp = function(event) {self.onMouseUp(event); };
document.addEventListener('keydown', onKeyDown, false);
document.addEventListener('keyup', onKeyUp, false);
listenerTarget.addEventListener('mousedown', function(event) { if (event.which == 1) onMouseDown(event);}, false);
listenerTarget.addEventListener('mousemove', function(event) { if (event.which == 1) onMouseMove(event);}, false);
listenerTarget.addEventListener('mouseup', onMouseUp, false);
// listenerTarget.addEventListener('mouseup', function() { console.log("mouseup");}, false);
// listenerTarget.addEventListener('mouseout', onMouseUp, false);
this.collisions = true;
}
PointerCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
PointerCamera.prototype.constructor = PointerCamera;
// Update function
PointerCamera.prototype.update = function(time) {
if (this.moving) {
this.linearMotion(time);
} else if (this.movingHermite) {
this.hermiteMotion(time);
} else {
this.normalMotion(time);
}
}
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();
}
}
PointerCamera.prototype.hermiteMotion = function(time) {
var eval = this.hermitePosition.eval(this.t);
this.position.x = eval.x;
this.position.y = eval.y;
this.position.z = eval.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();
}
}
PointerCamera.prototype.normalMotion = function(time) {
// Update angles
if (this.motion.increasePhi) {this.phi += this.sensitivity; this.changed = true; }
if (this.motion.decreasePhi) {this.phi -= this.sensitivity; this.changed = true; }
if (this.motion.increaseTheta) {this.theta += this.sensitivity; this.changed = true; }
if (this.motion.decreaseTheta) {this.theta -= this.sensitivity; this.changed = true; }
if (this.dragging) {
this.theta += this.mouseMove.x;
this.phi -= this.mouseMove.y;
this.mouseMove.x = 0;
this.mouseMove.y = 0;
this.changed = true;
}
// Clamp phi and theta
this.phi = Math.min(Math.max(-(Math.PI/2-0.1),this.phi), Math.PI/2-0.1);
this.theta = ((this.theta - Math.PI) % (2*Math.PI)) + Math.PI;
// Compute vectors (position and target)
this.vectorsFromAngles();
// Update with events
var delta = 0.1;
var forward = this.forward.clone();
forward.multiplyScalar(400.0 * delta);
var left = this.up.clone();
left.cross(forward);
left.normalize();
left.multiplyScalar(400.0 * delta);
// Move only if no collisions
var speed = this.speed * time / 20;
var direction = new THREE.Vector3();
if (this.motion.boost) speed *= 10;
if (this.motion.moveForward) {direction.add(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveBackward) {direction.sub(Tools.mul(forward, speed)); this.changed = true;}
if (this.motion.moveLeft) {direction.add(Tools.mul(left, speed)); this.changed = true;}
if (this.motion.moveRight) {direction.sub(Tools.mul(left, speed)); this.changed = true;}
if (!this.collisions || !this.isColliding(direction)) {
this.position.add(direction);
}
// Update angle
this.target = this.position.clone();
this.target.add(forward);
}
PointerCamera.prototype.reset = function() {
this.resetBobomb();
this.moving = false;
this.movingHermite = false;
(new BD.Event.ResetClicked()).send();
// this.position.copy(new THREE.Vector3(-8.849933489419644, 9.050627639459208, 0.6192960680432451));
// this.target.copy(new THREE.Vector3(17.945323228767702, -15.156828589982375, -16.585740412769756));
// this.anglesFromVectors();
}
PointerCamera.prototype.resetBobomb = function() {
this.position.copy(new THREE.Vector3(34.51854618261728,10.038879540840306,-21.772598201888613));
this.target.copy(new THREE.Vector3(-2.593404107644737,8.039712770013185,-6.983870133675925));
this.anglesFromVectors();
}
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();
}
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);
}
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()});
}
}
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()});
}
}
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 < 100*this.speed) {
return true;
}
}
return false;
}
// Look function
PointerCamera.prototype.look = function() {
this.lookAt(this.target);
}
PointerCamera.prototype.addToScene = function(scene) {
scene.add(this);
}
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 event = new BD.Event.KeyboardEvent();
event.camera = this;
event.send();
}
}
PointerCamera.prototype.onKeyDown = function(event) {
this.onKeyEvent(event, true);
}
PointerCamera.prototype.onKeyUp = function(event) {
this.onKeyEvent(event, false);
}
PointerCamera.prototype.onMouseDown = function(event) {
this.mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
this.dragging = true;
this.mouseMoved = false;
}
PointerCamera.prototype.onMouseMove = function(event) {
if (this.dragging) {
var mouse = {x: this.mouse.x, y: this.mouse.y};
this.mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
this.mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;
this.mouseMove.x = this.mouse.x - mouse.x;
this.mouseMove.y = this.mouse.y - mouse.y;
this.mouseMoved = true;
}
}
PointerCamera.prototype.onMouseUp = function(event) {
this.onMouseMove(event);
// Send log to DB
if (this.dragging && this.mouseMoved && !this.moving && !this.movingHermite) {
var event = new BD.Event.KeyboardEvent();
event.camera = this;
event.send();
}
this.dragging = false;
}
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)');
}
PointerCamera.prototype.save = function() {
var backup = {};
backup.position = this.position.clone();
backup.target = this.target.clone();
this.history.addState(backup);
}
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);
}
}
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);
}
}
PointerCamera.prototype.undoable = function() {
return this.history.undoable();
}
PointerCamera.prototype.redoable = function() {
return this.history.redoable();
}
var History = function() {
this.states = new Array();
this.index = -1;
this.size = 0;
console.log('New state ' + this.index + ' / ' + this.size);
}
History.prototype.addState = function(state) {
++this.index;
this.size = this.index + 1;
this.states[this.size-1] = state;
console.log('New state ' + this.index + ' / ' + this.size);
}
History.prototype.undo = function() {
if (this.undoable()) {
this.index--;
console.log('New state ' + this.index + ' / ' + this.size);
return this.currentState();
}
}
History.prototype.redo = function() {
if (this.redoable()) {
this.index++;
console.log('New state ' + this.index + ' / ' + this.size);
return this.currentState();
}
}
History.prototype.undoable = function() {
return this.index > 0;
}
History.prototype.redoable = function() {
return this.index < this.size - 1;
}
History.prototype.currentState = function() {
return this.states[this.index];
}

89
js/ProgressiveSphere.js Normal file
View File

@@ -0,0 +1,89 @@
var ProgessiveSphere = function(loader, res) {
Displayable.call(this);
this.started = false;
this.finished = false;
this.wasFinished = false;
this.begin = false;
this.addedToScene = false;
if (res === undefined)
res = 5;
(function(self) {
loader.load(static_path + 'data/spheres/' + res + '.obj', function(object) {
object.traverse(function(child) {
if (child instanceof THREE.Mesh) {
child.up = new THREE.Vector3(0,0,1);
self.totalMesh = child;
self.geometry = new THREE.Geometry();
self.material = new THREE.MeshLambertMaterial();
self.material.color.setRGB(1,0,0);
self.material.side = THREE.DoubleSide;
self.mesh = new THREE.Mesh(self.geometry, self.material);
self.current_face = 0;
self.started = true;
self.begin = true;
self.addToScene(scene);
}
});
});
})(this);
}
ProgessiveSphere.prototype = Object.create(Displayable.prototype);
ProgessiveSphere.prototype.constructor = ProgessiveSphere;
ProgessiveSphere.prototype.addFace = function() {
if (this.started && this.begin && this.addedToScene) {
if (this.current_face < this.totalMesh.geometry.attributes.position.array.length / 3) {
// Add the 3 new vertices
this.geometry.vertices.push(new THREE.Vector3(
this.totalMesh.geometry.attributes.position.array[3*this.current_face],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+1],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+2]
));
this.geometry.vertices.push(new THREE.Vector3(
this.totalMesh.geometry.attributes.position.array[3*this.current_face+3],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+4],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+5]
));
this.geometry.vertices.push(new THREE.Vector3(
this.totalMesh.geometry.attributes.position.array[3*this.current_face+6],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+7],
this.totalMesh.geometry.attributes.position.array[3*this.current_face+8]
));
// Add the new face
this.geometry.faces.push(new THREE.Face3(
this.geometry.vertices.length-3,
this.geometry.vertices.length-2,
this.geometry.vertices.length-1
));
// Update the stuff
this.geometry.mergeVertices();
this.geometry.computeFaceNormals();
this.geometry.computeVertexNormals();
this.current_face += 3;
this.geometry.elementsNeedUpdate = true;
this.geometry.normalsNeedUpdate = true;
this.geometry.verticesNeedUpdate = true;
this.geometry.groupsNeedUpdate = true;
} else {
this.finished = true;
}
}
if (!this.wasFinished && this.finished) {
this.wasFinished = true;
console.log("Finished reconstructing the mesh !");
}
}
ProgessiveSphere.prototype.addToScene = function(scene) {
Displayable.prototype.addToScene.call(this, scene);
this.addedToScene = true;
}

1
js/StaticPath.js Normal file
View File

@@ -0,0 +1 @@
static_path = "/static/";

37
js/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));
}

79
js/ToolsTest.js Normal file
View File

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

View File

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

252
js/prototype/ArrowCamera.js vendored Normal file
View File

@@ -0,0 +1,252 @@
// 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;
}
// 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 vertices = new Array();
// 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 (var 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 = new Array();
for (var 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.facesNeedUpdate = 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;
}

63
js/prototype/ButtonManager.js vendored Normal file
View File

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

93
js/prototype/Coin.js vendored Normal file
View File

@@ -0,0 +1,93 @@
var Coin = function(x,y,z) {
this.ready = false;
this.got = false;
this.init(x,y,z);
}
var _toto = new Audio();
Coin.extension = _toto.canPlayType("audio/x-vorbis") === "" ? ".ogg" : ".mp3";
Coin.prototype.init = function(x,y,z) {
Coin.nextSound = new Audio(static_path + 'data/music/redcoins/1' + Coin.extension);
if (Coin.BASIC_MESH !== null) {
this.mesh = Coin.BASIC_MESH.clone();
this.mesh.position.x = x;
this.mesh.position.y = y;
this.mesh.position.z = z;
this.ready = true;
this.mesh.raycastable = true;
} else {
(function(self,x,y,z) {
setTimeout(function() {
self.init(x,y,z);
},1000);
})(this,x,y,z);
}
}
Coin.prototype.addToScene = function(scene) {
scene.add(this.mesh);
}
Coin.prototype.update = function() {
if (this.ready)
(function(self) {
self.update = function() {
// self.mesh.rotation.y += 0.1;
}
})(this);
}
Coin.prototype.get = function() {
if (!this.got) {
this.got = true;
if (this.mesh) {
this.mesh.visible = false;
}
Coin.total ++;
Coin.nextSound.play();
if (Coin.total === 9) {
// You got the last coin
var music = document.getElementById('music');
var wasPlaying = !music.paused;
music.pause();
(function(music, wasPlaying) {
setTimeout(function() {
Coin.lastSound.play();
(function(wasPlaying) {
setTimeout(function() {
if (wasPlaying) {
music.play();
}
}, Coin.lastSound.duration*1000);
})(wasPlaying);
}, Coin.nextSound.duration*1000);
})(music, wasPlaying);
} else {
Coin.nextSound = new Audio('/static/data/music/redcoins/' + Coin.total + Coin.extension);
Coin.nextSound.preload = "auto";
}
}
}
Coin.lastSound = new Audio('/static/data/music/starappears' + Coin.extension);
Coin.lastSound.preload = "auto";
Coin.total = 1;
Coin.BASIC_MESH = null;
Coin._loader = new THREE.OBJLoader();
Coin._loader.load(
static_path + 'data/coin/Coin.obj',
function(object) {
object.traverse(function (mesh) {
if (mesh instanceof THREE.Mesh) {
mesh.scale.set(0.005,0.005,0.005);
mesh.material.color.setHex(0xff0000);
mesh.geometry.computeVertexNormals();
mesh.raycastable = true;
Coin.BASIC_MESH = mesh
}
});
}
);

9
js/prototype/FixedCamera.js vendored Normal file
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;

141
js/prototype/OldFixedCamera.js vendored Normal file
View File

@@ -0,0 +1,141 @@
// 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 direction = Tools.mul(direction, -2);
var target = Tools.sum(self.position, 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, direction),
Tools.sum(Tools.sum(self.position, left), other),
Tools.sum(self.position, direction),
Tools.diff(Tools.sum(self.position, other),left),
Tools.sum(self.position, direction),
Tools.diff(Tools.diff(self.position, left),other),
Tools.sum(self.position, 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;
}

79
js/prototype/Previewer.js vendored Normal file
View File

@@ -0,0 +1,79 @@
Math.clamp = Math.clamp || function(number, min, max) {
return Math.max(Math.min(number, max), min);
}
var Previewer = function(renderer) {
this.domElement = document.createElement('canvas');
this.ctx = this.domElement.getContext('2d');
this.renderer = renderer;
this.fixed = 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(scene, prev.camera);
if (!this.fixed) {
this.clearNeeded = true;
}
} else if (this.fixed) {
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;
}

201
js/prototype/ReplayCamera.js vendored Normal file
View File

@@ -0,0 +1,201 @@
// class camera extends THREE.PerspectiveCamera
var ReplayCamera = function() {
THREE.PerspectiveCamera.apply(this, arguments);
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);
(function(self) {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
self.path = JSON.parse(xhr.responseText);
self.reset();
self.started = true;
self.nextEvent();
}
}
})(this);
xhr.send();
// Set Position
this.theta = Math.PI;
this.phi = Math.PI;
}
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 eval = this.hermitePosition.eval(this.t);
this.position.x = eval.x;
this.position.y = eval.y;
this.position.z = eval.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') {
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(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.resetBobomb();
this.moving = false;
this.movingHermite = false;
// this.position.copy(new THREE.Vector3(-8.849933489419644, 9.050627639459208, 0.6192960680432451));
// this.target.copy(new THREE.Vector3(17.945323228767702, -15.156828589982375, -16.585740412769756));
// this.anglesFromVectors();
}
ReplayCamera.prototype.resetBobomb = function() {
this.position.copy(new THREE.Vector3(34.51854618261728,10.038879540840306,-21.772598201888613));
this.target.copy(new THREE.Vector3(-2.593404107644737,8.039712770013185,-6.983870133675925));
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()
);
}

74
js/prototype/ReverseCamera.js vendored Normal file
View File

@@ -0,0 +1,74 @@
// 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;
}

336
js/prototype/initScene.js vendored Normal file
View File

@@ -0,0 +1,336 @@
// Define RecommendedCamera if not defined
var RecommendedCamera = RecommendedCamera || FixedCamera;
function initPeachCastle(scene, collidableObjects, loader, static_path) {
// Create loader if not already done
if (loader === undefined) {
loader = new THREE.OBJMTLLoader();
}
// Try to guess the path to static files
if (static_path === undefined) {
static_path = "/static/";
}
loader.load(
static_path + 'data/castle/princess peaches castle (outside).obj',
static_path + 'data/castle/princess peaches castle (outside).mtl',
function ( object ) {
object.up = new THREE.Vector3(0,0,1);
scene.add(object);
collidableObjects.push(object);
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 === 'Material.103_princess_peaches_cast') {
object.material.transparent = true;
}
}
});
}
);
loader.load(
static_path + 'data/first/Floor 1.obj',
static_path + 'data/first/Floor 1.mtl',
function ( object ) {
object.position.z -= 10.9;
object.position.y += 0.555;
object.position.x += 3.23;
var theta = 0.27;
object.rotation.y = Math.PI - theta;
object.up = new THREE.Vector3(0,0,1);
scene.add(object);
collidableObjects.push(object);
object.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.material.side = THREE.DoubleSide;
object.geometry.mergeVertices();
object.geometry.computeVertexNormals();
object.raycastable = true;
if (object.material.name === 'Material.054_777F0E0B_c.bmp' ||
object.material.name === 'Material.061_5C3492AB_c.bmp' ) {
object.material.transparent = true;
}
}
});
}
);
}
function initZeldaScene(scene, collidableObjects, loader, static_path) {
// Create loader if not already done
if (loader === undefined) {
loader = new THREE.OBJMTLLoader();
}
// Try to guess the path to static files
if (static_path === undefined) {
static_path = "/static/";
}
loader.load(
static_path + 'data/zelda/Island.obj',
static_path + 'data/zelda/Island.mtl',
function ( object ) {
scene.add(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') {
object.material.transparent = true;
}
}
});
}
);
// loader.load(
// static_path + 'data/zelda/Sea.obj',
// static_path + 'data/zelda/Sea.mtl',
// function ( object ) {
// scene.add(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.raycastable = true;
// }
// });
// }
// );
// loader.load(
// static_path + 'data/zelda/Window Lights.obj',
// static_path + 'data/zelda/Window Lights.mtl',
// function ( object ) {
// scene.add(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.raycastable = true;
// }
// });
// }
// );
}
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)
));
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)
));
return cams;
}
function initBobombScene(scene, collidableObjects, loader, static_path) {
// Create loader if not already done
if (loader === undefined) {
loader = new THREE.OBJMTLLoader();
}
// Try to guess the path to static files
if (static_path === undefined) {
static_path = "/static/";
}
loader.load(
static_path + 'data/bobomb/bobomb battlefeild.obj',
static_path + 'data/bobomb/bobomb battlefeild.mtl',
function ( object ) {
// object.position.z -= 10.9;
// object.position.y += 0.555;
// object.position.x += 3.23;
var theta = 0.27;
object.rotation.y = Math.PI - theta;
object.up = new THREE.Vector3(0,0,1);
collidableObjects.push(object);
scene.add(object);
object.traverse(function (object) {
if (object instanceof THREE.Mesh) {
object.raycastable = true;
object.material.side = THREE.DoubleSide;
object.geometry.mergeVertices();
object.geometry.computeVertexNormals();
if (object.material.name === 'Material.071_574B138E_c.bmp' ||
object.material.name === 'Material.070_41A41EE3_c.bmp') {
object.material.transparent = true;
}
}
});
}
);
// loader.load(
// static_path + 'data/star/GrandStar.obj',
// static_path + 'data/star/GrandStar.mtl',
// function ( object ) {
// object.position.z -= 10.9;
// object.position.y += 0.555;
// object.position.x += 3.23;
// var theta = 0.27;
// object.rotation.y = Math.PI - theta;
// object.up = new THREE.Vector3(0,0,1);
// scene.add(object);
// collidableObjects.push(object);
// object.traverse(function (object) {
// if (object instanceof THREE.Mesh) {
// object.scale.set(0.005,0.005,0.005);
// object.position.x = 13;
// object.position.z = -35;
// object.position.y = 30;
// object.rotation.z = Math.PI/2;
// object.rotation.x = Math.PI/2;
// object.rotation.y = Math.PI;
// object.material.side = THREE.DoubleSide;
// object.geometry.mergeVertices();
// object.geometry.computeVertexNormals();
// object.raycastable = true;
// }
// });
// }
//);
}
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;
}

279
js/prototype/main.js vendored Normal file
View File

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

109
js/prototype/raycasterTools.js vendored Normal file
View File

@@ -0,0 +1,109 @@
var CameraSelecter = function(renderer, cameras, buttonManager) {
this.raycaster = new THREE.Raycaster();
this.renderer = renderer;
this.mouse = {};
this.cameras = cameras;
this.prev = {};
this.buttonManager = buttonManager;
}
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();
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(scene.children, true);
if ( intersects.length > 0 ) {
var minDistance;
var bestIndex;
// Looking for cameras
for (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 coins) {
if (obj === coins[coin].mesh) {
return coins[coin];
}
}
this.currentPointedCamera = this.cameras.getByObject(intersects[bestIndex].object);
return this.currentPointedCamera;
// }
}
}
this.currentPointedCamera = null;
}
CameraSelecter.prototype.update = function(event) {
if (event !== undefined) {
this.mouse.x = event.offsetX == undefined ? event.layerX : event.offsetX;
this.mouse.y = event.offsetY == undefined ? event.layerY : event.offsetY;
}
var previousCamera = this.currentPointedCamera;
var hovered = this.pointedCamera(event);
if (hovered !== undefined && !(hovered instanceof Coin)) {
if (hovered !== previousCamera) {
// log it
var event = new BD.Event.Hovered();
event.start = true;
event.arrow_id = cameras.cameras.indexOf(this.currentPointedCamera);
event.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
var event = new BD.Event.Hovered();
event.start = false;
event.arrow_id = null;
event.send();
}
this.prev.go = false;
}
}
CameraSelecter.prototype.click = function(event) {
var newCamera = this.pointedCamera(event);
if (newCamera !== undefined && !(newCamera instanceof Coin)) {
var event = new BD.Event.ArrowClicked();
event.arrow_id = cameras.cameras.indexOf(newCamera);
event.send();
newCamera.check();
this.cameras.mainCamera().moveHermite(newCamera);
buttonManager.updateElements();
} else if (newCamera instanceof Coin) {
// Coin found, notify server
var event = new BD.Event.CoinClicked();
event.coin_id = coins.indexOf(newCamera);
event.send();
newCamera.get();
}
}

254
js/prototype/replay.js vendored Normal file
View File

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

87
js/stream/main.js Normal file
View File

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

35133
js/three.js Normal file

File diff suppressed because one or more lines are too long

237
js/three/DDSLoader.js Normal file
View File

@@ -0,0 +1,237 @@
/*
* @author mrdoob / http://mrdoob.com/
*/
THREE.DDSLoader = function () {
this._parser = THREE.DDSLoader.parse;
};
THREE.DDSLoader.prototype = Object.create( THREE.CompressedTextureLoader.prototype );
THREE.DDSLoader.prototype.constructor = THREE.DDSLoader;
THREE.DDSLoader.parse = function ( buffer, loadMipmaps ) {
var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 };
// Adapted from @toji's DDS utils
// https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js
// All values and structures referenced from:
// http://msdn.microsoft.com/en-us/library/bb943991.aspx/
var DDS_MAGIC = 0x20534444;
var DDSD_CAPS = 0x1,
DDSD_HEIGHT = 0x2,
DDSD_WIDTH = 0x4,
DDSD_PITCH = 0x8,
DDSD_PIXELFORMAT = 0x1000,
DDSD_MIPMAPCOUNT = 0x20000,
DDSD_LINEARSIZE = 0x80000,
DDSD_DEPTH = 0x800000;
var DDSCAPS_COMPLEX = 0x8,
DDSCAPS_MIPMAP = 0x400000,
DDSCAPS_TEXTURE = 0x1000;
var DDSCAPS2_CUBEMAP = 0x200,
DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
DDSCAPS2_VOLUME = 0x200000;
var DDPF_ALPHAPIXELS = 0x1,
DDPF_ALPHA = 0x2,
DDPF_FOURCC = 0x4,
DDPF_RGB = 0x40,
DDPF_YUV = 0x200,
DDPF_LUMINANCE = 0x20000;
function fourCCToInt32( value ) {
return value.charCodeAt(0) +
(value.charCodeAt(1) << 8) +
(value.charCodeAt(2) << 16) +
(value.charCodeAt(3) << 24);
}
function int32ToFourCC( value ) {
return String.fromCharCode(
value & 0xff,
(value >> 8) & 0xff,
(value >> 16) & 0xff,
(value >> 24) & 0xff
);
}
function loadARGBMip( buffer, dataOffset, width, height ) {
var dataLength = width * height * 4;
var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength );
var byteArray = new Uint8Array( dataLength );
var dst = 0;
var src = 0;
for ( var y = 0; y < height; y ++ ) {
for ( var x = 0; x < width; x ++ ) {
var b = srcBuffer[src]; src ++;
var g = srcBuffer[src]; src ++;
var r = srcBuffer[src]; src ++;
var a = srcBuffer[src]; src ++;
byteArray[dst] = r; dst ++; //r
byteArray[dst] = g; dst ++; //g
byteArray[dst] = b; dst ++; //b
byteArray[dst] = a; dst ++; //a
}
}
return byteArray;
}
var FOURCC_DXT1 = fourCCToInt32("DXT1");
var FOURCC_DXT3 = fourCCToInt32("DXT3");
var FOURCC_DXT5 = fourCCToInt32("DXT5");
var headerLengthInt = 31; // The header length in 32 bit ints
// Offsets into the header array
var off_magic = 0;
var off_size = 1;
var off_flags = 2;
var off_height = 3;
var off_width = 4;
var off_mipmapCount = 7;
var off_pfFlags = 20;
var off_pfFourCC = 21;
var off_RGBBitCount = 22;
var off_RBitMask = 23;
var off_GBitMask = 24;
var off_BBitMask = 25;
var off_ABitMask = 26;
var off_caps = 27;
var off_caps2 = 28;
var off_caps3 = 29;
var off_caps4 = 30;
// Parse header
var header = new Int32Array( buffer, 0, headerLengthInt );
if ( header[ off_magic ] !== DDS_MAGIC ) {
console.error( 'THREE.DDSLoader.parse: Invalid magic number in DDS header.' );
return dds;
}
if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
console.error( 'THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.' );
return dds;
}
var blockBytes;
var fourCC = header[ off_pfFourCC ];
var isRGBAUncompressed = false;
switch ( fourCC ) {
case FOURCC_DXT1:
blockBytes = 8;
dds.format = THREE.RGB_S3TC_DXT1_Format;
break;
case FOURCC_DXT3:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT3_Format;
break;
case FOURCC_DXT5:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT5_Format;
break;
default:
if ( header[off_RGBBitCount] == 32
&& header[off_RBitMask]&0xff0000
&& header[off_GBitMask]&0xff00
&& header[off_BBitMask]&0xff
&& header[off_ABitMask]&0xff000000 ) {
isRGBAUncompressed = true;
blockBytes = 64;
dds.format = THREE.RGBAFormat;
} else {
console.error( 'THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC( fourCC ) );
return dds;
}
}
dds.mipmapCount = 1;
if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
}
//TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc.
dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false;
dds.width = header[ off_width ];
dds.height = header[ off_height ];
var dataOffset = header[ off_size ] + 4;
// Extract mipmaps buffers
var width = dds.width;
var height = dds.height;
var faces = dds.isCubemap ? 6 : 1;
for ( var face = 0; face < faces; face ++ ) {
for ( var i = 0; i < dds.mipmapCount; i ++ ) {
if ( isRGBAUncompressed ) {
var byteArray = loadARGBMip( buffer, dataOffset, width, height );
var dataLength = byteArray.length;
} else {
var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
}
var mipmap = { "data": byteArray, "width": width, "height": height };
dds.mipmaps.push( mipmap );
dataOffset += dataLength;
width = Math.max( width * 0.5, 1 );
height = Math.max( height * 0.5, 1 );
}
width = dds.width;
height = dds.height;
}
return dds;
};

441
js/three/MTLLoader.js Normal file
View File

@@ -0,0 +1,441 @@
/**
* Loads a Wavefront .mtl file specifying materials
*
* @author angelxuanchang
*/
THREE.MTLLoader = function( baseUrl, options, crossOrigin ) {
this.baseUrl = baseUrl;
this.options = options;
this.crossOrigin = crossOrigin;
};
THREE.MTLLoader.prototype = {
constructor: THREE.MTLLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader();
loader.setCrossOrigin( this.crossOrigin );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
/**
* Parses loaded MTL file
* @param text - Content of MTL file
* @return {THREE.MTLLoader.MaterialCreator}
*/
parse: function ( text ) {
var lines = text.split( "\n" );
var info = {};
var delimiter_pattern = /\s+/;
var materialsInfo = {};
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
// Blank line or comment ignore
continue;
}
var pos = line.indexOf( ' ' );
var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
key = key.toLowerCase();
var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : "";
value = value.trim();
if ( key === "newmtl" ) {
// New material
info = { name: value };
materialsInfo[ value ] = info;
} else if ( info ) {
if ( key === "ka" || key === "kd" || key === "ks" ) {
var ss = value.split( delimiter_pattern, 3 );
info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ];
} else {
info[ key ] = value;
}
}
}
var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
materialCreator.crossOrigin = this.crossOrigin
materialCreator.setMaterials( materialsInfo );
return materialCreator;
}
};
/**
* Create a new THREE-MTLLoader.MaterialCreator
* @param baseUrl - Url relative to which textures are loaded
* @param options - Set of options on how to construct the materials
* side: Which side to apply the material
* THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
* wrap: What type of wrapping to apply for textures
* THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
* normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
* Default: false, assumed to be already normalized
* ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
* Default: false
* invertTransparency: If transparency need to be inverted (inversion is needed if d = 0 is fully opaque)
* Default: false (d = 1 is fully opaque)
* @constructor
*/
THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) {
this.baseUrl = baseUrl;
this.options = options;
this.materialsInfo = {};
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
};
THREE.MTLLoader.MaterialCreator.prototype = {
constructor: THREE.MTLLoader.MaterialCreator,
setMaterials: function( materialsInfo ) {
this.materialsInfo = this.convert( materialsInfo );
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
},
convert: function( materialsInfo ) {
if ( !this.options ) return materialsInfo;
var converted = {};
for ( var mn in materialsInfo ) {
// Convert materials info into normalized form based on options
var mat = materialsInfo[ mn ];
var covmat = {};
converted[ mn ] = covmat;
for ( var prop in mat ) {
var save = true;
var value = mat[ prop ];
var lprop = prop.toLowerCase();
switch ( lprop ) {
case 'kd':
case 'ka':
case 'ks':
// Diffuse color (color under white light) using RGB values
if ( this.options && this.options.normalizeRGB ) {
value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
}
if ( this.options && this.options.ignoreZeroRGBs ) {
if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) {
// ignore
save = false;
}
}
break;
case 'd':
// According to MTL format (http://paulbourke.net/dataformats/mtl/):
// d is dissolve for current material
// factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
if ( this.options && this.options.invertTransparency ) {
value = 1 - value;
}
break;
default:
break;
}
if ( save ) {
covmat[ lprop ] = value;
}
}
}
return converted;
},
preload: function () {
for ( var mn in this.materialsInfo ) {
this.create( mn );
}
},
getIndex: function( materialName ) {
return this.nameLookup[ materialName ];
},
getAsArray: function() {
var index = 0;
for ( var mn in this.materialsInfo ) {
this.materialsArray[ index ] = this.create( mn );
this.nameLookup[ mn ] = index;
index ++;
}
return this.materialsArray;
},
create: function ( materialName ) {
if ( this.materials[ materialName ] === undefined ) {
this.createMaterial_( materialName );
}
return this.materials[ materialName ];
},
createMaterial_: function ( materialName ) {
// Create material
var mat = this.materialsInfo[ materialName ];
var params = {
name: materialName,
side: this.side
};
for ( var prop in mat ) {
var value = mat[ prop ];
switch ( prop.toLowerCase() ) {
// Ns is material specular exponent
case 'kd':
// Diffuse color (color under white light) using RGB values
params[ 'diffuse' ] = new THREE.Color().fromArray( value );
break;
case 'ka':
// Ambient color (color under shadow) using RGB values
break;
case 'ks':
// Specular color (color when light is reflected from shiny surface) using RGB values
params[ 'specular' ] = new THREE.Color().fromArray( value );
break;
case 'map_kd':
// Diffuse texture map
params[ 'map' ] = this.loadTexture( this.baseUrl + value );
params[ 'map' ].wrapS = this.wrap;
params[ 'map' ].wrapT = this.wrap;
break;
case 'ns':
// The specular exponent (defines the focus of the specular highlight)
// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
params['shininess'] = value;
break;
case 'd':
// According to MTL format (http://paulbourke.net/dataformats/mtl/):
// d is dissolve for current material
// factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
if ( value < 1 ) {
params['transparent'] = true;
params['opacity'] = value;
}
break;
case 'map_bump':
case 'bump':
// Bump texture map
if ( params[ 'bumpMap' ] ) break; // Avoid loading twice.
params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value );
params[ 'bumpMap' ].wrapS = this.wrap;
params[ 'bumpMap' ].wrapT = this.wrap;
break;
default:
break;
}
}
if ( params[ 'diffuse' ] ) {
params[ 'color' ] = params[ 'diffuse' ];
}
this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
return this.materials[ materialName ];
},
loadTexture: function ( url, mapping, onLoad, onError ) {
var texture;
var loader = THREE.Loader.Handlers.get( url );
if ( loader !== null ) {
texture = loader.load( url, onLoad );
} else {
texture = new THREE.Texture();
loader = new THREE.ImageLoader();
loader.crossOrigin = this.crossOrigin;
loader.load( url, function ( image ) {
texture.image = THREE.MTLLoader.ensurePowerOfTwo_( image );
texture.needsUpdate = true;
if ( onLoad ) onLoad( texture );
} );
}
if ( mapping !== undefined ) texture.mapping = mapping;
return texture;
}
};
THREE.MTLLoader.ensurePowerOfTwo_ = function ( image ) {
if ( ! THREE.Math.isPowerOfTwo( image.width ) || ! THREE.Math.isPowerOfTwo( image.height ) ) {
var canvas = document.createElement( "canvas" );
canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width );
canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height );
var ctx = canvas.getContext("2d");
ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
return canvas;
}
return image;
};
THREE.MTLLoader.nextHighestPowerOfTwo_ = function( x ) {
-- x;
for ( var i = 1; i < 32; i <<= 1 ) {
x = x | x >> i;
}
return x + 1;
};
THREE.EventDispatcher.prototype.apply( THREE.MTLLoader.prototype );

372
js/three/OBJLoader.js Normal file
View File

@@ -0,0 +1,372 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.OBJLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.OBJLoader.prototype = {
constructor: THREE.OBJLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader( scope.manager );
loader.setCrossOrigin( this.crossOrigin );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
parse: function ( text ) {
console.time( 'OBJLoader' );
var object, objects = [];
var geometry, material;
function parseVertexIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3;
}
function parseNormalIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3;
}
function parseUVIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2;
}
function addVertex( a, b, c ) {
geometry.vertices.push(
vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ],
vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ],
vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ]
);
}
function addNormal( a, b, c ) {
geometry.normals.push(
normals[ a ], normals[ a + 1 ], normals[ a + 2 ],
normals[ b ], normals[ b + 1 ], normals[ b + 2 ],
normals[ c ], normals[ c + 1 ], normals[ c + 2 ]
);
}
function addUV( a, b, c ) {
geometry.uvs.push(
uvs[ a ], uvs[ a + 1 ],
uvs[ b ], uvs[ b + 1 ],
uvs[ c ], uvs[ c + 1 ]
);
}
function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
var ia = parseVertexIndex( a );
var ib = parseVertexIndex( b );
var ic = parseVertexIndex( c );
var id;
if ( d === undefined ) {
addVertex( ia, ib, ic );
} else {
id = parseVertexIndex( d );
addVertex( ia, ib, id );
addVertex( ib, ic, id );
}
if ( ua !== undefined ) {
ia = parseUVIndex( ua );
ib = parseUVIndex( ub );
ic = parseUVIndex( uc );
if ( d === undefined ) {
addUV( ia, ib, ic );
} else {
id = parseUVIndex( ud );
addUV( ia, ib, id );
addUV( ib, ic, id );
}
}
if ( na !== undefined ) {
ia = parseNormalIndex( na );
ib = parseNormalIndex( nb );
ic = parseNormalIndex( nc );
if ( d === undefined ) {
addNormal( ia, ib, ic );
} else {
id = parseNormalIndex( nd );
addNormal( ia, ib, id );
addNormal( ib, ic, id );
}
}
}
// create mesh if no objects in text
if ( /^o /gm.test( text ) === false ) {
geometry = {
vertices: [],
normals: [],
uvs: []
};
material = {
name: ''
};
object = {
name: '',
geometry: geometry,
material: material
};
objects.push( object );
}
var vertices = [];
var normals = [];
var uvs = [];
// v float float float
var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vn float float float
var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vt float float
var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// f vertex vertex vertex ...
var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/;
// f vertex/uv vertex/uv vertex/uv ...
var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/;
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/;
// f vertex//normal vertex//normal vertex//normal ...
var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/
//
var lines = text.split( '\n' );
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
var result;
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
continue;
} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
vertices.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
normals.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
// ["vt 0.1 0.2", "0.1", "0.2"]
uvs.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
);
} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
// ["f 1 2 3", "1", "2", "3", undefined]
addFace(
result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
);
} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ],
result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ],
result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ]
);
} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
undefined, undefined, undefined, undefined,
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
} else if ( /^o /.test( line ) ) {
geometry = {
vertices: [],
normals: [],
uvs: []
};
material = {
name: ''
};
object = {
name: line.substring( 2 ).trim(),
geometry: geometry,
material: material
};
objects.push( object )
} else if ( /^g /.test( line ) ) {
// group
} else if ( /^usemtl /.test( line ) ) {
// material
material.name = line.substring( 7 ).trim();
} else if ( /^mtllib /.test( line ) ) {
// mtl file
} else if ( /^s /.test( line ) ) {
// smooth shading
} else {
// console.log( "THREE.OBJLoader: Unhandled line " + line );
}
}
var container = new THREE.Object3D();
for ( var i = 0, l = objects.length; i < l; i ++ ) {
object = objects[ i ];
geometry = object.geometry;
var buffergeometry = new THREE.BufferGeometry();
buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
if ( geometry.normals.length > 0 ) {
buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
}
if ( geometry.uvs.length > 0 ) {
buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
}
material = new THREE.MeshLambertMaterial();
material.name = object.material.name;
var mesh = new THREE.Mesh( buffergeometry, material );
mesh.name = object.name;
container.add( mesh );
}
console.timeEnd( 'OBJLoader' );
return container;
}
};

365
js/three/OBJMTLLoader.js Normal file
View File

@@ -0,0 +1,365 @@
/**
* Loads a Wavefront .obj file with materials
*
* @author mrdoob / http://mrdoob.com/
* @author angelxuanchang
*/
THREE.OBJMTLLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.OBJMTLLoader.prototype = {
constructor: THREE.OBJMTLLoader,
load: function ( url, mtlurl, onLoad, onProgress, onError ) {
var scope = this;
var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) );
mtlLoader.crossOrigin = scope.crossOrigin;
mtlLoader.load( mtlurl, function ( materials ) {
var materialsCreator = materials;
materialsCreator.preload();
var loader = new THREE.XHRLoader( scope.manager );
loader.setCrossOrigin( scope.crossOrigin );
loader.load( url, function ( text ) {
var object = scope.parse( text );
object.traverse( function ( object ) {
if ( object instanceof THREE.Mesh ) {
if ( object.material.name ) {
var material = materialsCreator.create( object.material.name );
if ( material ) object.material = material;
}
}
} );
onLoad( object );
}, onProgress, onError );
}, onProgress, onError );
},
/**
* Parses loaded .obj file
* @param data - content of .obj file
* @param mtllibCallback - callback to handle mtllib declaration (optional)
* @return {THREE.Object3D} - Object3D (with default material)
*/
parse: function ( data, mtllibCallback ) {
function vector( x, y, z ) {
return new THREE.Vector3( x, y, z );
}
function uv( u, v ) {
return new THREE.Vector2( u, v );
}
function face3( a, b, c, normals ) {
return new THREE.Face3( a, b, c, normals );
}
var face_offset = 0;
function meshN( meshName, materialName ) {
if ( vertices.length > 0 ) {
geometry.vertices = vertices;
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
object.add( mesh );
geometry = new THREE.Geometry();
mesh = new THREE.Mesh( geometry, material );
}
if ( meshName !== undefined ) mesh.name = meshName;
if ( materialName !== undefined ) {
material = new THREE.MeshLambertMaterial();
material.name = materialName;
mesh.material = material;
}
}
var group = new THREE.Group();
var object = group;
var geometry = new THREE.Geometry();
var material = new THREE.MeshLambertMaterial();
var mesh = new THREE.Mesh( geometry, material );
var vertices = [];
var normals = [];
var uvs = [];
function add_face( a, b, c, normals_inds ) {
if ( normals_inds === undefined ) {
geometry.faces.push( face3(
parseInt( a ) - (face_offset + 1),
parseInt( b ) - (face_offset + 1),
parseInt( c ) - (face_offset + 1)
) );
} else {
geometry.faces.push( face3(
parseInt( a ) - (face_offset + 1),
parseInt( b ) - (face_offset + 1),
parseInt( c ) - (face_offset + 1),
[
normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(),
normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(),
normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone()
]
) );
}
}
function add_uvs( a, b, c ) {
geometry.faceVertexUvs[ 0 ].push( [
uvs[ parseInt( a ) - 1 ].clone(),
uvs[ parseInt( b ) - 1 ].clone(),
uvs[ parseInt( c ) - 1 ].clone()
] );
}
function handle_face_line(faces, uvs, normals_inds) {
if ( faces[ 3 ] === undefined ) {
add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds );
if (!(uvs === undefined) && uvs.length > 0) {
add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] );
}
} else {
if (!(normals_inds === undefined) && normals_inds.length > 0) {
add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]);
add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]);
} else {
add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]);
add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]);
}
if (!(uvs === undefined) && uvs.length > 0) {
add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] );
add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] );
}
}
}
// v float float float
var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// vn float float float
var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// vt float float
var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// f vertex vertex vertex ...
var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/;
// f vertex/uv vertex/uv vertex/uv ...
var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/;
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/;
// f vertex//normal vertex//normal vertex//normal ...
var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/
//
var lines = data.split( "\n" );
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
var result;
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
continue;
} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
vertices.push( vector(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
) );
} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
normals.push( vector(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
) );
} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
// ["vt 0.1 0.2", "0.1", "0.2"]
uvs.push( uv(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
) );
} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
// ["f 1 2 3", "1", "2", "3", undefined]
handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]);
} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces
[ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv
);
} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces
[ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv
[ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal
);
} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces
[ ], //uv
[ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal
);
} else if ( /^o /.test( line ) ) {
// object
meshN();
face_offset = face_offset + vertices.length;
vertices = [];
object = new THREE.Object3D();
object.name = line.substring( 2 ).trim();
group.add( object );
} else if ( /^g /.test( line ) ) {
// group
meshN( line.substring( 2 ).trim(), undefined );
} else if ( /^usemtl /.test( line ) ) {
// material
meshN( undefined, line.substring( 7 ).trim() );
} else if ( /^mtllib /.test( line ) ) {
// mtl file
if ( mtllibCallback ) {
var mtlfile = line.substring( 7 );
mtlfile = mtlfile.trim();
mtllibCallback( mtlfile );
}
} else if ( /^s /.test( line ) ) {
// Smooth shading
} else {
console.log( "THREE.OBJMTLLoader: Unhandled line " + line );
}
}
//Add last object
meshN(undefined, undefined);
return group;
}
};
THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype );

706
js/three/OrbitControls.js Normal file
View File

@@ -0,0 +1,706 @@
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
*/
/*global THREE, console */
// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
// supported.
//
// Orbit - left mouse / touch: one finger move
// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
// Pan - right mouse, or arrow keys / touch: three finter swipe
THREE.OrbitControls = function ( object, domElement ) {
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
// Set to false to disable this control
this.enabled = true;
// "target" sets the location of focus, where the control orbits around
// and where it pans with respect to.
this.target = new THREE.Vector3();
// center is old, deprecated; use "target" instead
this.center = this.target;
// This option actually enables dollying in and out; left as "zoom" for
// backwards compatibility
this.noZoom = false;
this.zoomSpeed = 1.0;
// Limits to how far you can dolly in and out ( PerspectiveCamera only )
this.minDistance = 0;
this.maxDistance = Infinity;
// Limits to how far you can zoom in and out ( OrthographicCamera only )
this.minZoom = 0;
this.maxZoom = Infinity;
// Set to true to disable this control
this.noRotate = false;
this.rotateSpeed = 1.0;
// Set to true to disable this control
this.noPan = false;
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
// Set to true to automatically rotate around the target
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
this.minAzimuthAngle = - Infinity; // radians
this.maxAzimuthAngle = Infinity; // radians
// Set to true to disable use of the keys
this.noKeys = false;
// The four arrow keys
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// Mouse buttons
this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
////////////
// internals
var scope = this;
var EPS = 0.000001;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var panOffset = new THREE.Vector3();
var offset = new THREE.Vector3();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
var theta;
var phi;
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var pan = new THREE.Vector3();
var lastPosition = new THREE.Vector3();
var lastQuaternion = new THREE.Quaternion();
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
var state = STATE.NONE;
// for reset
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
// so camera.up is the orbit axis
var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
var quatInverse = quat.clone().inverse();
// events
var changeEvent = { type: 'change' };
var startEvent = { type: 'start' };
var endEvent = { type: 'end' };
this.rotateLeft = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta -= angle;
};
this.rotateUp = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta -= angle;
};
// pass in distance in world space to move left
this.panLeft = function ( distance ) {
var te = this.object.matrix.elements;
// get X column of matrix
panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
panOffset.multiplyScalar( - distance );
pan.add( panOffset );
};
// pass in distance in world space to move up
this.panUp = function ( distance ) {
var te = this.object.matrix.elements;
// get Y column of matrix
panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
panOffset.multiplyScalar( distance );
pan.add( panOffset );
};
// pass in x,y of change desired in pixel space,
// right and down are positive
this.pan = function ( deltaX, deltaY ) {
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( scope.object instanceof THREE.PerspectiveCamera ) {
// perspective
var position = scope.object.position;
var offset = position.clone().sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
// we actually don't use screenWidth, since perspective camera is fixed to screen height
scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
// orthographic
scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
} else {
// camera neither orthographic or perspective
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
}
};
this.dollyIn = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale /= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );
scope.object.updateProjectionMatrix();
scope.dispatchEvent( changeEvent );
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
this.dollyOut = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale *= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );
scope.object.updateProjectionMatrix();
scope.dispatchEvent( changeEvent );
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
this.update = function () {
var position = this.object.position;
offset.copy( position ).sub( this.target );
// rotate offset to "y-axis-is-up" space
offset.applyQuaternion( quat );
// angle from z-axis around y-axis
theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
if ( this.autoRotate && state === STATE.NONE ) {
this.rotateLeft( getAutoRotationAngle() );
}
theta += thetaDelta;
phi += phiDelta;
// restrict theta to be between desired limits
theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
// move target to panned location
this.target.add( pan );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
// rotate offset back to "camera-up-vector-is-up" space
offset.applyQuaternion( quatInverse );
position.copy( this.target ).add( offset );
this.object.lookAt( this.target );
thetaDelta = 0;
phiDelta = 0;
scale = 1;
pan.set( 0, 0, 0 );
// update condition is:
// min(camera displacement, camera rotation in radians)^2 > EPS
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
if ( lastPosition.distanceToSquared( this.object.position ) > EPS
|| 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
lastQuaternion.copy (this.object.quaternion );
}
};
this.reset = function () {
state = STATE.NONE;
this.target.copy( this.target0 );
this.object.position.copy( this.position0 );
this.object.zoom = this.zoom0;
this.object.updateProjectionMatrix();
this.dispatchEvent( changeEvent );
this.update();
};
this.getPolarAngle = function () {
return phi;
};
this.getAzimuthalAngle = function () {
return theta
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
if ( event.button === scope.mouseButtons.ORBIT ) {
if ( scope.noRotate === true ) return;
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.ZOOM ) {
if ( scope.noZoom === true ) return;
state = STATE.DOLLY;
dollyStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.PAN ) {
if ( scope.noPan === true ) return;
state = STATE.PAN;
panStart.set( event.clientX, event.clientY );
}
if ( state !== STATE.NONE ) {
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( startEvent );
}
}
function onMouseMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( state === STATE.ROTATE ) {
if ( scope.noRotate === true ) return;
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.DOLLY ) {
if ( scope.noZoom === true ) return;
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyIn();
} else if ( dollyDelta.y < 0 ) {
scope.dollyOut();
}
dollyStart.copy( dollyEnd );
} else if ( state === STATE.PAN ) {
if ( scope.noPan === true ) return;
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
}
if ( state !== STATE.NONE ) scope.update();
}
function onMouseUp( /* event */ ) {
if ( scope.enabled === false ) return;
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
function onMouseWheel( event ) {
if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return;
event.preventDefault();
event.stopPropagation();
var delta = 0;
if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail !== undefined ) { // Firefox
delta = - event.detail;
}
if ( delta > 0 ) {
scope.dollyOut();
} else if ( delta < 0 ) {
scope.dollyIn();
}
scope.update();
scope.dispatchEvent( startEvent );
scope.dispatchEvent( endEvent );
}
function onKeyDown( event ) {
if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
switch ( event.keyCode ) {
case scope.keys.UP:
scope.pan( 0, scope.keyPanSpeed );
scope.update();
break;
case scope.keys.BOTTOM:
scope.pan( 0, - scope.keyPanSpeed );
scope.update();
break;
case scope.keys.LEFT:
scope.pan( scope.keyPanSpeed, 0 );
scope.update();
break;
case scope.keys.RIGHT:
scope.pan( - scope.keyPanSpeed, 0 );
scope.update();
break;
}
}
function touchstart( event ) {
if ( scope.enabled === false ) return;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) return;
state = STATE.TOUCH_ROTATE;
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) return;
state = STATE.TOUCH_DOLLY;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyStart.set( 0, distance );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) return;
state = STATE.TOUCH_PAN;
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
default:
state = STATE.NONE;
}
if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
}
function touchmove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
event.stopPropagation();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) return;
if ( state !== STATE.TOUCH_ROTATE ) return;
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
scope.update();
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) return;
if ( state !== STATE.TOUCH_DOLLY ) return;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyEnd.set( 0, distance );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyOut();
} else if ( dollyDelta.y < 0 ) {
scope.dollyIn();
}
dollyStart.copy( dollyEnd );
scope.update();
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) return;
if ( state !== STATE.TOUCH_PAN ) return;
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
scope.update();
break;
default:
state = STATE.NONE;
}
}
function touchend( /* event */ ) {
if ( scope.enabled === false ) return;
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'touchstart', touchstart, false );
this.domElement.addEventListener( 'touchend', touchend, false );
this.domElement.addEventListener( 'touchmove', touchmove, false );
window.addEventListener( 'keydown', onKeyDown, false );
// force an update at start
this.update();
};
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;

6
js/three/stats.min.js vendored Normal file
View File

@@ -0,0 +1,6 @@
// stats.js - http://github.com/mrdoob/stats.js
var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats);

835
js/three/three.min.js vendored Normal file

File diff suppressed because one or more lines are too long