Loads of documentation, and improved dev utils
This commit is contained in:
parent
fa1636ac8e
commit
97558ab600
|
@ -2,6 +2,7 @@ var fs = require('fs');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @namespace
|
* @namespace
|
||||||
|
* @description Contains all functions and classes relative to meshes and streaming (server-side)
|
||||||
*/
|
*/
|
||||||
var geo = {};
|
var geo = {};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,12 @@ all: Geo
|
||||||
Geo:
|
Geo:
|
||||||
$(CLOSURE) $(OPT) \
|
$(CLOSURE) $(OPT) \
|
||||||
--js Geo.js \
|
--js Geo.js \
|
||||||
|
--js ConfigGenerators/ConfigGenerator.js \
|
||||||
|
--js ConfigGenerators/NV_PN.js \
|
||||||
|
--js ConfigGenerators/V_PP.js \
|
||||||
|
--js ConfigGenerators/V_PD.js \
|
||||||
|
--js ConfigGenerators/V_PP_PD.js \
|
||||||
|
--js ConfigGenerators/ConfigGeneratorEnd.js \
|
||||||
--js Mesh.js \
|
--js Mesh.js \
|
||||||
--js MeshContainer.js \
|
--js MeshContainer.js \
|
||||||
--js MeshStreamer.js \
|
--js MeshStreamer.js \
|
||||||
|
|
|
@ -1,16 +1,53 @@
|
||||||
/**
|
/**
|
||||||
* Reprensents a mesh
|
* Reprensents an elementary mesh (only one material)
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
*/
|
*/
|
||||||
geo.Mesh = function() {
|
geo.Mesh = function() {
|
||||||
|
/**
|
||||||
|
* @type {geo.Vertex[]}
|
||||||
|
* @description All the vertices of the mesh
|
||||||
|
* @deprecated Prefer the use of {@link geo.MeshContainer}.vertices
|
||||||
|
*/
|
||||||
this.vertices = [];
|
this.vertices = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {geo.Face[]}
|
||||||
|
* @description All the faces of the mesh
|
||||||
|
*/
|
||||||
this.faces = [];
|
this.faces = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {geo.TexCoord[]}
|
||||||
|
* @description All the textures coordinates of the mesh
|
||||||
|
*/
|
||||||
this.texCoords = [];
|
this.texCoords = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {geo.Normal[]}
|
||||||
|
* @description All the normals of the mesh
|
||||||
|
*/
|
||||||
this.normals = [];
|
this.normals = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated You should use your own counter
|
||||||
|
*/
|
||||||
this.faceIndex = 0;
|
this.faceIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {String}
|
||||||
|
* @description Name of the material of the current mesh
|
||||||
|
*/
|
||||||
this.material = null;
|
this.material = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated You should use your own attributes
|
||||||
|
*/
|
||||||
this.started = false;
|
this.started = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated You should use your own attributes
|
||||||
|
*/
|
||||||
this.finished = false;
|
this.finished = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,7 +95,7 @@ geo.Mesh.prototype.addFaces = function(face) {
|
||||||
if (face instanceof geo.Face) {
|
if (face instanceof geo.Face) {
|
||||||
this.faces.push(face);
|
this.faces.push(face);
|
||||||
} else if (typeof face === 'string' || face instanceof String) {
|
} else if (typeof face === 'string' || face instanceof String) {
|
||||||
faces = parseFace(face);
|
faces = geo.parseFace(face);
|
||||||
this.faces = this.faces.concat(faces);
|
this.faces = this.faces.concat(faces);
|
||||||
} else {
|
} else {
|
||||||
console.error("Can only add face from geo.Face or string");
|
console.error("Can only add face from geo.Face or string");
|
||||||
|
@ -106,6 +143,9 @@ geo.Mesh.prototype.addNormal = function(normal) {
|
||||||
return this.normals[this.normals.length - 1];
|
return this.normals[this.normals.length - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
geo.Mesh.prototype.isFinished = function() {
|
geo.Mesh.prototype.isFinished = function() {
|
||||||
return this.faceIndex === this.faces.length;
|
return this.faceIndex === this.faces.length;
|
||||||
};
|
};
|
||||||
|
@ -113,6 +153,7 @@ geo.Mesh.prototype.isFinished = function() {
|
||||||
/**
|
/**
|
||||||
* Represent a 3D vertex
|
* Represent a 3D vertex
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @param {String} A string like in the .obj file (e.g. 'v 1.1 0.2 3.4')
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
*/
|
*/
|
||||||
geo.Vertex = function() {
|
geo.Vertex = function() {
|
||||||
|
@ -175,6 +216,7 @@ geo.Vertex.prototype.toString = function() {
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
* @augments geo.Vertex
|
* @augments geo.Vertex
|
||||||
|
* @param {String} A string like in the .obj file (e.g. 'vn 1.1 2.2 3.3')
|
||||||
*/
|
*/
|
||||||
geo.Normal = function() {
|
geo.Normal = function() {
|
||||||
geo.Vertex.apply(this, arguments);
|
geo.Vertex.apply(this, arguments);
|
||||||
|
@ -216,6 +258,7 @@ geo.Normal.prototype.toString = function() {
|
||||||
* Represent a texture coordinate element
|
* Represent a texture coordinate element
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
|
* @param {String} a string like in the .obj file (e.g. 'vt 0.5 0.5')
|
||||||
*/
|
*/
|
||||||
geo.TexCoord = function() {
|
geo.TexCoord = function() {
|
||||||
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
|
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
|
||||||
|
@ -268,9 +311,10 @@ geo.TexCoord.prototype.toString = function() {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a face
|
* Represents a face. Only triangles are supported. For quadrangular polygons, see {@link geo.parseFace}
|
||||||
* @constructor
|
* @constructor
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
|
* @param {String} A string like in a .obj file (e.g. 'f 1/1/1 2/2/2 3/3/3' or 'f 1 2 3').
|
||||||
*/
|
*/
|
||||||
geo.Face = function() {
|
geo.Face = function() {
|
||||||
var split;
|
var split;
|
||||||
|
@ -368,7 +412,7 @@ geo.Face = function() {
|
||||||
* @returns {Face[]} a single 3-vertices face or two 3-vertices face if it was
|
* @returns {Face[]} a single 3-vertices face or two 3-vertices face if it was
|
||||||
* a 4-vertices face
|
* a 4-vertices face
|
||||||
*/
|
*/
|
||||||
var parseFace = function(arg) {
|
geo.parseFace = function(arg) {
|
||||||
|
|
||||||
var split = arg.trim().split(' ');
|
var split = arg.trim().split(' ');
|
||||||
var ret = [];
|
var ret = [];
|
||||||
|
|
|
@ -2,10 +2,25 @@ var Log = require('../lib/NodeLog.js');
|
||||||
var L3D = require('../../static/js/l3d.min.js');
|
var L3D = require('../../static/js/l3d.min.js');
|
||||||
var THREE = require('three');
|
var THREE = require('three');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones a vector
|
||||||
|
* @private
|
||||||
|
* @param {Object} vec an object with attributes x, y, and z
|
||||||
|
* @return {Object} a new object with the same x, y, and z attributes
|
||||||
|
*/
|
||||||
function clone(vec) {
|
function clone(vec) {
|
||||||
return {x : vec.x, y : vec.y, z : vec.z};
|
return {x : vec.x, y : vec.y, z : vec.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates a vector, three.js style
|
||||||
|
* @private
|
||||||
|
* @param {Object} vec1 an object with attributes x, y, and z
|
||||||
|
* @param {Number} x three.js's rotateX value
|
||||||
|
* @param {Number} y three.js's rotateY value
|
||||||
|
* @param {Number} z three.js's rotateZ value
|
||||||
|
* @return {Object} a new vector corresponding to the rotated vector
|
||||||
|
*/
|
||||||
function rotation(vec1, x, y, z) {
|
function rotation(vec1, x, y, z) {
|
||||||
|
|
||||||
var cos = Math.cos(z);
|
var cos = Math.cos(z);
|
||||||
|
@ -39,6 +54,18 @@ function rotation(vec1, x, y, z) {
|
||||||
return clone(newVec);
|
return clone(newVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a transformation to a vector
|
||||||
|
* @param {Object} vector an object with attributes x, y, and z
|
||||||
|
* @param {Object} transfo an object with attributes
|
||||||
|
* <ul>
|
||||||
|
* <li><code>translation</code> : an object with attributes x, y, and z representing the translation</li>
|
||||||
|
* <li><code>rotation</code> : an object with attributes x, y, and z representing the rotation</li>
|
||||||
|
* <li><code>scale</code> : a number representing the scaling </li>
|
||||||
|
* </ul>
|
||||||
|
* @see {@link rotation}
|
||||||
|
* @return {Object} a new object with attributes x, y and z corresponding to the transformation applied to <code>vector</code>
|
||||||
|
*/
|
||||||
function applyTransformation(vector, transfo) {
|
function applyTransformation(vector, transfo) {
|
||||||
|
|
||||||
var ret = rotation(vector, transfo.rotation.x, transfo.rotation.y, transfo.rotation.z);
|
var ret = rotation(vector, transfo.rotation.x, transfo.rotation.y, transfo.rotation.z);
|
||||||
|
@ -57,6 +84,9 @@ function applyTransformation(vector, transfo) {
|
||||||
* Represents a mesh. All meshes are loaded once in geo.availableMesh to avoid
|
* Represents a mesh. All meshes are loaded once in geo.availableMesh to avoid
|
||||||
* loading at each mesh request
|
* loading at each mesh request
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @param {String} path path to the .obj file
|
||||||
|
* @param {Object} transfo a transformation object to apply during the loading
|
||||||
|
* @param {function} callback callback to call on the mesh
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
*/
|
*/
|
||||||
geo.MeshContainer = function(path, transfo, callback) {
|
geo.MeshContainer = function(path, transfo, callback) {
|
||||||
|
@ -71,31 +101,31 @@ geo.MeshContainer = function(path, transfo, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* array of each part of the mesh
|
* Array of each part of the mesh
|
||||||
* @type {geo.Mesh[]}
|
* @type {geo.Mesh[]}
|
||||||
*/
|
*/
|
||||||
this.meshes = [];
|
this.meshes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* array of the vertices of the meshes (all merged)
|
* Array of the vertices of the meshes (all merged)
|
||||||
* @type {geo.Vertex[]}
|
* @type {geo.Vertex[]}
|
||||||
*/
|
*/
|
||||||
this.vertices = [];
|
this.vertices = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* array of the faces of the meshes (all merged)
|
* Array of the faces of the meshes (all merged)
|
||||||
* @type {geo.Face[]}
|
* @type {geo.Face[]}
|
||||||
*/
|
*/
|
||||||
this.faces = [];
|
this.faces = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* array of the normals of the meshes (all merged)
|
* Array of the normals of the meshes (all merged)
|
||||||
* @type {geo.Normal[]}
|
* @type {geo.Normal[]}
|
||||||
*/
|
*/
|
||||||
this.normals = [];
|
this.normals = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* array of the texture coordinates (all merged)
|
* Array of the texture coordinates (all merged)
|
||||||
* @type {geo.TexCoord[]}
|
* @type {geo.TexCoord[]}
|
||||||
*/
|
*/
|
||||||
this.texCoords = [];
|
this.texCoords = [];
|
||||||
|
@ -106,8 +136,17 @@ geo.MeshContainer = function(path, transfo, callback) {
|
||||||
*/
|
*/
|
||||||
this.numberOfFaces = 0;
|
this.numberOfFaces = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformation that should be applied to the mesh when loading it
|
||||||
|
* @type {Object}
|
||||||
|
* @see {@link applyTransformation}
|
||||||
|
*/
|
||||||
this.transfo = transfo;
|
this.transfo = transfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to call on the mesh once it is loaded
|
||||||
|
* @type {function}
|
||||||
|
*/
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
if (path !== undefined) {
|
if (path !== undefined) {
|
||||||
|
@ -119,7 +158,7 @@ geo.MeshContainer = function(path, transfo, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a obj file
|
* Loads a obj file and apply the transformation
|
||||||
* @param {string} path the path to the file
|
* @param {string} path the path to the file
|
||||||
*/
|
*/
|
||||||
geo.MeshContainer.prototype.loadFromFile = function(path) {
|
geo.MeshContainer.prototype.loadFromFile = function(path) {
|
||||||
|
@ -195,10 +234,7 @@ geo.MeshContainer.prototype.loadFromFile = function(path) {
|
||||||
|
|
||||||
} else if (line[0] === 'u') {
|
} else if (line[0] === 'u') {
|
||||||
|
|
||||||
// usemtl
|
// usemtl : create a new mesh
|
||||||
// If a current mesh exists, finish it
|
|
||||||
|
|
||||||
// Create a new mesh
|
|
||||||
currentMesh = new geo.Mesh();
|
currentMesh = new geo.Mesh();
|
||||||
self.meshes.push(currentMesh);
|
self.meshes.push(currentMesh);
|
||||||
currentMesh.material = (new geo.Material(line)).name;
|
currentMesh.material = (new geo.Material(line)).name;
|
||||||
|
|
|
@ -3,12 +3,23 @@ var THREE = require('three');
|
||||||
var L3D = require('../../static/js/l3d.min.js');
|
var L3D = require('../../static/js/l3d.min.js');
|
||||||
|
|
||||||
function readIt(sceneNumber, recoId) {
|
function readIt(sceneNumber, recoId) {
|
||||||
return {
|
var toZip = {
|
||||||
triangles :
|
triangles :
|
||||||
JSON.parse(fs.readFileSync('./geo/generated/scene' + sceneNumber + '/triangles' + recoId + '.json')),
|
JSON.parse(fs.readFileSync('./geo/generated/scene' + sceneNumber + '/triangles' + recoId + '.json')),
|
||||||
areas :
|
areas :
|
||||||
JSON.parse(fs.readFileSync('./geo/generated/scene' + sceneNumber + '/areas' + recoId + '.json'))
|
JSON.parse(fs.readFileSync('./geo/generated/scene' + sceneNumber + '/areas' + recoId + '.json'))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var ret = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < toZip.triangles.length; i++) {
|
||||||
|
ret.push({
|
||||||
|
index: toZip.triangles[i],
|
||||||
|
area: toZip.areas[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfReco = [0, 0, 12, 12, 11, 2];
|
numberOfReco = [0, 0, 12, 12, 11, 2];
|
||||||
|
@ -46,6 +57,13 @@ try
|
||||||
predictionTables = [];
|
predictionTables = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks quickly if a triangle might be in a frustum
|
||||||
|
* @private
|
||||||
|
* @param {Object[]} element array of thre 3 vertices of the triangle to test
|
||||||
|
* @param {Object[]} planes array of planes (Object with normal and constant values)
|
||||||
|
* @return {Boolean} false if we can be sure that the triangle is not in the frustum, true oherwise
|
||||||
|
*/
|
||||||
function isInFrustum(element, planes) {
|
function isInFrustum(element, planes) {
|
||||||
|
|
||||||
if (element instanceof Array) {
|
if (element instanceof Array) {
|
||||||
|
@ -99,47 +117,6 @@ function isInFrustum(element, planes) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
* A class that streams easily a mesh via socket.io
|
||||||
* @memberOf geo
|
* @memberOf geo
|
||||||
|
@ -184,12 +161,6 @@ geo.MeshStreamer = function(path) {
|
||||||
*/
|
*/
|
||||||
this.texCoords = [];
|
this.texCoords = [];
|
||||||
|
|
||||||
this.minThreshold = 0.75;
|
|
||||||
this.maxThreshold = 0.85;
|
|
||||||
this.currentlyPrefetching = false;
|
|
||||||
|
|
||||||
this.beginning = false;
|
|
||||||
|
|
||||||
this.beginningThreshold = 0.9;
|
this.beginningThreshold = 0.9;
|
||||||
|
|
||||||
this.frustumPercentage = 0.6;
|
this.frustumPercentage = 0.6;
|
||||||
|
@ -212,6 +183,12 @@ geo.MeshStreamer = function(path) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a face is oriented towards the camera
|
||||||
|
* @param {Object} camera a camera (with a position, and a direction)
|
||||||
|
* @param {geo.Face} the face to test
|
||||||
|
* @return {Boolean} true if the face is in the good orientation, face otherwise
|
||||||
|
*/
|
||||||
geo.MeshStreamer.prototype.isBackFace = function(camera, face) {
|
geo.MeshStreamer.prototype.isBackFace = function(camera, face) {
|
||||||
|
|
||||||
var directionCamera = L3D.Tools.diff(
|
var directionCamera = L3D.Tools.diff(
|
||||||
|
@ -244,18 +221,6 @@ geo.MeshStreamer.prototype.faceComparator = function(camera) {
|
||||||
|
|
||||||
var self = this;
|
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) {
|
return function(face1, face2) {
|
||||||
|
|
||||||
var center1 = {
|
var center1 = {
|
||||||
|
@ -271,12 +236,6 @@ geo.MeshStreamer.prototype.faceComparator = function(camera) {
|
||||||
z: center1.z - camera.position.z
|
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 = dir1.x * dir1.x + dir1.y * dir1.y + dir1.z * dir1.z;
|
var dot1 = dir1.x * dir1.x + dir1.y * dir1.y + dir1.z * dir1.z;
|
||||||
|
|
||||||
var center2 = {
|
var center2 = {
|
||||||
|
@ -291,12 +250,6 @@ geo.MeshStreamer.prototype.faceComparator = function(camera) {
|
||||||
z: center2.z - camera.position.z
|
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 = dir2.x * dir2.x + dir2.y * dir2.y + dir2.z * dir2.z;
|
var dot2 = dir2.x * dir2.x + dir2.y * dir2.y + dir2.z * dir2.z;
|
||||||
|
|
||||||
// Decreasing order
|
// Decreasing order
|
||||||
|
@ -312,12 +265,11 @@ geo.MeshStreamer.prototype.faceComparator = function(camera) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the socket.io callback
|
* Initialize the socket.io callbacks
|
||||||
* @param {socket} socket the socket to initialize
|
* @param {socket} socket the socket to initialize
|
||||||
*/
|
*/
|
||||||
geo.MeshStreamer.prototype.start = function(socket) {
|
geo.MeshStreamer.prototype.start = function(socket) {
|
||||||
|
|
||||||
this.meshIndex = 0;
|
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -328,8 +280,6 @@ geo.MeshStreamer.prototype.start = function(socket) {
|
||||||
self.chunk = 1;
|
self.chunk = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.prefetch = prefetch;
|
|
||||||
|
|
||||||
self.mesh = geo.availableMeshes[path];
|
self.mesh = geo.availableMeshes[path];
|
||||||
|
|
||||||
switch (path) {
|
switch (path) {
|
||||||
|
@ -356,6 +306,9 @@ geo.MeshStreamer.prototype.start = function(socket) {
|
||||||
self.predictionTable = predictionTables[3];
|
self.predictionTable = predictionTables[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.generator = geo.ConfigGenerator.createFromString(prefetch, self);
|
||||||
|
self.backupGenerator = new geo.ConfigGenerator(self);
|
||||||
|
|
||||||
if (self.mesh === undefined) {
|
if (self.mesh === undefined) {
|
||||||
process.stderr.write('Wrong path for model : ' + path);
|
process.stderr.write('Wrong path for model : ' + path);
|
||||||
socket.emit('refused');
|
socket.emit('refused');
|
||||||
|
@ -434,103 +387,45 @@ geo.MeshStreamer.prototype.start = function(socket) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create config for proportions of chunks
|
if (cameraExists) {
|
||||||
var config;
|
|
||||||
var didPrefetch = false;
|
|
||||||
|
|
||||||
// if (false) {
|
// Create config for proportions of chunks
|
||||||
|
var didPrefetch = false;
|
||||||
|
var config = self.generator.generateMainConfig(cameraFrustum, recommendationClicked);
|
||||||
|
|
||||||
if (cameraExists) {
|
// Send next elements
|
||||||
|
var oldTime = Date.now();
|
||||||
|
var next = self.nextElements(config);
|
||||||
|
|
||||||
switch (self.prefetch) {
|
// console.log(
|
||||||
case 'V-PP':
|
// 'Adding ' +
|
||||||
config = self.generateConfig_V_PP(cameraFrustum, recommendationClicked);
|
// next.size +
|
||||||
break;
|
// ' for newConfig : '
|
||||||
case 'V-PD':
|
// + JSON.stringify(config.map(function(o) { return o.proportion}))
|
||||||
config = self.generateConfig_V_PD(cameraFrustum, recommendationClicked);
|
// );
|
||||||
break;
|
|
||||||
case 'V-PP+PD':
|
|
||||||
config = self.generateConfig_V_PP_PD(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'NV-PN':
|
|
||||||
default:
|
|
||||||
config = self.generateConfig_NV_PN(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
// console.log(self.prefetch)
|
|
||||||
// process.exit(-1);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send next elements
|
|
||||||
var oldTime = Date.now();
|
|
||||||
var next = self.nextElements(config);
|
|
||||||
|
|
||||||
// console.log(
|
|
||||||
// 'Adding ' +
|
|
||||||
// next.size +
|
|
||||||
// ' for newConfig : '
|
|
||||||
// + JSON.stringify(config.map(function(o) { return o.proportion}))
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
|
||||||
if (self.beginning === true && next.size < self.chunk) {
|
if (self.beginning === true && next.size < self.chunk) {
|
||||||
self.beginning = false;
|
|
||||||
|
|
||||||
switch (self.prefetch) {
|
self.beginning = false;
|
||||||
case 'V-PP':
|
config = self.generator.generateMainConfig(cameraFrustum, recommendationClicked);
|
||||||
config = self.generateConfig_V_PP(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'V-PD':
|
|
||||||
config = self.generateConfig_V_PD(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'V-PP+PD':
|
|
||||||
config = self.generateConfig_V_PP_PD(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'NV-PN':
|
|
||||||
default:
|
|
||||||
config = self.generateConfig_NV_PN(cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fillElements = self.nextElements(config, self.chunk - next.size);
|
}
|
||||||
|
|
||||||
next.configSizes = fillElements.configSizes;
|
var fillElements = self.nextElements(config, self.chunk - next.size);
|
||||||
next.data.push.apply(next.data, fillElements.data);
|
|
||||||
next.size += fillElements.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
next.configSizes = fillElements.configSizes;
|
||||||
|
next.data.push.apply(next.data, fillElements.data);
|
||||||
|
next.size += fillElements.size;
|
||||||
|
|
||||||
// Chunk is not empty, compute fill config
|
// Chunk is not empty, compute fill config
|
||||||
if (next.size < self.chunk) {
|
if (next.size < self.chunk) {
|
||||||
|
|
||||||
switch (self.prefetch) {
|
config = self.generator.generateFillingConfig(config, next, cameraFrustum, recommendationClicked);
|
||||||
case 'V-PP':
|
fillElements = self.nextElements(config, self.chunk - next.size);
|
||||||
config = self.generateFillConfig_V_PP(config, next, cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'V-PD':
|
|
||||||
config = self.generateFillConfig_V_PD(config, next, cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'V-PP+PD':
|
|
||||||
config = self.generateFillConfig_V_PP_PD(config, next, cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
case 'NV-PN':
|
|
||||||
default:
|
|
||||||
config = self.generateFillConfig_NV_PN(config, next, cameraFrustum, recommendationClicked);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
next.data.push.apply(next.data, fillElements.data);
|
||||||
|
next.size += fillElements.size;
|
||||||
|
|
||||||
fillElements = self.nextElements(config, self.chunk - next.size);
|
|
||||||
|
|
||||||
next.data.push.apply(next.data, fillElements.data);
|
|
||||||
next.size += fillElements.size;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
next = { data : [], size : 0 };
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,10 +439,12 @@ geo.MeshStreamer.prototype.start = function(socket) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// }
|
} else {
|
||||||
|
|
||||||
// var config = [{proportion: 1, smart: true, recommendationId: 1}];
|
config = self.backupGenerator.generateMainConfig();
|
||||||
// var next = self.nextElements(config);
|
next = self.nextElements(config, self.chunk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Chunk of size ' + next.size + ' (generated in ' + (Date.now() - oldTime) + 'ms)');
|
console.log('Chunk of size ' + next.size + ' (generated in ' + (Date.now() - oldTime) + 'ms)');
|
||||||
|
|
||||||
|
@ -595,241 +492,11 @@ geo.MeshStreamer.prototype.nextMaterials = function() {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateConfig_NV_PN = function(cameraFrustum) {
|
|
||||||
|
|
||||||
var config;
|
|
||||||
|
|
||||||
// if (this.beginning === true) {
|
|
||||||
|
|
||||||
// console.log('Begining : full init');
|
|
||||||
// config = [{recommendationId : 0, proportion:1, smart: true}];
|
|
||||||
|
|
||||||
|
|
||||||
// } else {
|
|
||||||
|
|
||||||
// Case without prefetch
|
|
||||||
console.log("No prefetching");
|
|
||||||
config = [{ frustum: cameraFrustum, proportion: 1}];
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateConfig_V_PD = function(cameraFrustum, recommendationClicked) {
|
|
||||||
|
|
||||||
var config;
|
|
||||||
if (recommendationClicked != null) {
|
|
||||||
|
|
||||||
if (this.beginning === true) {
|
|
||||||
this.beginning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case full reco
|
|
||||||
console.log("Going to " + recommendationClicked);
|
|
||||||
console.log("Recommendation is clicking : full for " + JSON.stringify(this.mesh.recommendations[recommendationClicked].position));
|
|
||||||
config = [{recommendationId : recommendationClicked + 1, proportion: 1, smart:true}];
|
|
||||||
|
|
||||||
} else if (this.beginning === true) {
|
|
||||||
|
|
||||||
console.log('Begining : full init');
|
|
||||||
config = [{recommendationId : 0, proportion:1, smart: true}];
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Case without prefetch
|
|
||||||
console.log("No prefetching");
|
|
||||||
config = [{ frustum: cameraFrustum, proportion: 1}];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateConfig_V_PP = function(cameraFrustum) {
|
|
||||||
|
|
||||||
var config;
|
|
||||||
|
|
||||||
if (this.beginning === true) {
|
|
||||||
|
|
||||||
console.log('Begining : full init');
|
|
||||||
config = [{recommendationId : 0, proportion:1, smart: true}];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Case full prefetch
|
|
||||||
console.log("Allow some prefetching");
|
|
||||||
|
|
||||||
didPrefetch = true;
|
|
||||||
config = [{ frustum: cameraFrustum, proportion : this.frustumPercentage}];
|
|
||||||
|
|
||||||
if (this.predictionTable !== undefined) {
|
|
||||||
|
|
||||||
var sum = 0;
|
|
||||||
|
|
||||||
for (var i = 1; i <= this.mesh.recommendations.length; i++) {
|
|
||||||
|
|
||||||
sum += this.predictionTable[this.previousReco][i];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 1; i <= this.mesh.recommendations.length; i++) {
|
|
||||||
|
|
||||||
if (this.predictionTable[this.previousReco][i] > 0) {
|
|
||||||
|
|
||||||
config.push({
|
|
||||||
|
|
||||||
proportion : this.predictionTable[this.previousReco][i] * this.prefetchPercentage / sum,
|
|
||||||
recommendationId : i,
|
|
||||||
smart: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
process.stderr.write('ERROR : PREDICTION TABLE IF UNDEFINED');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateConfig_V_PP_PD = function(cameraFrustum, recommendationClicked) {
|
|
||||||
|
|
||||||
var config;
|
|
||||||
|
|
||||||
if (recommendationClicked != null) {
|
|
||||||
|
|
||||||
if (this.beginning === true) {
|
|
||||||
this.beginning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Case full reco
|
|
||||||
console.log("Going to " + recommendationClicked);
|
|
||||||
console.log("Recommendation is clicking : full for " + JSON.stringify(this.mesh.recommendations[recommendationClicked].position));
|
|
||||||
config = [{recommendationId : recommendationClicked + 1, proportion: 1, smart:true}];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else if (this.beginning === true) {
|
|
||||||
|
|
||||||
console.log('Begining : full init');
|
|
||||||
config = [{recommendationId : 0, proportion:1, smart: true}];
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Case full prefetch
|
|
||||||
console.log("Allow some prefetching");
|
|
||||||
|
|
||||||
config = [{ frustum: cameraFrustum, proportion : this.frustumPercentage}];
|
|
||||||
|
|
||||||
// Find best recommendation
|
|
||||||
var bestReco;
|
|
||||||
var bestScore = -Infinity;
|
|
||||||
var bestIndex = null;
|
|
||||||
|
|
||||||
if (this.predictionTable !== undefined) {
|
|
||||||
|
|
||||||
var sum = 0;
|
|
||||||
|
|
||||||
for (var i = 1; i <= this.mesh.recommendations.length; i++) {
|
|
||||||
|
|
||||||
sum += this.predictionTable[this.previousReco][i];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 1; i <= this.mesh.recommendations.length; i++) {
|
|
||||||
|
|
||||||
if (this.predictionTable[this.previousReco][i] > 0) {
|
|
||||||
|
|
||||||
config.push({
|
|
||||||
|
|
||||||
proportion : this.predictionTable[this.previousReco][i] * this.prefetchPercentage / sum,
|
|
||||||
recommendationId : i,
|
|
||||||
smart: true
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (score > this.maxThreshold)
|
|
||||||
// this.currentlyPrefetching = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
process.stderr.write('ERROR : PREDICTION TABLE IF UNDEFINED');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateFillConfig_NV_PN =
|
|
||||||
function(previousConfig, previousResult, cameraFrustum, recommendationClicked) {
|
|
||||||
|
|
||||||
// Nothing to do better than linear, let default fill do its work
|
|
||||||
return {data:[], size: 0};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateFillConfig_V_PP =
|
|
||||||
function(previousConfig, previousResult, cameraFrustum, recommendationClicked) {
|
|
||||||
|
|
||||||
var sum = 0;
|
|
||||||
var newConfig = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < previousConfig.length; i++) {
|
|
||||||
|
|
||||||
// Check if previousConfig was full
|
|
||||||
if (previousResult.configSizes[i] >= this.chunk * previousConfig[i].proportion) {
|
|
||||||
|
|
||||||
newConfig.push(previousConfig[i]);
|
|
||||||
sum += previousConfig[i].proportion;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize previousConfig probabilities
|
|
||||||
for (var i = 0; i < newConfig.length; i++) {
|
|
||||||
|
|
||||||
newConfig[i].proportion /= sum;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return newConfig;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateFillConfig_V_PP_PD =
|
|
||||||
geo.MeshStreamer.prototype.generateFillConfig_V_PP;
|
|
||||||
|
|
||||||
geo.MeshStreamer.prototype.generateFillConfig_V_PD =
|
|
||||||
function(previousConfig, previousResult, cameraFrustum, recommendationClicked) {
|
|
||||||
|
|
||||||
return [{proportion:1, frustum: cameraFrustum}];
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the next elements
|
* Prepare the next elements
|
||||||
* @param {camera} _camera a camera that can be usefull to do smart streaming (stream
|
* @param {Object[]} config a configuration list
|
||||||
* only interesting parts according to the camera
|
|
||||||
* @returns {array} an array of elements ready to send
|
* @returns {array} an array of elements ready to send
|
||||||
|
* @see {@link https://github.com/DragonRock/3dinterface/wiki/Streaming-configuration|Configuration list documentation}
|
||||||
*/
|
*/
|
||||||
geo.MeshStreamer.prototype.nextElements = function(config, chunk) {
|
geo.MeshStreamer.prototype.nextElements = function(config, chunk) {
|
||||||
|
|
||||||
|
@ -915,18 +582,15 @@ geo.MeshStreamer.prototype.nextElements = function(config, chunk) {
|
||||||
var currentArea = 0;
|
var currentArea = 0;
|
||||||
|
|
||||||
// Fill buffer using facesToSend
|
// Fill buffer using facesToSend
|
||||||
for (var faceIndex = 0; faceIndex < this.facesToSend[currentConfig.recommendationId].triangles.length; faceIndex++) {
|
for (var faceIndex = 0; faceIndex < this.facesToSend[currentConfig.recommendationId].length; faceIndex++) {
|
||||||
|
|
||||||
var faceInfo = {
|
var faceInfo = this.facesToSend[currentConfig.recommendationId][faceIndex];
|
||||||
index:this.facesToSend[currentConfig.recommendationId].triangles[faceIndex],
|
|
||||||
area: this.facesToSend[currentConfig.recommendationId].areas[faceIndex]
|
|
||||||
};
|
|
||||||
|
|
||||||
area += faceInfo.area;
|
area += faceInfo.area;
|
||||||
|
|
||||||
// if (area > 0.6) {
|
if (area > 0.9) {
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (this.faces[faceInfo.index] !== true) {
|
if (this.faces[faceInfo.index] !== true) {
|
||||||
|
|
||||||
|
@ -1091,7 +755,6 @@ geo.MeshStreamer.prototype.pushFace = function(face, buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.push(face.toList());
|
buffer.push(face.toList());
|
||||||
// this.meshFaces[meshIndex] = this.meshFaces[meshIndex] || [];
|
|
||||||
this.faces[face.index] = true;
|
this.faces[face.index] = true;
|
||||||
totalSize+=3;
|
totalSize+=3;
|
||||||
|
|
||||||
|
|
|
@ -122,3 +122,7 @@ function main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = main;
|
module.exports = main;
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue