Some cleaning 😢

This commit is contained in:
Thomas FORGIONE
2015-11-13 10:36:54 +01:00
parent 59518eb702
commit 5e0a6c3121
113 changed files with 433 additions and 67 deletions
+12
View File
@@ -0,0 +1,12 @@
var fs = require('fs');
/**
* @namespace
*/
var geo = {};
if (typeof module === 'object') {
module.exports = geo;
}
+17
View File
@@ -0,0 +1,17 @@
OPT=--compilation_level SIMPLE_OPTIMIZATIONS
ifeq ($(TYPE),RELEASE)
CLOSURE=java -jar ../../utils/closure-compiler/closure-compiler.jar
else
CLOSURE=../../utils/simple-compiler/compiler.sh
endif
all: Geo
Geo:
$(CLOSURE) $(OPT) \
--js Geo.js \
--js Mesh.js \
--js MeshContainer.js \
--js MeshStreamer.js \
--js_output_file ../lib/geo.min.js
+504
View File
@@ -0,0 +1,504 @@
/**
* Reprensents a mesh
* @constructor
* @memberOf geo
*/
geo.Mesh = function() {
this.vertices = [];
this.faces = [];
this.texCoords = [];
this.normals = [];
this.faceIndex = 0;
this.material = null;
this.started = false;
this.finished = false;
};
/**
* Checks if there are normals in the mesh
* @returns {Boolean} true if there are normals in the mesh, false otherwise
*/
geo.Mesh.prototype.hasNormals = function() {
return this.normals.length > 0;
};
/**
* Checks if there are texture coordinates in the mesh
* @returns {Boolean} true if there are texture coordinates in the mesh, false otherwise
*/
geo.Mesh.prototype.hasTexCoords = function() {
return this.texCoords.length > 0;
};
/**
* Adds a vertex to a mesh
* @param {geo.Vertex|String} A Vertex object or its string representation
*/
geo.Mesh.prototype.addVertex = function(vertex) {
if (vertex instanceof geo.Vertex) {
this.vertices.push(vertex);
} else if (typeof vertex === 'string' || vertex instanceof String) {
this.vertices.push(new geo.Vertex(vertex));
} else {
console.error("Can only add vertex from geo.Vertex or string");
return;
}
return this.vertices[this.vertices.length - 1];
};
/**
* Adds a face to a mesh
* @param {geo.Face|String} A Face object or its string representation
*/
geo.Mesh.prototype.addFaces = function(face) {
var faces;
if (face instanceof geo.Face) {
this.faces.push(face);
} else if (typeof face === 'string' || face instanceof String) {
faces = parseFace(face);
this.faces = this.faces.concat(faces);
} else {
console.error("Can only add face from geo.Face or string");
return;
}
if (faces === undefined) {
return this.faces[this.faces.length - 1];
} else {
return faces;
}
};
/**
* Adds a texture coordinate to a mesh
* @param {geo.TexCoord|String} A TexCoord object or its string representation
*/
geo.Mesh.prototype.addTexCoord = function(texCoord) {
if (texCoord instanceof geo.TexCoord) {
this.texCoords.push(texCoord);
} else if (typeof texCoord === 'string' || texCoord instanceof String) {
this.texCoords.push(new geo.TexCoord(texCoord));
} else {
console.error("Can only add texCoord from geo.TexCoord or string");
return;
}
return this.texCoords[this.texCoords.length - 1];
};
/**
* Adds a normal to a mesh
* @param {geo.Normal|String} A Normal object or its string representation
*/
geo.Mesh.prototype.addNormal = function(normal) {
if (normal instanceof geo.Normal) {
this.normals.push(normal);
} else if (typeof normal === 'string' || normal instanceof String) {
this.normals.push(new geo.Normal(normal));
} else {
console.error("Can only add normal from geo.Normal of string");
return;
}
return this.normals[this.normals.length - 1];
};
geo.Mesh.prototype.isFinished = function() {
return this.faceIndex === this.faces.length;
};
/**
* Represent a 3D vertex
* @constructor
* @memberOf geo
*/
geo.Vertex = function() {
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
/**
* x coordinate of the vertex
* @type {Number}
*/
this.x = parseFloat(split[1]);
/**
* y coordinate of the vertex
* @type {Number}
*/
this.y = parseFloat(split[2]);
/**
* z coordinate of the vertex
* @type {Number}
*/
this.z = parseFloat(split[3]);
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Gives a list representation of the vertex
* @returns {Array} An array representing the vertex
*
* @example
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
* vertex.index = 5;
* console.log(vertex.toList()); // Prints ['v', 5, 3.5, 3.6, 3.7]
*/
geo.Vertex.prototype.toList = function() {
return ['v', this.index, this.x, this.y, this.z];
};
/**
* Gives a string representation of the vertex
* @returns {string} A string representing the vertex
*
* @example
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
* console.log(vertex.toString()); // Prints v 3.5 3.6 3.7
*/
geo.Vertex.prototype.toString = function() {
return 'v ' + this.x + ' ' + this.y + ' ' + this.z;
};
/**
* Represent a 3D normal
* @constructor
* @memberOf geo
* @augments geo.Vertex
*/
geo.Normal = function() {
geo.Vertex.apply(this, arguments);
};
geo.Normal.prototype = Object.create(geo.Vertex.prototype);
geo.Normal.prototype.constructor = geo.Normal;
/**
* Gives a list representation of the normal
* @returns {Array} An array representing the normal
*
* @example
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
* normal.index = 5;
* console.log(normal.toList()); // Prints ['vn', 5, 3.5, 3.6, 3.7]
*/
geo.Normal.prototype.toList = function() {
var superObject = geo.Vertex.prototype.toList.call(this);
superObject[0] = 'vn';
return superObject;
};
/**
* Gives a string representation of the normal
* @returns {string} A string representing the normal
*
* @example
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
* console.log(normal.toString()); // Prints vn 3.5 3.6 3.7
*/
geo.Normal.prototype.toString = function() {
var superObject = geo.Vertex.prototype.toString.call(this);
superObject.replace('v', 'vn');
return superObject;
};
/**
* Represent a texture coordinate element
* @constructor
* @memberOf geo
*/
geo.TexCoord = function() {
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
/**
* x coordinate of the texture
* @type {Number}
*/
this.x = parseFloat(split[1]);
/**
* y coordinate of the texture
* @type {Number}
*/
this.y = parseFloat(split[2]);
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Gives a list representation of the texture coordinate
* @returns {Array} An array representing the texture coordinate
*
* @example
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['vt', 5, 3.5, 3.6]
*/
geo.TexCoord.prototype.toList = function() {
return ['vt', this.index, this.x, this.y];
};
/**
* Gives a string representation of the texture coordinate
* @returns {string} A string representing the texture coordinate
*
* @example
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
* console.log(texCoord.toString()); // Prints vt 3.5 3.6
*/
geo.TexCoord.prototype.toString = function() {
return 'vt ' + this.x + ' ' + this.y;
};
/**
* Represents a face
* @constructor
* @memberOf geo
*/
geo.Face = function() {
var split;
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
if (arguments[0].indexOf('/') === -1) {
// No / : easy win : "f 1 2 3" or "f 1 2 3 4"
split = arguments[0].replace(/\s+/g, ' ').split(' ');
this.a = parseInt(split[1]) - 1;
this.b = parseInt(split[2]) - 1;
this.c = parseInt(split[3]) - 1;
} else {
// There might be textures coords
split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
// Split elements
var split1 = split[1].split('/');
var split2 = split[2].split('/');
var split3 = split[3].split('/');
var vIndex = 0;
var tIndex = 1;
var nIndex = 2;
/**
* index of the first vertex of the face
* @type {Number}
*/
this.a = parseInt(split1[vIndex]) - 1;
/**
* index of the second vertex of the face
* @type {Number}
*/
this.b = parseInt(split2[vIndex]) - 1;
/**
* index of the third vertex of the face
* @type {Number}
*/
this.c = parseInt(split3[vIndex]) - 1;
/**
* index of the texture coordinate of the first vertex of the face
* @type {Number}
*/
this.aTexture = parseInt(split1[tIndex]) - 1;
/**
* index of the texture coordinate of the second vertex of the face
* @type {Number}
*/
this.bTexture = parseInt(split2[tIndex]) - 1;
/**
* index of the texture coordinate of the third vertex of the face
* @type {Number}
*/
this.cTexture = parseInt(split3[tIndex]) - 1;
/**
* index of the normal of the first vertex of the face
* @type {Number}
*/
this.aNormal = parseInt(split1[nIndex]) - 1;
/**
* index of the normal of the second vertex of the face
* @type {Number}
*/
this.bNormal = parseInt(split2[nIndex]) - 1;
/**
* index of the normal of the third vertex of the face
* @type {Number}
*/
this.cNormal = parseInt(split3[nIndex]) - 1;
}
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Parse a face line and returns an array of faces
*
* @private
* @param {String} a string representing a face
* @returns {Face[]} a single 3-vertices face or two 3-vertices face if it was
* a 4-vertices face
*/
var parseFace = function(arg) {
var split = arg.trim().split(' ');
var ret = [];
// Face3
if (split.length >= 4) {
ret.push(new geo.Face(arg));
}
// Face3 == 2 * Face3
if (split.length >= 5) {
ret.push(new geo.Face(
[
split[0],
split[1],
split[3],
split[4]
].join(' ')
));
}
return ret;
};
/**
* Returns the max index of the vertices of the face
* @returns {Number} the max index of the vertices
*/
geo.Face.prototype.max = function() {
if (this.d !== undefined) {
return Math.max(this.a, this.b, this.c, this.d);
} else {
return Math.max(this.a, this.b, this.c);
}
};
/**
* Returns the max index of the texture coordinates of the face
* @returns {Number} the max index of the texture coordinates
*/
geo.Face.prototype.maxTexture = function() {
if (this.dTexture) {
return Math.max(this.aTexture, this.bTexture, this.cTexture, this.dTexture);
} else {
return Math.max(this.aTexture, this.bTexture, this.cTexture);
}
};
/**
* Gives a list representation of the face
* @returns {Array} An array representing the texture coordinate
* <ol start=0>
* <li>'f'</li>
* <li>the index of the face</li>
* <li>a list containing the indices of the vertex of the face</li>
* <li>a list containing the indices of the texture coordinates</li>
* <li>a list containing the indices of the normals</li>
* </ol>
*
* @example
* var face = new geo.Face('f 1/2/3 4/5/6 7/8/9');
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['f', 5, [1,4,7], [2,5,8], [3,6,9]]
*/
geo.Face.prototype.toList = function() {
var l = ['f', this.index, this.meshIndex,
[this.a, this.b, this.c ],
isNaN(this.aTexture) ? [] : [this.aTexture, this.bTexture, this.cTexture],
isNaN(this.aNormal ) ? [] : [this.aNormal, this.bNormal, this.cNormal ]
];
// if (this.d !== undefined)
// l.push(this.d);
// if (this.aTexture !== undefined) {
// l.push(this.aTexture);
// l.push(this.bTexture);
// l.push(this.cTexture);
// }
// if (this.dTexture !== undefined)
// l.push(this.dTexture);
return l;
};
/**
* Gives a string representation of the face
* @returns {string} A string representing the face
*
* @example
* var face = new geo.Face('f 3 5 6');
* console.log(face.toString()); // Prints f 3 5 6
*/
geo.Face.prototype.toString = function() {
return 'f ' + this.a + ' ' + this.b + ' ' + this.c + (this.d !== undefined ? ' ' + this.d : '');
};
/**
* Represents a material name
* @constructor
* @param {string} line the string representing the material
* @memberOf geo
*/
geo.Material = function() {
var split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
/**
* The name of the material
* @type {string}
*/
this.name = split[1];
};
/**
* Gives a string representation of the material
* @returns {string} obj representation of usemtl
*/
geo.Material.prototype.toString = function() {
return 'usemtl ' + this.name;
};
/**
* Gives a list representation of the material
* @returns {array} an array representing the material
* @example
* var material = new geo.Material('usemtl MyMaterial');
* console.log(material.toList()); // Logs ['u', 'MyMaterial']
*/
geo.Material.prototype.toList = function() {
return ['u', this.name];
};
+381
View File
@@ -0,0 +1,381 @@
var Log = require('../lib/NodeLog.js');
var L3D = require('../../static/js/l3d.min.js');
var THREE = require('three');
function clone(vec) {
return {x : vec.x, y : vec.y, z : vec.z};
}
function rotation(vec1, x, y, z) {
var cos = Math.cos(z);
var sin = Math.sin(z);
var newVec = {x:0, y:0, z:0};
oldVec = clone(vec1);
newVec.x = cos * oldVec.x - sin * oldVec.y;
newVec.y = sin * oldVec.x + cos * oldVec.y;
newVec.z = oldVec.z;
oldVec = clone(newVec);
cos = Math.cos(y);
sin = Math.sin(y);
newVec.x = cos * oldVec.x + sin * oldVec.z;
newVec.y = oldVec.y;
newVec.z = - sin * oldVec.x + cos * oldVec.z;
cos = Math.cos(x);
sin = Math.sin(x);
oldVec = clone(newVec);
newVec.x = oldVec.x;
newVec.y = oldVec.y * cos - oldVec.z * sin;
newVec.z = oldVec.y * sin + oldVec.z * cos;
return clone(newVec);
}
function applyTransformation(vector, transfo) {
var ret = rotation(vector, transfo.rotation.x, transfo.rotation.y, transfo.rotation.z);
var scale = transfo.scale || 1;
return {
x: (ret.x + transfo.translation.x) * scale,
y: (ret.y + transfo.translation.y) * scale,
z: (ret.z + transfo.translation.z) * scale
};
}
/**
* Represents a mesh. All meshes are loaded once in geo.availableMesh to avoid
* loading at each mesh request
* @constructor
* @memberOf geo
*/
geo.MeshContainer = function(path, transfo, callback) {
if (callback === undefined && typeof transfo === 'function') {
callback = transfo;
transfo = {translation: {x:0,y:0,z:0}, rotation: {x:0,y:0,z:0}};
}
if (transfo === undefined) {
transfo = {translation: {x:0,y:0,z:0}, rotation: {x:0,y:0,z:0}};
}
/**
* array of each part of the mesh
* @type {geo.Mesh[]}
*/
this.meshes = [];
/**
* array of the vertices of the meshes (all merged)
* @type {geo.Vertex[]}
*/
this.vertices = [];
/**
* array of the faces of the meshes (all merged)
* @type {geo.Face[]}
*/
this.faces = [];
/**
* array of the normals of the meshes (all merged)
* @type {geo.Normal[]}
*/
this.normals = [];
/**
* array of the texture coordinates (all merged)
* @type {geo.TexCoord[]}
*/
this.texCoords = [];
/**
* Number of elements to stream in the mesh
* @type {Number}
*/
this.numberOfFaces = 0;
this.transfo = transfo;
this.callback = callback;
if (path !== undefined) {
this.loadFromFile('../' + path);
}
};
/**
* Loads a obj file
* @param {string} path the path to the file
*/
geo.MeshContainer.prototype.loadFromFile = function(path) {
var self = this;
fs.readFile(path, {encoding: 'utf-8'}, function(err, data) {
var currentMesh;
// Get lines from file
var lines = data.toString('utf-8').split("\n");
// For each line
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
if (line[0] === 'v') {
if (line[1] === 't') {
// Texture coord
var texCoord = new geo.TexCoord(line);
texCoord.index = self.texCoords.length;
self.texCoords.push(texCoord);
} else if (line[1] === 'n') {
var normal = new geo.Normal(line);
normal.index = self.normals.length;
self.normals.push(normal);
} else {
// Just a simple vertex
var vertex = new geo.Vertex(line);
var vertexTransformed = applyTransformation(vertex, self.transfo);
vertex.x = vertexTransformed.x;
vertex.y = vertexTransformed.y;
vertex.z = vertexTransformed.z;
vertex.index = self.vertices.length;
self.vertices.push(vertex);
}
} else if (line[0] === 'f') {
self.numberOfFaces++;
// Create mesh if it doesn't exist
if (currentMesh === undefined) {
currentMesh = new geo.Mesh();
self.meshes.push(currentMesh);
}
// Create faces (two if Face4)
var faces = currentMesh.addFaces(line);
faces[0].index = self.faces.length;
faces[0].meshIndex = self.meshes.length - 1;
self.faces.push(faces[0]);
if (faces.length === 2) {
self.numberOfFaces++;
faces[1].index = self.faces.length;
faces[1].meshIndex = self.meshes.length - 1;
self.faces.push(faces[1]);
}
} else if (line[0] === 'u') {
// usemtl
// If a current mesh exists, finish it
// Create a new mesh
currentMesh = new geo.Mesh();
self.meshes.push(currentMesh);
currentMesh.material = (new geo.Material(line)).name;
// console.log(currentMesh.material);
}
}
if (typeof self.callback === 'function') {
self.callback();
}
});
};
function trySetLoaded() {
for (var name in availableMeshNames) {
if (availableMeshNames[name].done === false) {
return;
}
}
Log.ready("Meshes loaded in " + (Date.now() - start) + 'ms');
}
var availableMeshNames = {
'/static/data/castle/princess peaches castle (outside).obj': {
done: false,
recommendations : L3D.createPeachRecommendations(1134, 768)
},
'/static/data/mountain/coocoolmountain.obj': {
done: false,
recommendations : L3D.createMountainRecommendations(1134, 768)
},
'/static/data/mountain/coocoolmountain_sub.obj': {
done: false,
recommendations : L3D.createMountainRecommendations(1134, 768)
},
'/static/data/whomp/Whomps Fortress.obj': {
done: false,
transfo: {
rotation: {
x: -Math.PI / 2,
y: 0,
z: Math.PI / 2
},
translation: {
x: 0,
y: 0,
z: 0
},
scale: 0.1
},
recommendations : L3D.createWhompRecommendations(1134, 768)
},
'/static/data/whomp/Whomps Fortress_sub.obj': {
done: false,
transfo: {
rotation: {
x: -Math.PI / 2,
y: 0,
z: Math.PI / 2
},
translation: {
x: 0,
y: 0,
z: 0
},
scale: 0.1
},
recommendations : L3D.createWhompRecommendations(1134, 768)
},
'/static/data/bobomb/bobomb battlefeild.obj': {
done: false,
transfo: {
rotation: {
x: 0,
y: Math.PI - 0.27,
z: 0
},
translation: {
x: 0,
y: 0,
z: 0
}
},
recommendations : L3D.createBobombRecommendations(1134, 768)
},
'/static/data/bobomb/bobomb battlefeild_sub.obj': {
done: false,
transfo: {
rotation: {
x: 0,
y: Math.PI - 0.27,
z: 0
},
translation: {
x: 0,
y: 0,
z: 0
}
},
recommendations : L3D.createBobombRecommendations(1134, 768)
},
'/static/data/sponza/sponza.obj': {
done: false
}
};
for (var i = 1; i < 26; i++) {
availableMeshNames['/static/data/spheres/' + i + '.obj'] = { done: false};
}
geo.availableMeshes = {};
var start = Date.now();
function pushMesh(name) {
geo.availableMeshes[name] = new geo.MeshContainer(
name.substring(1, name.length),
availableMeshNames[name].transfo,
function() {
geo.availableMeshes[name].recommendations = [];
if (availableMeshNames[name].recommendations !== undefined) {
for (var i = 0; i < availableMeshNames[name].recommendations.length; i++) {
var reco = availableMeshNames[name].recommendations[i].camera;
reco.lookAt(reco.target);
reco.updateMatrix();
reco.updateProjectionMatrix();
reco.updateMatrixWorld();
reco.matrixWorldInverse.getInverse( reco.matrixWorld );
var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse);
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse));
geo.availableMeshes[name].recommendations.push({
position: reco.position,
frustum: frustum.planes
});
}
}
availableMeshNames[name].done = true;
trySetLoaded();
}
);
}
for (var name in availableMeshNames) {
pushMesh(name);
}
+553
View File
@@ -0,0 +1,553 @@
var THREE = require('three');
var L3D = require('../../static/js/l3d.min.js');
function isInFrustum(element, planes) {
if (element instanceof Array) {
var outcodes = [];
for (var i = 0; i < element.length; i++) {
var vertex = element[i];
var currentOutcode = "";
for (var j = 0; j < planes.length; j++) {
var plane = planes[j];
distance =
plane.normal.x * vertex.x +
plane.normal.y * vertex.y +
plane.normal.z * vertex.z +
plane.constant;
// if (distance < 0) {
// exitToContinue = true;
// break;
// }
currentOutcode += distance > 0 ? '0' : '1';
}
outcodes.push(parseInt(currentOutcode,2));
}
// http://vterrain.org/LOD/culling.html
// I have no idea what i'm doing
// http://i.kinja-img.com/gawker-media/image/upload/japbcvpavbzau9dbuaxf.jpg
// But it seems to work
// EDIT : Not, this should be ok http://www.cs.unc.edu/~blloyd/comp770/Lecture07.pdf
if ((outcodes[0] | outcodes[1] | outcodes[2]) === 0) {
return true;
} else if ((outcodes[0] & outcodes[1] & outcodes[2]) !== 0) {
return false;
} else {
// part of the triangle is inside the viewing volume
return true;
}
}
}
/**
* @private
*/
function bisect(items, x, lo, hi) {
var mid;
if (typeof(lo) == 'undefined') lo = 0;
if (typeof(hi) == 'undefined') hi = items.length;
while (lo < hi) {
mid = Math.floor((lo + hi) / 2);
if (x < items[mid]) hi = mid;
else lo = mid + 1;
}
return lo;
}
/**
* @private
*/
function insort(items, x) {
items.splice(bisect(items, x), 0, x);
}
/**
* @private
*/
function partialSort(items, k, comparator) {
var smallest = items.slice(0, k).sort(),
max = smallest[k-1];
for (var i = k, len = items.length; i < len; ++i) {
var item = items[i];
var cond = comparator === undefined ? item < max : comparator(item, max) < 0;
if (cond) {
insort(smallest, item);
smallest.length = k;
max = smallest[k-1];
}
}
return smallest;
}
/**
* A class that streams easily a mesh via socket.io
* @memberOf geo
* @constructor
* @param {string} path to the mesh
*/
geo.MeshStreamer = function(path) {
/**
* array of array telling if the jth face of the ith mesh has already been sent
*
* For each mesh, there is an object containing
* <ul>
* <li>`counter` : the number of faces currently sent</li>
* <li>`array` : an array boolean telling if the ith face has already been sent</li>
* </ul>
* @type {Object[]}
*/
this.meshFaces = [];
/**
* array of booleans telling if the ith vertex has already been sent
* @type {Boolean[]}
*/
this.vertices = [];
/**
* array of booleans telling if the ith face has already been sent
* @type {Boolean[]}
*/
this.faces = [];
/**
* array of booleans telling if the ith normal has already been sent
* @type {Boolean[]}
*/
this.normals = [];
/**
* array of booleans telling if the ith texCoord has already been sent
* @type {Boolean[]}
*/
this.texCoords = [];
/**
* Number of element to send by packet
* @type {Number}
*/
this.chunk = 1000;
if (path !== undefined) {
this.mesh = geo.availableMeshes[path];
}
};
geo.MeshStreamer.prototype.isBackFace = function(camera, face) {
var directionCamera = L3D.Tools.diff(camera.target, camera.position);
var v1 = L3D.Tools.diff(this.mesh.vertices[face.b], this.mesh.vertices[face.a]);
var v2 = L3D.Tools.diff(this.mesh.vertices[face.c], this.mesh.vertices[face.a]);
var normal = L3D.Tools.cross(v1, v2);
return L3D.Tools.dot(directionCamera, normal) > 0;
};
/**
* Compute a function that can compare two faces
* @param {Camera} camera a camera seeing or not face
* @returns {function} the function that compares two faces : the higher face is the most interesting for the camera
*/
geo.MeshStreamer.prototype.faceComparator = function(camera) {
var self = this;
var direction = {
x: camera.target.x - camera.position.x,
y: camera.target.y - camera.position.y,
z: camera.target.z - camera.position.z
};
var norm = Math.sqrt(direction.x * direction.x + direction.y * direction.y + direction.z * direction.z);
direction.x /= norm;
direction.y /= norm;
direction.z /= norm;
return function(face1, face2) {
var center1 = {
x: (self.mesh.vertices[face1.a].x + self.mesh.vertices[face1.b].x + self.mesh.vertices[face1.b].x) / 3,
y: (self.mesh.vertices[face1.a].y + self.mesh.vertices[face1.b].y + self.mesh.vertices[face1.b].y) / 3,
z: (self.mesh.vertices[face1.a].z + self.mesh.vertices[face1.b].z + self.mesh.vertices[face1.b].z) / 3
};
var dir1 = {
x: center1.x - camera.position.x,
y: center1.y - camera.position.y,
z: center1.z - camera.position.z
};
var norm1 = Math.sqrt(dir1.x * dir1.x + dir1.y * dir1.y + dir1.z + dir1.z);
dir1.x /= norm1;
dir1.y /= norm1;
dir1.z /= norm1;
var dot1 = direction.x * dir1.x + direction.y * dir1.y + direction.z * dir1.z;
var center2 = {
x: (self.mesh.vertices[face2.a].x + self.mesh.vertices[face2.b].x + self.mesh.vertices[face2.b].x) / 3,
y: (self.mesh.vertices[face2.a].y + self.mesh.vertices[face2.b].y + self.mesh.vertices[face2.b].y) / 3,
z: (self.mesh.vertices[face2.a].z + self.mesh.vertices[face2.b].z + self.mesh.vertices[face2.b].z) / 3
};
var dir2 = {
x: center2.x - camera.position.x,
y: center2.y - camera.position.y,
z: center2.z - camera.position.z
};
var norm2 = Math.sqrt(dir2.x * dir2.x + dir2.y * dir2.y + dir2.z + dir2.z);
dir2.x /= norm2;
dir2.y /= norm2;
dir2.z /= norm2;
var dot2 = direction.x * dir2.x + direction.y * dir2.y + direction.z * dir2.z;
// Decreasing order
if (dot1 > dot2) {
return -1;
}
if (dot1 < dot2) {
return 1;
}
return 0;
};
};
/**
* Initialize the socket.io callback
* @param {socket} socket the socket to initialize
*/
geo.MeshStreamer.prototype.start = function(socket) {
this.meshIndex = 0;
this.socket = socket;
var self = this;
socket.on('request', function(path, laggy) {
if (laggy === true) {
self.chunk = 1;
}
self.mesh = geo.availableMeshes[path];
if (self.mesh === undefined) {
process.stderr.write('Wrong path for model : ' + path);
socket.emit('refused');
socket.disconnect();
return;
}
self.meshFaces = new Array(self.mesh.meshes.length);
for (var i = 0; i < self.meshFaces.length; i++) {
self.meshFaces[i] = {
counter: 0,
array: new Array(self.mesh.meshes[i].faces.length)
};
}
socket.emit('ok');
});
socket.on('materials', function() {
var data = self.nextMaterials();
socket.emit('elements', data);
});
socket.on('next', function(camera) {
// Send next elements
var next = self.nextElements(camera);
if (next.data.length === 0) {
// If nothing, just serve stuff
var tmp = self.nextElements(camera, true);
next.data = tmp.data;
}
socket.emit('elements', next.data);
if (next.finished) {
socket.disconnect();
}
});
};
/**
* Prepare the array of materials
* @return array the array to send with all materials of the current mesh
*/
geo.MeshStreamer.prototype.nextMaterials = function() {
var data = [];
data.push(['g', this.mesh.numberOfFaces]);
for (var i = 0; i < this.mesh.meshes.length; i++) {
var currentMesh = this.mesh.meshes[i];
// Send usemtl
data.push([
'u',
currentMesh.material,
currentMesh.vertices.length,
currentMesh.faces.length,
this.mesh.texCoords.length > 0,
this.mesh.normals.length > 0
]);
}
return data;
};
/**
* Prepare the next elements
* @param {camera} _camera a camera that can be usefull to do smart streaming (stream
* only interesting parts according to the camera
* @returns {array} an array of elements ready to send
*/
geo.MeshStreamer.prototype.nextElements = function(_camera, force) {
var i;
if (force === undefined) {
force = false;
}
// Prepare camera (and scale to model)
var camera = null;
var planes = [];
var direction;
if (_camera !== null) {
camera = {
position: {
x: _camera[0][0],
y: _camera[0][1],
z: _camera[0][2]
},
target: {
x: _camera[1][0],
y: _camera[1][1],
z: _camera[1][2]
}
};
for (i = 2; i < _camera.length; i++) {
planes.push({
normal: {
x: _camera[i][0],
y: _camera[i][1],
z: _camera[i][2]
},
constant: _camera[i][3]
});
}
// Compute camera direction
direction = {
x: camera.target.x - camera.position.x,
y: camera.target.y - camera.position.y,
z: camera.target.z - camera.position.z
};
}
var sent = 0;
var data = [];
var mightBeCompletetlyFinished = true;
// BOOM
// if (camera != null)
// this.mesh.faces.sort(this.faceComparator(camera));
for (var faceIndex = 0; faceIndex < this.mesh.faces.length; faceIndex++) {
var currentFace = this.mesh.faces[faceIndex];
if (this.faces[currentFace.index] === true) {
continue;
}
mightBeCompletetlyFinished = false;
var vertex1 = this.mesh.vertices[currentFace.a];
var vertex2 = this.mesh.vertices[currentFace.b];
var vertex3 = this.mesh.vertices[currentFace.c];
if (!force && camera !== null) {
var display = false;
var exitToContinue = false;
threeVertices = [vertex1, vertex2, vertex3];
// Frustum culling
if (!isInFrustum(threeVertices, planes)) {
continue;
}
// Backface culling
if (this.isBackFace(camera, currentFace)) {
continue;
}
}
if (!this.vertices[currentFace.a]) {
data.push(vertex1.toList());
this.vertices[currentFace.a] = true;
sent++;
}
if (!this.vertices[currentFace.b]) {
data.push(vertex2.toList());
this.vertices[currentFace.b] = true;
sent++;
}
if (!this.vertices[currentFace.c]) {
data.push(vertex3.toList());
this.vertices[currentFace.c] = true;
sent++;
}
var normal1 = this.mesh.normals[currentFace.aNormal];
var normal2 = this.mesh.normals[currentFace.bNormal];
var normal3 = this.mesh.normals[currentFace.cNormal];
if (normal1 !== undefined && !this.normals[currentFace.aNormal]) {
data.push(normal1.toList());
this.normals[currentFace.aNormal] = true;
sent++;
}
if (normal2 !== undefined && !this.normals[currentFace.bNormal]) {
data.push(normal2.toList());
this.normals[currentFace.bNormal] = true;
sent++;
}
if (normal3 !== undefined && !this.normals[currentFace.cNormal]) {
data.push(normal3.toList());
this.normals[currentFace.cNormal] = true;
sent++;
}
var tex1 = this.mesh.texCoords[currentFace.aTexture];
var tex2 = this.mesh.texCoords[currentFace.bTexture];
var tex3 = this.mesh.texCoords[currentFace.cTexture];
if (tex1 !== undefined && !this.texCoords[currentFace.aTexture]) {
data.push(tex1.toList());
this.texCoords[currentFace.aTexture] = true;
sent++;
}
if (tex2 !== undefined && !this.texCoords[currentFace.bTexture]) {
data.push(tex2.toList());
this.texCoords[currentFace.bTexture] = true;
sent++;
}
if (tex3 !== undefined && !this.texCoords[currentFace.cTexture]) {
data.push(tex3.toList());
this.texCoords[currentFace.cTexture] = true;
sent++;
}
data.push(currentFace.toList());
// this.meshFaces[meshIndex] = this.meshFaces[meshIndex] || [];
this.faces[currentFace.index] = true;
// this.meshFaces[meshIndex].counter++;
// currentMesh.faceIndex++;
sent++;
if (sent > this.chunk) {
return {data: data, finished: false};
}
}
return {data: data, finished: mightBeCompletetlyFinished};
};
geo.MeshStreamer.prototype.isFinished = function(i) {
return this.meshFaces[i].counter === this.meshFaces[i].array.length;
};
+1
View File
@@ -0,0 +1 @@
[[0,0.07894736842105263,0.18421052631578946,0,0.02631578947368421,0.02631578947368421,0,0.02631578947368421,0,0.13157894736842105,0.2894736842105263,0.2631578947368421],[0,0,0.10526315789473684,0.15789473684210525,0.18421052631578946,0.02631578947368421,0,0.07894736842105263,0.02631578947368421,0.05263157894736842,0.05263157894736842,0.05263157894736842],[0,0.02631578947368421,0,0.5,0.02631578947368421,0.02631578947368421,0.02631578947368421,0.07894736842105263,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.05263157894736842],[0,0.05263157894736842,0.07894736842105263,0,0.4473684210526316,0.02631578947368421,0.13157894736842105,0.02631578947368421,0,0.07894736842105263,0,0.13157894736842105],[0,0,0.02631578947368421,0.15789473684210525,0,0.3157894736842105,0.21052631578947367,0.05263157894736842,0,0.07894736842105263,0,0.10526315789473684],[0,0.10526315789473684,0,0.05263157894736842,0.13157894736842105,0,0.13157894736842105,0.05263157894736842,0.15789473684210525,0.02631578947368421,0.02631578947368421,0.02631578947368421],[0,0.15789473684210525,0.10526315789473684,0,0,0.10526315789473684,0,0.05263157894736842,0.21052631578947367,0.13157894736842105,0,0],[0,0.07894736842105263,0.05263157894736842,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.10526315789473684,0,0.07894736842105263,0.02631578947368421,0.02631578947368421,0.05263157894736842],[0,0,0.10526315789473684,0.02631578947368421,0.02631578947368421,0.18421052631578946,0.15789473684210525,0,0,0.21052631578947367,0.07894736842105263,0.07894736842105263],[0,0.07894736842105263,0.10526315789473684,0.02631578947368421,0,0,0.07894736842105263,0.15789473684210525,0.13157894736842105,0,0.21052631578947367,0.07894736842105263],[0,0.02631578947368421,0.10526315789473684,0.07894736842105263,0.05263157894736842,0.02631578947368421,0,0.02631578947368421,0.23684210526315788,0.07894736842105263,0,0.10526315789473684],[0,0.18421052631578946,0.13157894736842105,0.13157894736842105,0.10526315789473684,0.02631578947368421,0,0.13157894736842105,0.02631578947368421,0.05263157894736842,0.07894736842105263,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0,602,0,0,0,0,0,0,151,191,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1116,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,87,0,0,0,0,0,0,0,0,0,82],[0,0,0,0,0,0,0,0,195,0,0,0],[0,86,41,0,0,0,0,0,0,563,74,72],[0,0,59,0,0,0,0,0,0,0,0,49],[0,147,151,0,0,0,0,0,0,0,0,110],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0.03125,0.09375,0.5,0.21875,0.03125,0.09375,0.1875,0,0.125,0.15625,0],[0,0,0.15625,0.0625,0.21875,0.0625,0.15625,0.09375,0,0.0625,0.03125,0],[0,0.21875,0,0.0625,0.0625,0,0,0,0,0,0.03125,0.0625],[0,0.09375,0.0625,0,0.25,0.03125,0.1875,0.1875,0.03125,0.25,0,0.03125],[0,0.125,0.0625,0.125,0,0.03125,0,0,0.1875,0.09375,0.15625,0.0625],[0,0.03125,0,0,0,0,0.21875,0,0.25,0,0,0.1875],[0,0.03125,0.0625,0.0625,0.03125,0.34375,0,0.125,0.34375,0,0.40625,0.0625],[0,0.125,0,0.15625,0,0.0625,0.25,0,0.03125,0.09375,0,0],[0,0.125,0.03125,0.0625,0,0.1875,0.15625,0.03125,0,0.0625,0,0.25],[0,0.1875,0,0.125,0.125,0,0.0625,0.03125,0,0,0.03125,0.125],[0,0.0625,0.0625,0.03125,0.09375,0,0.46875,0.09375,0.03125,0.09375,0,0.1875],[0,0,0.0625,0.0625,0,0,0,0.03125,0.1875,0.125,0.46875,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0,0,218,0,0,0,0,0,0,0,0],[0,0,0,106,36,0,0,182,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,3,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,72],[0,0,0,0,0,0,0,0,0,0,0,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0.05555555555555555,0.08333333333333333,0,0.16666666666666666,0.027777777777777776,0.5,0,0.05555555555555555,0.027777777777777776,0],[0,0,0.05555555555555555,0.08333333333333333,0.08333333333333333,0,0.08333333333333333,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0,0.1111111111111111,0.027777777777777776,0,0.027777777777777776,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0.027777777777777776,0,0.1111111111111111,0,0.027777777777777776,0.027777777777777776,0.08333333333333333,0.027777777777777776,0],[0,0.08333333333333333,0,0.1111111111111111,0,0.3888888888888889,0,0.16666666666666666,0.05555555555555555,0.027777777777777776,0.05555555555555555],[0,0,0,0.027777777777777776,0.25,0,0.1111111111111111,0.1388888888888889,0,0,0.2222222222222222],[0,0.05555555555555555,0.08333333333333333,0.1388888888888889,0,0.027777777777777776,0,0.027777777777777776,0.08333333333333333,0.16666666666666666,0.3055555555555556],[0,0.027777777777777776,0.027777777777777776,0,0.027777777777777776,0.1388888888888889,0.05555555555555555,0,0.08333333333333333,0.05555555555555555,0.027777777777777776],[0,0,0,0,0.08333333333333333,0.05555555555555555,0.1111111111111111,0.05555555555555555,0,0.1111111111111111,0.1111111111111111],[0,0.027777777777777776,0.027777777777777776,0.027777777777777776,0.16666666666666666,0,0.05555555555555555,0.027777777777777776,0.1388888888888889,0,0],[0,0,0.027777777777777776,0,0.1388888888888889,0.16666666666666666,0.1111111111111111,0.08333333333333333,0.1111111111111111,0,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0,0,0,0,0,70,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,12,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,10,0,0,0,0,0,0,0],[0,0,0,0,0,83,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,64],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,36,0,0,0,16,0,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0.1,0.3,0,0,0,0,0,0,0.1,0.4,0.5],[0,0,0.1,0.2,0.2,0,0,0.2,0,0.1,0.1,0],[0,0.1,0,0.4,0,0,0.1,0.3,0.1,0.1,0.1,0],[0,0.1,0,0,0.4,0.1,0.2,0,0,0.1,0,0.2],[0,0,0,0.2,0,0.5,0.1,0,0,0.1,0,0],[0,0,0,0,0.3,0,0.1,0,0.3,0.1,0.1,0.1],[0,0.3,0.1,0,0,0,0,0.1,0.4,0.1,0,0],[0,0.1,0.1,0,0.1,0,0.4,0,0,0,0.1,0.2],[0,0,0.3,0,0,0.3,0.1,0,0,0.3,0.1,0],[0,0.1,0.1,0,0,0,0.1,0.4,0,0,0.2,0.1],[0,0,0.2,0.2,0.1,0.1,0,0.1,0.3,0,0,0],[0,0.2,0.2,0.3,0,0,0,0.1,0,0.1,0.1,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0,0.1,0.5,0.3,0,0.1,0.1,0,0.2,0,0],[0,0,0.2,0.1,0.1,0,0.3,0.2,0,0.2,0,0],[0,0.2,0,0.1,0.2,0,0,0,0,0,0,0.1],[0,0.1,0.1,0,0.4,0,0,0.2,0,0.3,0,0],[0,0.2,0,0,0,0.1,0,0,0.4,0.1,0.2,0.1],[0,0.1,0,0,0,0,0.1,0,0.4,0,0,0.2],[0,0.1,0,0,0.1,0.4,0,0.1,0.1,0,0.3,0.1],[0,0,0,0.3,0,0.1,0.2,0,0,0,0,0],[0,0.2,0.1,0.1,0,0.2,0.2,0,0,0,0,0.2],[0,0.3,0,0.1,0.1,0,0.1,0,0,0,0.1,0],[0,0.1,0.1,0,0,0,0.3,0.1,0,0.1,0,0.2],[0,0,0.1,0.1,0,0,0,0,0.1,0,0.5,0]]
+1
View File
@@ -0,0 +1 @@
[[0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0.5,0,0,0,0],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0,0,0],[0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0.16666666666666666,0],[0,0,0,0.3333333333333333,0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0],[0,0,0,0.16666666666666666,0.5,0,0,0,0,0,0.3333333333333333],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0,0,0.5],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0,0.16666666666666666,0,0],[0,0,0,0,0,0.16666666666666666,0.16666666666666666,0,0,0.5,0.16666666666666666],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0,0,0.3333333333333333,0,0],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0.3333333333333333,0.16666666666666666,0,0]]