Avoid multiple loading of same mesh (long operation)

This commit is contained in:
Thomas FORGIONE 2015-06-29 09:50:26 +02:00
parent 412f413e96
commit 09f6c2028f
2 changed files with 218 additions and 164 deletions

169
geo/MeshContainer.js Normal file
View File

@ -0,0 +1,169 @@
var fs = require('fs');
var mesh = require('./Mesh.js');
/**
* @namespace
*/
var cont = {};
/**
* Represents a mesh. All meshes are loaded once in cont.availableMesh to avoid
* loading at each mesh request
* @constructor
* @memberOf cont
*/
cont.MeshContainer = function(path) {
/**
* array of each part of the mesh
* @type {mesh.Mesh[]}
*/
this.meshes = [];
/**
* array of the vertices of the meshes (all merged)
* @type {mesh.Vertex[]}
*/
this.vertices = [];
/**
* array of the faces of the meshes (all merged)
* @type {mesh.Face[]}
*/
this.faces = [];
/**
* array of the normals of the meshes (all merged)
* @type {mesh.Normal[]}
*/
this.normals = [];
/**
* array of the texture coordinates (all merged)
* @type {mesh.TexCoord[]}
*/
this.texCoords = [];
if (path !== undefined) {
this.loadFromFile(path);
}
}
/**
* Loads a obj file
* @param {string} path the path to the file
*/
cont.MeshContainer.prototype.loadFromFile = function(path) {
var self = this;
var data = fs.readFileSync(path, {encoding: 'utf-8'});
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 mesh.TexCoord(line);
texCoord.index = self.texCoords.length;
self.texCoords.push(texCoord);
} else if (line[1] === 'n') {
var normal = new mesh.Normal(line);
normal.index = self.normals.length;
self.normals.push(normal);
} else {
// Just a simple vertex
// if (currentMesh === undefined) {
// // Chances are that we won't use any material in this case
// currentMesh = new mesh.Mesh();
// self.meshes.push(currentMesh);
// }
var vertex = new mesh.Vertex(line);
vertex.index = self.vertices.length;
self.vertices.push(vertex);
}
} else if (line[0] === 'f') {
// Create mesh if it doesn't exist
if (currentMesh === undefined) {
currentMesh = new mesh.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) {
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 mesh.Mesh();
self.meshes.push(currentMesh);
currentMesh.material = (new mesh.Material(line)).name;
// console.log(currentMesh.material);
}
}
}
var availableMeshNames = [
'/static/data/castle/princess peaches castle (outside).obj',
'/static/data/mountain/coocoolmountain.obj',
'/static/data/whomp/Whomps Fortress.obj',
'/static/data/bobomb/bobomb battlefeild.obj',
'/static/data/sponza/sponza.obj'
];
for (var i = 1; i < 26; i++) {
availableMeshNames.push('/static/data/spheres/' + i + '.obj');
}
cont.availableMeshes = {};
for (var i = 0; i < availableMeshNames.length; i++) {
var name = availableMeshNames[i];
cont.availableMeshes[name] = new cont.MeshContainer(name.substring(1, name.length));
}
module.exports = cont;

View File

@ -1,5 +1,6 @@
var fs = require('fs'); var fs = require('fs');
var mesh = require('./Mesh.js'); var mesh = require('./Mesh.js');
var cont = require('./MeshContainer.js');
/** /**
* @namespace * @namespace
@ -52,45 +53,33 @@ function partialSort(items, k, comparator) {
* @memberOf geo * @memberOf geo
* @constructor * @constructor
* @param {string} path to the mesh * @param {string} path to the mesh
* @param {function} callback to execute when the mesh streamer is loaded
*/ */
geo.MeshStreamer = function(path, callback) { geo.MeshStreamer = function(path) {
/**
* array of each part of the mesh
* @type {mesh.Mesh[]}
*/
this.meshes = [];
/** /**
* array of the vertices of the meshes (all merged) * array of booleans telling if the ith vertex has already been sent
* @type {mesh.Vertex[]} * @type {Boolean[]}
*/ */
this.vertices = []; this.vertices = [];
/** /**
* array of the faces of the meshes (all merged) * array of booleans telling if the ith face has already been sent
* @type {mesh.Face[]} * @type {Boolean[]}
*/ */
this.faces = []; this.faces = [];
/** /**
* array of the normals of the meshes (all merged) * array of booleans telling if the ith normal has already been sent
* @type {mesh.Normal[]} * @type {Boolean[]}
*/ */
this.normals = []; this.normals = [];
/** /**
* array of the texture coordinates (all merged) * array of booleans telling if the ith texCoord has already been sent
* @type {mesh.TexCoord[]} * @type {Boolean[]}
*/ */
this.texCoords = []; this.texCoords = [];
/**
* array of the faces in a nice order for sending
* @type {mesh.Face[]}
*/
this.orderedFaces = [];
/** /**
* Number of element to send by packet * Number of element to send by packet
* @type {Number} * @type {Number}
@ -98,13 +87,11 @@ geo.MeshStreamer = function(path, callback) {
this.chunk = 1000; this.chunk = 1000;
if (path !== undefined) { if (path !== undefined) {
var self = this;
this.loadFromFile(path, function() {
if (typeof callback === 'function')
callback();
}); this.mesh = cont.availableMeshes[path];
} }
} }
/** /**
@ -183,108 +170,6 @@ geo.MeshStreamer.prototype.faceComparator = function(camera) {
} }
} }
/**
* Loads a obj file
* @param {string} path the path to the file
* @param {function} callback the callback to call when the mesh is loaded
*/
geo.MeshStreamer.prototype.loadFromFile = function(path, callback) {
var self = this;
fs.readFile(path, function(err, data) {
var oldTime = Date.now();
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 mesh.TexCoord(line);
texCoord.index = self.texCoords.length;
self.texCoords.push(texCoord);
} else if (line[1] === 'n') {
var normal = new mesh.Normal(line);
normal.index = self.normals.length;
self.normals.push(normal);
} else {
// Just a simple vertex
// if (currentMesh === undefined) {
// // Chances are that we won't use any material in this case
// currentMesh = new mesh.Mesh();
// self.meshes.push(currentMesh);
// }
var vertex = new mesh.Vertex(line);
vertex.index = self.vertices.length;
self.vertices.push(vertex);
}
} else if (line[0] === 'f') {
// Create mesh if it doesn't exist
if (currentMesh === undefined) {
currentMesh = new mesh.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]);
self.orderedFaces.push(faces[0]);
if (faces.length === 2) {
faces[1].index = self.faces.length;
faces[1].meshIndex = self.meshes.length - 1;
self.faces.push(faces[1]);
self.orderedFaces.push(faces[1]);
}
} else if (line[0] === 'u') {
// usemtl
// If a current mesh exists, finish it
// Create a new mesh
currentMesh = new mesh.Mesh();
self.meshes.push(currentMesh);
currentMesh.material = (new mesh.Material(line)).name;
// console.log(currentMesh.material);
}
}
if (typeof callback === 'function') {
callback();
}
console.log(Date.now() - oldTime);
});
}
/** /**
* Initialize the socket.io callback * Initialize the socket.io callback
* @param {socket} socket the socket to initialize * @param {socket} socket the socket to initialize
@ -299,6 +184,8 @@ geo.MeshStreamer.prototype.start = function(socket) {
socket.on('request', function(path) { socket.on('request', function(path) {
console.log('Asking for ' + path); console.log('Asking for ' + path);
self.mesh = cont.availableMeshes[path];
var regex = /.*\.\..*/; var regex = /.*\.\..*/;
var filePath = path.substring(1, path.length); var filePath = path.substring(1, path.length);
@ -308,9 +195,7 @@ geo.MeshStreamer.prototype.start = function(socket) {
return; return;
} }
self.loadFromFile(filePath, function() {
socket.emit('ok'); socket.emit('ok');
});
}); });
@ -355,9 +240,9 @@ geo.MeshStreamer.prototype.nextMaterials = function() {
var data = []; var data = [];
for (var i = 0; i < this.meshes.length; i++) { for (var i = 0; i < this.mesh.meshes.length; i++) {
var currentMesh = this.meshes[i]; var currentMesh = this.mesh.meshes[i];
// Send usemtl // Send usemtl
data.push([ data.push([
@ -365,8 +250,8 @@ geo.MeshStreamer.prototype.nextMaterials = function() {
currentMesh.material, currentMesh.material,
currentMesh.vertices.length, currentMesh.vertices.length,
currentMesh.faces.length, currentMesh.faces.length,
this.texCoords.length > 0, this.mesh.texCoords.length > 0,
this.normals.length > 0 this.mesh.normals.length > 0
]); ]);
} }
@ -437,9 +322,9 @@ geo.MeshStreamer.prototype.nextElements = function(_camera, force) {
// Sort faces // Sort faces
var mightBeCompletetlyFinished = true; var mightBeCompletetlyFinished = true;
for (var meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) { for (var meshIndex = 0; meshIndex < this.mesh.meshes.length; meshIndex++) {
var currentMesh = this.meshes[meshIndex]; var currentMesh = this.mesh.meshes[meshIndex];
if (currentMesh.isFinished()) { if (currentMesh.isFinished()) {
@ -461,9 +346,9 @@ geo.MeshStreamer.prototype.nextElements = function(_camera, force) {
} }
var vertex1 = this.vertices[currentFace.a]; var vertex1 = this.mesh.vertices[currentFace.a];
var vertex2 = this.vertices[currentFace.b]; var vertex2 = this.mesh.vertices[currentFace.b];
var vertex3 = this.vertices[currentFace.c]; var vertex3 = this.mesh.vertices[currentFace.c];
// if (camera !== null) { // if (camera !== null) {
@ -534,82 +419,82 @@ geo.MeshStreamer.prototype.nextElements = function(_camera, force) {
} }
if (!vertex1.sent) { if (!this.vertices[currentFace.a]) {
data.push(vertex1.toList()); data.push(vertex1.toList());
vertex1.sent = true; this.vertices[currentFace.a] = true;
sent++; sent++;
} }
if (!vertex2.sent) { if (!this.vertices[currentFace.b]) {
data.push(vertex2.toList()); data.push(vertex2.toList());
vertex2.sent = true; this.vertices[currentFace.b] = true;
sent++; sent++;
} }
if (!vertex3.sent) { if (!this.vertices[currentFace.c]) {
data.push(vertex3.toList()); data.push(vertex3.toList());
vertex3.sent = true; this.vertices[currentFace.c] = true;
sent++; sent++;
} }
var normal1 = this.normals[currentFace.aNormal]; var normal1 = this.mesh.normals[currentFace.aNormal];
var normal2 = this.normals[currentFace.bNormal]; var normal2 = this.mesh.normals[currentFace.bNormal];
var normal3 = this.normals[currentFace.cNormal]; var normal3 = this.mesh.normals[currentFace.cNormal];
if (normal1 !== undefined && !normal1.sent) { if (normal1 !== undefined && !this.normals[currentFace.aNormal]) {
data.push(normal1.toList()); data.push(normal1.toList());
normal1.sent = true; this.normals[currentFace.aNormal] = true;
sent++; sent++;
} }
if (normal2 !== undefined && !normal2.sent) { if (normal2 !== undefined && !this.normals[currentFace.bNormal]) {
data.push(normal2.toList()); data.push(normal2.toList());
normal2.sent = true; this.normals[currentFace.bNormal] = true;
sent++; sent++;
} }
if (normal3 !== undefined && !normal3.sent) { if (normal3 !== undefined && !this.normals[currentFace.cNormal]) {
data.push(normal3.toList()); data.push(normal3.toList());
normal3.sent = true; this.normals[currentFace.cNormal] = true;
sent++; sent++;
} }
var tex1 = this.texCoords[currentFace.aTexture]; var tex1 = this.mesh.texCoords[currentFace.aTexture];
var tex2 = this.texCoords[currentFace.bTexture]; var tex2 = this.mesh.texCoords[currentFace.bTexture];
var tex3 = this.texCoords[currentFace.cTexture]; var tex3 = this.mesh.texCoords[currentFace.cTexture];
if (tex1 !== undefined && !tex1.sent) { if (tex1 !== undefined && !this.texCoords[currentFace.aTexture]) {
data.push(tex1.toList()); data.push(tex1.toList());
tex1.sent = true; this.texCoords[currentFace.aTexture] = true;
sent++; sent++;
} }
if (tex2 !== undefined && !tex2.sent) { if (tex2 !== undefined && !this.texCoords[currentFace.bTexture]) {
data.push(tex2.toList()); data.push(tex2.toList());
tex2.sent = true; this.texCoords[currentFace.bTexture] = true;
sent++; sent++;
} }
if (tex3 !== undefined && !tex3.sent) { if (tex3 !== undefined && !this.texCoords[currentFace.cTexture]) {
data.push(tex3.toList()); data.push(tex3.toList());
tex3.sent = true; this.texCoords[currentFace.cTexture] = true;
sent++; sent++;
} }