From fa1636ac8e4c3e65156adc0a2a0c7fd43cbce913 Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Mon, 4 Jan 2016 09:29:13 +0100 Subject: [PATCH] Some commits --- analysis/replay/serialize.js | 116 ++++ js/l3d/apps/prototype/GlobalFunctions.js | 3 +- js/l3d/apps/prototype/interactive/main.js | 46 +- js/l3d/src/cameras/PointerCamera.js | 30 +- js/l3d/src/cameras/ReplayCamera.js | 4 +- js/l3d/src/loaders/ProgressiveLoader.js | 20 +- .../recommendations/ViewportRecommendation.js | 2 +- js/l3d/src/scenes/initScene.js | 96 +++- server/geo/MeshContainer.js | 15 + server/geo/MeshStreamer.js | 524 +++++++++++------- server/lib/NodeLog.js | 7 + server/lib/Serial.js | 7 +- server/server.js | 178 +++--- utils/build_all.sh | 1 - 14 files changed, 706 insertions(+), 343 deletions(-) create mode 100644 analysis/replay/serialize.js diff --git a/analysis/replay/serialize.js b/analysis/replay/serialize.js new file mode 100644 index 0000000..e24991b --- /dev/null +++ b/analysis/replay/serialize.js @@ -0,0 +1,116 @@ +"use strict"; + +require('app-module-path').addPath(__dirname + '/../../server/lib'); + +// REQUIRES AND INITS +let width = Math.floor(1134) // /10); +let height = Math.floor(768 ) // /10); + +let XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; +let THREE = require('three'); +let Coin = require('./Coin.js'); +let L3D = require('../../static/js/l3d.min.js'); +let fs = require('fs'); + +let Matrix = require('Matrix'); +let Serial = require('Serial'); + +let scene = new THREE.Scene(); +let geometry = new THREE.Geometry(); + +let peach = new THREE.Object3D(); +let bobomb = new THREE.Object3D(); +let whomp = new THREE.Object3D(); +let mountain = new THREE.Object3D(); + +var finished = false; +let frame = 0; +let raycaster = new THREE.Raycaster(); + +var total = 0; + +let loader, progLoader; + +let id = process.argv[2] === undefined ? 56 : parseInt(process.argv[2]) +let laggy = true; + +let info = {}; + + +// INIT COLORS +var colors = [[0,0,0]]; + +for (let i = 0; i < 856; i++) { + colors.push([ + Math.floor(255*Math.random()), + Math.floor(255*Math.random()), + Math.floor(255*Math.random()) + ]); +} + +var camera; var finished = false; +var Recommendation = L3D.BaseRecommendation; +var forceFinished = false; +main(); + +// FUNCTIONS +function main() { + var path = initElements(id); + var outputName = path.split('/'); + outputName = outputName[outputName.length - 1].replace('.obj', '.json'); + loader = new L3D.ProgressiveLoader( + path, new THREE.Object3D(), null + ); + loader.load( + function() { + console.log("Loaded"); + Serial.serializeToFile(outputName, loader.obj); + } + ); + +} + +function testDistance(old, newP) { + + return ( + L3D.Tools.norm2(L3D.Tools.diff(old.position, newP.position)) + + L3D.Tools.norm2(L3D.Tools.diff(old.target, newP.target)) > 0.1 + ); +} + + +function initElements(id) { + switch (id) { + case 1: + return '/static/data/castle/princess peaches castle (outside)_sub.obj'; + case 2: + return '/static/data/bobomb/bobomb battlefeild_sub.obj'; + case 3: + return '/static/data/mountain/coocoolmountain_sub.obj'; + case 4: + return '/static/data/whomp/Whomps Fortress_sub.obj'; + case 5: + return '/static/data/sponza/sponza.obj'; + default: + console.err('This sceneId doesn\'t exist'); + process.exit(-1); + + + } +} + +function init(data) { + scene.add(camera); + + camera.reset(); + camera.speed = 0.001; + camera.start(); + setTimeout(loop, 0); +} + +function equalFaces(face1, face2) { return face1.a === face2.a && face1.b === face2.b && face1.c === face2.c; }; + +function printVector(vec) { console.log(`(${vec.x},${vec.y},${vec.z})`); } + +let old; + diff --git a/js/l3d/apps/prototype/GlobalFunctions.js b/js/l3d/apps/prototype/GlobalFunctions.js index 8fbe5d2..d49cfd2 100644 --- a/js/l3d/apps/prototype/GlobalFunctions.js +++ b/js/l3d/apps/prototype/GlobalFunctions.js @@ -100,12 +100,13 @@ function objectClickerOnClick(camera1, buttonManager, recommendations, coins) { } else if (obj instanceof L3D.BaseRecommendation) { obj.check(); - camera1.moveHermite(obj); // Send event to DB event = new L3D.DB.Event.ArrowClicked(); event.arrowId = recommendations.indexOf(obj); event.send(); + + camera1.moveHermite(obj, undefined, event.arrowId); } // Update the button manager diff --git a/js/l3d/apps/prototype/interactive/main.js b/js/l3d/apps/prototype/interactive/main.js index def399e..e3dfe15 100644 --- a/js/l3d/apps/prototype/interactive/main.js +++ b/js/l3d/apps/prototype/interactive/main.js @@ -38,15 +38,15 @@ var pointer; var startCanvas; var loadingCanvas; -window.onbeforeunload = function() { - - if (initMainScene !== L3D.initPeach && initMainScene !== L3D.initSponza && !($('#next').is(":visible"))) { - - return 'Warning : you are going to leave the page and abort the current test !'; - - } - -}; +// window.onbeforeunload = function() { +// +// if (initMainScene !== L3D.initPeach && initMainScene !== L3D.initSponza && !($('#next').is(":visible"))) { +// +// return 'Warning : you are going to leave the page and abort the current test !'; +// +// } +// +// }; var nextPage = '/prototype/play'; @@ -69,7 +69,7 @@ function main() { initModels(); initListeners(); - appendTo(container)(stats, Coin, startCanvas, pointer, previewer, loadingCanvas, renderer); + appendTo(container)(stats, Coin, startCanvas, pointer, previewer, /*loadingCanvas,*/ renderer); // appendTo(container)(startCanvas, pointer, previewer, renderer); // Set the good size of cameras @@ -117,6 +117,32 @@ function initThreeElements() { renderer = new THREE.WebGLRenderer({alpha:true, antialias:true}); renderer.setClearColor(0x87ceeb); + var loader = new THREE.OBJLoader(); + + loader.load( + '/static/data/coin/Coin.obj', + function(object) { + object.traverse(function (mesh) { + if (mesh instanceof THREE.Mesh) { + mesh.scale.set(0.01,0.01,0.01); + mesh.material.color.setHex(0xffff00); + mesh.geometry.computeVertexNormals(); + mesh.raycastable = true; + mesh.position.copy(new THREE.Vector3(-23.85237224023958,12.30017484578007,2.883526209796364)); + scene.add(mesh); + + newMesh = mesh.clone(); + newMesh.position.copy(new THREE.Vector3(-8.225753727064939,11.932703941399415,8.637544772060489)); + scene.add(newMesh); + + newMesh.position.copy(new THREE.Vector3(18.198980821370327,2.5219742652442885,10.741621475827422)); + scene.add(newMesh); + + } + }); + } + ); + // Initialize pointer camera camera1 = new L3D.PointerCamera( 50, diff --git a/js/l3d/src/cameras/PointerCamera.js b/js/l3d/src/cameras/PointerCamera.js index d8aca95..47207f3 100644 --- a/js/l3d/src/cameras/PointerCamera.js +++ b/js/l3d/src/cameras/PointerCamera.js @@ -167,7 +167,7 @@ L3D.PointerCamera = function() { * Option to enable or disable the collisions * @type {Boolean} */ - this.collisions = true; + this.collisions = false; /** * Is true when we should log the camera angles. It will be set to false @@ -457,7 +457,7 @@ L3D.PointerCamera.prototype.anglesFromVectors = function() { * @param {Camera} camera Camera to move to * @param {Boolean} [toSave=true] true if you want to save the current state of the camera */ -L3D.PointerCamera.prototype.move = function(recommendation, toSave) { +L3D.PointerCamera.prototype.move = function(recommendation, toSave, recommendationId) { if (toSave === undefined) toSave = true; @@ -488,13 +488,13 @@ L3D.PointerCamera.prototype.move = function(recommendation, toSave) { * @param {Camera} camera Camera to move to * @param {Boolean} [toSave=true] true if you want to save the current state of the camera */ -L3D.PointerCamera.prototype.moveHermite = function(recommendation, toSave) { +L3D.PointerCamera.prototype.moveHermite = function(recommendation, toSave, recommendationId) { if (toSave === undefined) toSave = true; - var otherCamera = recommendation.camera || recommendation; + this.recommendationClicked = recommendationId; - this.recommendationClicked = otherCamera; + var otherCamera = recommendation.camera || recommendation; this.moving = false; this.movingHermite = true; @@ -756,19 +756,22 @@ L3D.PointerCamera.prototype.redoable = function() { * */ L3D.PointerCamera.prototype.toList = function() { - this.updateMatrix(); - this.updateMatrixWorld(); + + var camera = this; // (this.recommendationClicked === null ? this : this.cameras[this.recommendationClicked].camera); + + camera.updateMatrix(); + camera.updateMatrixWorld(); + + camera.matrixWorldInverse.getInverse(camera.matrixWorld); var frustum = new THREE.Frustum(); - var projScreenMatrix = new THREE.Matrix4(); - projScreenMatrix.multiplyMatrices(this.projectionMatrix, this.matrixWorldInverse); - frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(this.projectionMatrix, this.matrixWorldInverse)); + frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)); var ret = - [[this.position.x, this.position.y, this.position.z], - [this.target.x, this.target.y, this.target.z], - this.recommendationClicked !== null + [[camera.position.x, camera.position.y, camera.position.z], + [camera.target.x, camera.target.y, camera.target.z], + this.recommendationClicked ]; for (var i = 0; i < frustum.planes.length; i++) { @@ -782,5 +785,6 @@ L3D.PointerCamera.prototype.toList = function() { } return ret; + }; diff --git a/js/l3d/src/cameras/ReplayCamera.js b/js/l3d/src/cameras/ReplayCamera.js index eab3296..932083a 100644 --- a/js/l3d/src/cameras/ReplayCamera.js +++ b/js/l3d/src/cameras/ReplayCamera.js @@ -121,7 +121,7 @@ L3D.ReplayCamera.prototype.nextEvent = function() { self.isArrow = false; if (typeof self.logReco === 'function') { var info = self.logReco(false, self.totalTime); - require('fs').appendFileSync(info.path, info.value); + // require('fs').appendFileSync(info.path, info.value); } process.stderr.write('\033[31mArrowclicked finished !\033[0m\n'); } @@ -161,7 +161,7 @@ L3D.ReplayCamera.prototype.nextEvent = function() { self.isArrow = true; if (typeof self.logReco === 'function') { var info = self.logReco(true, self.totalTime); - require('fs').appendFileSync(info.path, info.value); + // require('fs').appendFileSync(info.path, info.value); } process.stderr.write('\033[33mArrowclicked ! ' + JSON.stringify(self.cameras[self.event.id].camera.position) + '\033[0m\n'); if (self.quittingTime === Infinity) diff --git a/js/l3d/src/loaders/ProgressiveLoader.js b/js/l3d/src/loaders/ProgressiveLoader.js index 2d8fefe..c5a0b96 100644 --- a/js/l3d/src/loaders/ProgressiveLoader.js +++ b/js/l3d/src/loaders/ProgressiveLoader.js @@ -207,9 +207,9 @@ var ProgressiveLoader = function(path, scene, camera, callback, log, laggy, pref // Only good for sponza model this.camera._moveHermite = this.camera.moveHermite; - this.camera.moveHermite = function(param) { - var toSend = param.position.x > 0 ? 0 : 1; - self.socket.emit('reco', toSend); + this.camera.moveHermite = function() { + console.log(arguments); + self.socket.emit('reco', arguments[2]); self.camera._moveHermite.apply(self.camera, arguments); }; @@ -242,7 +242,7 @@ var ProgressiveLoader = function(path, scene, camera, callback, log, laggy, pref this.mapFace = {}; - this.prefetch = prefetch === undefined ? true : (!!prefetch); + this.prefetch = prefetch; }; @@ -434,11 +434,8 @@ ProgressiveLoader.prototype.initIOCallbacks = function() { var param; if (typeof self.onBeforeEmit === 'function') { - for (var m of self.meshes) { - m.geometry.computeBoundingSphere(); - } param = self.onBeforeEmit(); - setTimeout(function() { self.socket.emit('next', self.getCamera(), param);}, 100); + self.socket.emit('next', self.getCamera(), param); } else { @@ -467,6 +464,13 @@ ProgressiveLoader.prototype.initIOCallbacks = function() { }); }; +ProgressiveLoader.prototype.computeBoundingSphere = function() { + for (var m of this.meshes) { + m.geometry.computeBoundingSphere(); + } + +}; + /** * Starts the communication with the server */ diff --git a/js/l3d/src/recommendations/ViewportRecommendation.js b/js/l3d/src/recommendations/ViewportRecommendation.js index 5c8a61e..0c5d896 100644 --- a/js/l3d/src/recommendations/ViewportRecommendation.js +++ b/js/l3d/src/recommendations/ViewportRecommendation.js @@ -40,7 +40,7 @@ L3D.ViewportRecommendation = function(arg1, arg2, arg3, arg4, position, target) ); (function(self, direction, left, other) { - var material = new THREE.LineBasicMaterial({ color: '0x000000'}); + var material = new THREE.LineBasicMaterial({ color: '0x000000', linewidth: 3}); var geometry = new THREE.Geometry(); var tmpDirection = L3D.Tools.mul(direction, -2); var target = L3D.Tools.sum(self.camera.position, tmpDirection); diff --git a/js/l3d/src/scenes/initScene.js b/js/l3d/src/scenes/initScene.js index e1d7d5d..36c0bb4 100644 --- a/js/l3d/src/scenes/initScene.js +++ b/js/l3d/src/scenes/initScene.js @@ -11,12 +11,12 @@ L3D.LogFunction = function(a,b) { }; L3D.addLight = function(scene) { - var directionalLight = new THREE.DirectionalLight(0xdddddd); - directionalLight.position.set(1, 2.5, 1).normalize(); + var directionalLight = new THREE.DirectionalLight(0x777777); + directionalLight.position.set(1, 1, 0).normalize(); directionalLight.castShadow = false; scene.add(directionalLight); - var ambientLight = new THREE.AmbientLight(0x555555); + var ambientLight = new THREE.AmbientLight(0xbbbbbb); scene.add(ambientLight); }; @@ -167,7 +167,7 @@ L3D.createPeachRecommendations = function(width, height, rec) { L3D.initBobombScene = function(scene, collidableObjects, recommendation, clickable) { var loader = new L3D.ProgressiveLoader( - '/static/data/bobomb/bobomb battlefeild.obj', + '/static/data/bobomb/bobomb battlefeild_sub.obj', scene, recommendation, function(object) { @@ -179,7 +179,9 @@ L3D.initBobombScene = function(scene, collidableObjects, recommendation, clickab THREEx.Transparency.push(object); } }, - L3D.LogFunction + L3D.LogFunction, + false, + prefetch ); loader.load(); @@ -200,6 +202,8 @@ L3D.resetBobombElements = function() { L3D.generateCoins = function(totalCoins, coinIds) { + return []; + var i = 0; var tmp = []; @@ -354,7 +358,7 @@ L3D.initBobomb = function(camera, scene, coins, clickable, coinIds) { L3D.initWhompScene = function(scene, collidableObjects, recommendation, clickable) { var loader = new L3D.ProgressiveLoader( - '/static/data/whomp/Whomps Fortress.obj', + '/static/data/whomp/Whomps Fortress_sub.obj', scene, recommendation, function(object) { @@ -375,7 +379,10 @@ L3D.initWhompScene = function(scene, collidableObjects, recommendation, clickabl } }, - L3D.LogFunction + L3D.LogFunction, + false, + prefetch + ); loader.load(); @@ -510,7 +517,7 @@ L3D.initWhomp = function(recommendation, scene, coins, clickable, coinIds) { L3D.initMountainScene = function(scene, collidableObjects, recommendation, clickable) { var loader = new L3D.ProgressiveLoader( - '/static/data/mountain/coocoolmountain.obj', + '/static/data/mountain/coocoolmountain_sub.obj', scene, recommendation, function(object) { @@ -535,7 +542,10 @@ L3D.initMountainScene = function(scene, collidableObjects, recommendation, click object.material.opacity = 0.5; } }, - L3D.LogFunction + L3D.LogFunction, + false, + prefetch + ); loader.load(); @@ -670,26 +680,26 @@ L3D.initSponzaScene = function(scene, collidableObjects, recommendation, clickab loader.load(); - loader.getCamera = function() { - var ret = loader.camera.toList(); - ret[0][0] *= 10; - ret[0][1] *= 10; - ret[0][2] *= 10; + // loader.getCamera = function() { + // var ret = loader.camera.toList(); + // ret[0][0] *= 10; + // ret[0][1] *= 10; + // ret[0][2] *= 10; - ret[1][0] *= 10; - ret[1][1] *= 10; - ret[1][2] *= 10; + // ret[1][0] *= 10; + // ret[1][1] *= 10; + // ret[1][2] *= 10; - // Planes - for (var i = 2; i < ret.length; i++) { + // // Planes + // for (var i = 3; i < ret.length; i++) { - ret[i][3] *= 10; + // ret[i][3] *= 10; - } + // } - return ret; - }; - loader.obj.scale.set(0.1,0.1,0.1); + // return ret; + // }; + // loader.obj.scale.set(0.1,0.1,0.1); collidableObjects.push(loader.obj); loader.obj.raycastable = true; @@ -724,6 +734,38 @@ L3D.createSponzaRecommendations = function(width, height) { ); }; + return [ +// createRecommendation( +// new THREE.Vector3(-2.591997650227227,4.652225309342689,-2.815524195264902), +// new THREE.Vector3(-40.87987891143996,10.202406707437795,7.344871219063935) +// ) +// ,createRecommendation( +// new THREE.Vector3(-20.507451191489245,1.7638914167988349,1.9557104822169127), +// new THREE.Vector3(-58.90750279083062,7.314072814893941,-7.772163058087716) +// ) +// , +// createRecommendation( +// new THREE.Vector3(-23.383482289183434,14.264152490508069,-1.2119079930928534), +// new THREE.Vector3(-1.7847952083517313,1.9364343472313017,30.117376738037517) +// ), +// createRecommendation( +// new THREE.Vector3(2.327317420088316,0.3629147522258326,-0.3325792884643282), +// new THREE.Vector3(1.3934131694970663,-0.8288981685786133,3.369771966148228) +// ), +// createRecommendation( +// new THREE.Vector3(22.983553977938616,3.829033470023654,0.7135547783419287), +// new THREE.Vector3(1.9041126108599506,-8.375131998286331,32.4423350397072) +// ) +// createRecommendation( +// new THREE.Vector3(-12.939581055355553,3.796374966524073,-2.463006239142574), +// new THREE.Vector3(-51.61901925503118,-1.1193807374029414,6.466518183623911) +// ) +createRecommendation( +new THREE.Vector3(1.3571661176961554,4.934280286310308,-4.294700794239404), +new THREE.Vector3(-31.49512083496389,15.286798072464663,16.04129235749628) +) + ]; + return [ createRecommendation( new THREE.Vector3(97.36225946503932,10.925697484337014,12.852363038244272), @@ -742,8 +784,8 @@ L3D.createSponzaCoins = function() { L3D.resetSponzaElements = function() { return { - position: new THREE.Vector3(92.98373669520107,60.8877777990862,11.130138641670737), - target: new THREE.Vector3(53.76696417668598,56.09739213575453,4.877382575136091) + position: new THREE.Vector3(9.298373669520107,6.08877777990862,1.1130138641670737), + target: new THREE.Vector3(5.376696417668598,5.609739213575453,0.4877382575136091) }; }; @@ -757,7 +799,7 @@ L3D.initSponza = function(recommendation, scene, coins, clickable) { recommendation.resetElements = L3D.resetSponzaElements(); recommendation.collidableObjects = collidableObjects; - recommendation.speed = 0.05; + recommendation.speed = 0.005; recommendation.reset(); recommendation.save(); diff --git a/server/geo/MeshContainer.js b/server/geo/MeshContainer.js index eabe5b2..3222916 100644 --- a/server/geo/MeshContainer.js +++ b/server/geo/MeshContainer.js @@ -317,6 +317,19 @@ var availableMeshNames = { '/static/data/sponza/sponza.obj': { done: false, + transfo : { + rotation: { + x: 0, + y: 0, + z: 0 + }, + translation: { + x: 0, + y: 0, + z: 0 + }, + scale: 0.02 + }, recommendations : L3D.createSponzaRecommendations(1134,768) } @@ -346,6 +359,8 @@ function pushMesh(name) { var reco = availableMeshNames[name].recommendations[i].camera; + reco.aspect = 1134 / 768; + reco.lookAt(reco.target); reco.updateMatrix(); diff --git a/server/geo/MeshStreamer.js b/server/geo/MeshStreamer.js index c568080..01a7999 100644 --- a/server/geo/MeshStreamer.js +++ b/server/geo/MeshStreamer.js @@ -11,7 +11,7 @@ function readIt(sceneNumber, recoId) { }; } -numberOfReco = [0, 0, 12, 12, 11]; +numberOfReco = [0, 0, 12, 12, 11, 2]; function readAll(sceneNumber) { var ret = []; @@ -30,15 +30,15 @@ try JSON.parse(fs.readFileSync('./geo/mat1.json')), JSON.parse(fs.readFileSync('./geo/mat2.json')), JSON.parse(fs.readFileSync('./geo/mat3.json')), - [[1,1,0], - [1,2,0], - [2,1,0]] + [[1,1], + [1,2]] ]; var facesToSend = [ readAll(2), readAll(3), - readAll(4) + readAll(4), + readAll(5) ]; } catch (e) { @@ -188,9 +188,9 @@ geo.MeshStreamer = function(path) { this.maxThreshold = 0.85; this.currentlyPrefetching = false; - this.begining = true; + this.beginning = false; - this.beginingThreshold = 0.9; + this.beginningThreshold = 0.9; this.frustumPercentage = 0.6; this.prefetchPercentage = 1 - this.frustumPercentage; @@ -199,6 +199,7 @@ geo.MeshStreamer = function(path) { * Number of element to send by packet * @type {Number} */ + // this.chunk = 100000; this.chunk = 1250; this.previousReco = 0; @@ -347,6 +348,10 @@ geo.MeshStreamer.prototype.start = function(socket) { self.predictionTable = predictionTables[2]; self.facesToSend = facesToSend[2]; break; + case '/static/data/sponza/sponza.obj': + self.predictionTable = predictionTables[3]; + self.facesToSend = facesToSend[3]; + break; default: self.predictionTable = predictionTables[3]; }; @@ -390,7 +395,8 @@ geo.MeshStreamer.prototype.start = function(socket) { socket.on('next', function(_camera) { // score) { var cameraFrustum = {}; - var begining = self.begining; + var beginning = self.beginning; + var cameraExists = false; // Clean camera attribute if (_camera !== null) { @@ -424,219 +430,126 @@ geo.MeshStreamer.prototype.start = function(socket) { } + cameraExists = true; + } // Create config for proportions of chunks var config; var didPrefetch = false; - if (self.begining === true) { + // if (false) { - console.log('Begining : full init'); - config = [{recommendationId : 0, proportion:1, smart: true}]; + if (cameraExists) { - } else if (!self.prefetch) { - // Case without prefetch - console.log("No prefetching"); - config = [{ frustum: cameraFrustum, proportion: 1}]; - - } else if (recommendationClicked !== null) { - - // Case full reco - console.log("Going to " + recommendationClicked); - console.log("Recommendation is clicking : full for " + JSON.stringify(self.mesh.recommendations[recommendationClicked].position)); - // config = [{frustum: cameraFrustum, proportion:0.5}, {frustum : self.mesh.recommendations[recommendationClicked], proportion: 0.5}]; - config = [{recommendationId : recommendationClicked + 1, proportion: 1, smart:true}]; - - - // } else if (score < self.minThreshold || (!self.currentlyPrefetching && score < self.maxThreshold)) { - - // // Case no prefetch - // console.log("Not good % (" + score + ", prefetch = " + self.currentlyPrefetching + "), full frustum"); - // config = [{ frustum: cameraFrustum, proportion: 1}]; - - // if (score < self.minThreshold) - // self.currentlyPrefetching = false; - - } else { // if (score > self.maxThreshold || (self.currentlyPrefetching && score > self.minThreshold) { - - // Case full prefetch - console.log("Allow some prefetching"); - - didPrefetch = true; - config = [{ frustum: cameraFrustum, proportion : self.frustumPercentage}]; - - // Find best recommendation - var bestReco; - var bestScore = -Infinity; - var bestIndex = null; - - if (self.predictionTable !== undefined) { - - var sum = 0; - - for (var i = 1; i <= self.mesh.recommendations.length; i++) { - - sum += self.predictionTable[self.previousReco][i]; + switch (self.prefetch) { + case 'V-PP': + 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; + // console.log(self.prefetch) + // process.exit(-1); } - for (var i = 1; i <= self.mesh.recommendations.length; i++) { + // Send next elements + var oldTime = Date.now(); + var next = self.nextElements(config); - if (self.predictionTable[self.previousReco][i] > 0) { + // console.log( + // 'Adding ' + + // next.size + + // ' for newConfig : ' + // + JSON.stringify(config.map(function(o) { return o.proportion})) + // ); - config.push({ - proportion : self.predictionTable[self.previousReco][i] * self.prefetchPercentage / sum, - recommendationId : i, - smart: true - - }); + if (self.beginning === true && next.size < self.chunk) { + self.beginning = false; + switch (self.prefetch) { + case 'V-PP': + 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; + next.data.push.apply(next.data, fillElements.data); + next.size += fillElements.size; } - // if (score > self.maxThreshold) - // self.currentlyPrefetching = true; - } else { + // Chunk is not empty, compute fill config + if (next.size < self.chunk) { - process.stderr.write('ERROR : PREDICTION TABLE IF UNDEFINED'); - - } - - } - - // 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})) - // ); - - - console.log(next.configSizes); - - // console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms'); - - if (self.prefetch && next.size < self.chunk) { - - console.log("Chunk not full : prefetch reco"); - - // Recompute config - var newConfig = []; - var sum = 0; - - if (!didPrefetch) { - - if (self.predictionTable !== undefined) { - - var sum = 0; - - for (var i = 1; i <= self.mesh.recommendations.length; i++) { - - sum += self.predictionTable[self.previousReco][i]; + switch (self.prefetch) { + case 'V-PP': + 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; } - for (var i = 1; i <= self.mesh.recommendations.length; i++) { - if (self.predictionTable[self.previousReco][i] > 0) { + fillElements = self.nextElements(config, self.chunk - next.size); - newConfig.push({ - - proportion : self.predictionTable[self.previousReco][i] / (sum), - recommendationId : i, - smart : true - - }); - - } - - } + next.data.push.apply(next.data, fillElements.data); + next.size += fillElements.size; } } else { - for (var i = 0; i < config.length; i++) { - - // Check if config was full - if (next.configSizes[i] >= self.chunk * config[i].proportion) { - - newConfig.push(config[i]); - sum += config[i].proportion; - - } - - } - - // Normalize config probabilities - for (var i = 0; i < newConfig.length; i++) { - - newConfig[i].proportion /= sum; - - } + next = { data : [], size : 0 }; } + // If still not empty, fill linear + if (next.size < self.chunk) { - var newData = self.nextElements(newConfig, self.chunk - next.size); + fillElements = self.nextElements([], self.chunk - next.size); - next.data.push.apply(next.data, newData.data); + next.data.push.apply(next.data, fillElements.data); + next.size += fillElements.size; - // console.log( - // 'Adding ' + - // newData.size + - // ' for newConfig : ' - // + JSON.stringify(newConfig.map(function(o) { return o.proportion})) - // ); + } - next.size = next.size + newData.size; + // } - } - - if (begining && !self.prefetch && next.size < self.chunk) { - - console.log("Chunk not full (begining) : fill frustum"); - - // If nothing, just serve stuff - var tmp = self.nextElements([ - { - proportion: 1, - frustum: cameraFrustum - } - ], self.chunk - next.size); - - next.data.push.apply(next.data, tmp.data); - next.size += tmp.size; - - } - - if (next.size < self.chunk) { - - console.log("Chunk not full : fill linear"); - - // If nothing, just serve stuff - var tmp = self.nextElements([ - // { - // proportion: 1, - // frustum: cameraFrustum - // } - ], self.chunk - next.size); - - next.data.push.apply(next.data, tmp.data); - next.size += tmp.size; - - } + // var config = [{proportion: 1, smart: true, recommendationId: 1}]; + // var next = self.nextElements(config); console.log('Chunk of size ' + next.size + ' (generated in ' + (Date.now() - oldTime) + 'ms)'); - // console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms'); if (next.data.length === 0) { @@ -682,6 +595,236 @@ 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 * @param {camera} _camera a camera that can be usefull to do smart streaming (stream @@ -781,6 +924,10 @@ geo.MeshStreamer.prototype.nextElements = function(config, chunk) { area += faceInfo.area; + // if (area > 0.6) { + // break; + // } + if (this.faces[faceInfo.index] !== true) { var face = this.mesh.faces[faceInfo.index]; @@ -788,31 +935,24 @@ geo.MeshStreamer.prototype.nextElements = function(config, chunk) { if (face === undefined) { console.log(faceInfo.index, this.mesh.faces.length); console.log('ERROR !!!'); + } else { + buffers[configIndex].push(face); } - buffers[configIndex].push(face); - - } else if (this.begining === true) { + } else if (this.beginning === true) { currentArea += faceInfo.area; - if (currentArea > this.beginingThreshold) { + if (currentArea > this.beginningThreshold) { - this.begining = false; + this.beginning = false; } } - if (area > 0.9) { - break; - } - - - } - } var totalSize = 0; diff --git a/server/lib/NodeLog.js b/server/lib/NodeLog.js index 30d5b4f..f1b101a 100644 --- a/server/lib/NodeLog.js +++ b/server/lib/NodeLog.js @@ -66,6 +66,13 @@ Log.dberror = function(error) { ); }; +Log.prefetcherror = function(error) { + log( + '[PFE] ' + new Date() + ' ' + error, + Colors.RED + ); +}; + Log.mailerror = function(error) { log( '[MLE] ' + new Date() + ' ' + error, diff --git a/server/lib/Serial.js b/server/lib/Serial.js index b481e4d..4a26941 100644 --- a/server/lib/Serial.js +++ b/server/lib/Serial.js @@ -83,9 +83,12 @@ module.exports.loadFromFile = loadFromFile; function main() { let loader = new L3D.ProgressiveLoader( - '/static/data/castle/princess peaches castle (outside).obj', + // '/static/data/castle/princess peaches castle (outside).obj', + '/static/data/sponza/sponza.obj', new THREE.Object3D(), - null + null, + undefined, + function(a,b) { console.log(100*a/b + '%'); } ); loader.load(function() { diff --git a/server/server.js b/server/server.js index e1f66e3..0f4409b 100644 --- a/server/server.js +++ b/server/server.js @@ -1,118 +1,124 @@ -var http = require('http'); -var express = require('express'); -var jade = require('jade'); -var pg = require('pg'); +function main() { -var favicon = require('serve-favicon'); + var http = require('http'); + var express = require('express'); + var jade = require('jade'); + var pg = require('pg'); -// secret variables -var secret = require('./private'); + var favicon = require('serve-favicon'); -var app = express(); + // secret variables + var secret = require('./private'); -// Socket.io initialization -var http = require('http').Server(app); -var io = require('socket.io')(http); -require('./socket.js')(io); + var app = express(); -var bodyParser = require('body-parser'); -var session = require('cookie-session'); -var cookieParser = require('cookie-parser'); -var urls = require('./urls'); -var Log = require('./lib/NodeLog.js'); + // Socket.io initialization + var http = require('http').Server(app); + var io = require('socket.io')(http); + require('./socket.js')(io); -var isDev = app.get('env') === 'development'; + var bodyParser = require('body-parser'); + var session = require('cookie-session'); + var cookieParser = require('cookie-parser'); + var urls = require('./urls'); + var Log = require('./lib/NodeLog.js'); -app.set('view engine', 'jade'); -app.set('trust proxy', 1); + var isDev = app.get('env') === 'development'; -app.use(cookieParser(secret.secret)); -app.use(session({ - keys: [secret.secret] -})); + app.set('view engine', 'jade'); + app.set('trust proxy', 1); -app.use(bodyParser.text()); -app.use(bodyParser.urlencoded({ extended: false })); -app.use(bodyParser.json()); + app.use(cookieParser(secret.secret)); + app.use(session({ + keys: [secret.secret] + })); -app.use(function(req, res, next) { + app.use(bodyParser.text()); + app.use(bodyParser.urlencoded({ extended: false })); + app.use(bodyParser.json()); - var start = Date.now(); + app.use(function(req, res, next) { - res.on('finish', function() { - // Log connection - Log.request(req, res, Date.now() - start); + var start = Date.now(); + res.on('finish', function() { + // Log connection + Log.request(req, res, Date.now() - start); + + }); + + res.locals.title = "3DUI"; + res.locals.urls = urls; + res.locals.session = req.session; + next(); }); - res.locals.title = "3DUI"; - res.locals.urls = urls; - res.locals.session = req.session; - next(); -}); + // Set a cookie to know if already came. If not, France laws force to + // warn the user that the website uses cookies. + app.use(function(req, res, next) { + if (req.cookies.alreadyCame) { + res.locals.alertCookie = false; + } else { + res.locals.alertCookie = true; + res.cookie('alreadyCame', true, {maxAge: 604800000}); // One week in ms + } -// Set a cookie to know if already came. If not, France laws force to -// warn the user that the website uses cookies. -app.use(function(req, res, next) { - if (req.cookies.alreadyCame) { - res.locals.alertCookie = false; - } else { - res.locals.alertCookie = true; - res.cookie('alreadyCame', true, {maxAge: 604800000}); // One week in ms - } + if (req.url.substr(0, 7) === '/static' || req.url === '/favicon.ico') { + req.static = true; + } - if (req.url.substr(0, 7) === '/static' || req.url === '/favicon.ico') { - req.static = true; - } + next(); + }); - next(); -}); + // Load controllers + require('./lib/controllers')(app); -// Load controllers -require('./lib/controllers')(app); + // Load post to log data from user study + require('./lib/posts')(app); -// Load post to log data from user study -require('./lib/posts')(app); + // Static files + app.use('/static', express.static('../static')); -// Static files -app.use('/static', express.static('../static')); + // Favicon + app.use(favicon(__dirname + '/../static/ico/favicon.ico')); -// Favicon -app.use(favicon(__dirname + '/../static/ico/favicon.ico')); + // When error raised + app.use(function(err, req, res, next) { + if (err.status === 404) { + res.setHeader('Content-Type', 'text/html'); -// When error raised -app.use(function(err, req, res, next) { - if (err.status === 404) { + res.render('404.jade', res.locals, function(err, result) { + res.send(result); + }); + } + }); + + // When route not found, raise not found + app.use(function(req, res) { res.setHeader('Content-Type', 'text/html'); res.render('404.jade', res.locals, function(err, result) { res.send(result); }); - } -}); - -// When route not found, raise not found -app.use(function(req, res) { - res.setHeader('Content-Type', 'text/html'); - - res.render('404.jade', res.locals, function(err, result) { - res.send(result); }); -}); -// Set ports and ip address -var serverPort, serverIpAddress; -if ( isDev ) { - serverPort = 4000; - // serverIpAddress = require('ip').address(); - serverIpAddress = '0.0.0.0'; -} else { - // Openhift conf - serverPort = process.env.OPENSHIFT_NODEJS_PORT || 8080; - serverIpAddress = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1'; + // Set ports and ip address + var serverPort, serverIpAddress; + if ( isDev ) { + serverPort = 4000; + // serverIpAddress = require('ip').address(); + serverIpAddress = '0.0.0.0'; + } else { + // Openhift conf + serverPort = process.env.OPENSHIFT_NODEJS_PORT || 8080; + serverIpAddress = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1'; + } + + // Start server + http.listen(serverPort, serverIpAddress, function() { + Log.ready("Now listening " + serverIpAddress + ":" + serverPort); + }); + } -// Start server -http.listen(serverPort, serverIpAddress, function() { - Log.ready("Now listening " + serverIpAddress + ":" + serverPort); -}); +module.exports = main; diff --git a/utils/build_all.sh b/utils/build_all.sh index 394a8c1..6095ab6 100755 --- a/utils/build_all.sh +++ b/utils/build_all.sh @@ -3,7 +3,6 @@ type="RELEASE" if [ "$1" == "--dev" ] || [ "$1" == "-d" ]; then - echo yes type="DEV" elif [ "$1" == "--help" ] || [ "$1" == "-h" ]; then echo -e "This is the 3dinterface builder"