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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user