From 0808d00bcb17e1571e8160b8e29dc8bb7bcd0f4f Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Mon, 4 Jan 2016 17:54:14 +0100 Subject: [PATCH] Missing files --- server.js | 2 + server/controllers/demo/index.js | 32 +++++ server/controllers/demo/urls.js | 4 + .../controllers/demo/views/demo-config.jade | 42 ++++++ server/controllers/demo/views/demo.jade | 65 +++++++++ .../geo/ConfigGenerators/ConfigGenerator.js | 33 +++++ .../ConfigGenerators/ConfigGeneratorEnd.js | 24 ++++ server/geo/ConfigGenerators/NV_PN.js | 40 ++++++ server/geo/ConfigGenerators/V_PD.js | 61 +++++++++ server/geo/ConfigGenerators/V_PP.js | 109 +++++++++++++++ server/geo/ConfigGenerators/V_PP_PD.js | 128 ++++++++++++++++++ 11 files changed, 540 insertions(+) create mode 100644 server.js create mode 100644 server/controllers/demo/index.js create mode 100644 server/controllers/demo/urls.js create mode 100644 server/controllers/demo/views/demo-config.jade create mode 100644 server/controllers/demo/views/demo.jade create mode 100644 server/geo/ConfigGenerators/ConfigGenerator.js create mode 100644 server/geo/ConfigGenerators/ConfigGeneratorEnd.js create mode 100644 server/geo/ConfigGenerators/NV_PN.js create mode 100644 server/geo/ConfigGenerators/V_PD.js create mode 100644 server/geo/ConfigGenerators/V_PP.js create mode 100644 server/geo/ConfigGenerators/V_PP_PD.js diff --git a/server.js b/server.js new file mode 100644 index 0000000..dbc7817 --- /dev/null +++ b/server.js @@ -0,0 +1,2 @@ +process.chdir('./server'); +require('./server/server.js')(); diff --git a/server/controllers/demo/index.js b/server/controllers/demo/index.js new file mode 100644 index 0000000..a11c829 --- /dev/null +++ b/server/controllers/demo/index.js @@ -0,0 +1,32 @@ +module.exports.demoConfig = function(req, res) { + res.setHeader('Content-Type', 'text/html'); + + res.render('demo-config.jade', res.locals, function(err, result) { + res.send(result); + }); + +}; + +module.exports.demo = function(req, res) { + + res.setHeader('Content-Type', 'text/html'); + + switch (req.query.scene) { + case '2': res.locals.scene = 'L3D.initBobomb'; break; + case '3': res.locals.scene = 'L3D.initMountain'; break; + case '4': res.locals.scene = 'L3D.initWhomp'; break; + } + + switch (req.query.bookmark) { + case '0': res.locals.bookmark = 'L3D.BaseRecommendation'; break; + case '1': res.locals.bookmark = 'L3D.ViewportRecommendation'; break; + case '2': res.locals.bookmark = 'L3D.ArrowRecommendation'; break; + } + + res.locals.prefetch = req.query.prefetch; + + res.render('demo.jade', res.locals, function(err, result) { + res.send(result); + }); +}; + diff --git a/server/controllers/demo/urls.js b/server/controllers/demo/urls.js new file mode 100644 index 0000000..70d2451 --- /dev/null +++ b/server/controllers/demo/urls.js @@ -0,0 +1,4 @@ +module.exports = { + '/demo-config': 'demoConfig', + '/demo': 'demo' +}; diff --git a/server/controllers/demo/views/demo-config.jade b/server/controllers/demo/views/demo-config.jade new file mode 100644 index 0000000..33e0ef8 --- /dev/null +++ b/server/controllers/demo/views/demo-config.jade @@ -0,0 +1,42 @@ +extends ../../../views/base.jade + +block extrahead + link(rel="stylesheet", href="/static/css/signin.css") + +block content + form#form.form-signin(method="GET", action='/demo') + h2 Set your parameters ! + .form-group + label Select your scene + .form-group + input(type='radio', name='scene', value='2', style={'margin-right': '5px'}, checked) + | Bobomb scene
+ input(type='radio', name='scene', value='3', style={'margin-right': '5px'}) + | Cool cool mountain scene
+ input(type='radio', name='scene', value='4', style={'margin-right': '5px'}) + | Whomp scene + + label Select your bookmarks + .form-group + input(type='radio', name='bookmark', value='0', style={'margin-right': '5px'}, checked) + | No bookmarks
+ input(type='radio', name='bookmark', value='1', style={'margin-right': '5px'}) + | Viewports
+ input(type='radio', name='bookmark', value='2', style={'margin-right': '5px'}) + | Arrows + + label Select your prefetching policy + .form-group + input(type='radio', name='prefetch', value='NV-PN', style={'margin-right': '5px'}, checked) + | NV-PN : frustum / backface culling, no prefetch
+ input(type='radio', name='prefetch', value='V-PP', style={'margin-right': '5px'}) + | V-PP : try to predict the next clicked bookmark and prefetch it
+ input(type='radio', name='prefetch', value='V-PD', style={'margin-right': '5px'}) + | V-PD : only prefetch when clicking on a bookmark
+ input(type='radio', name='prefetch', value='V-PP+PD', style={'margin-right': '5px'}) + | V-PP+PD : try to predict bookmark and prefetch on click + + button.btn.btn-lg.btn-primary.btn-block(type="submit") Start playing ! + + + diff --git a/server/controllers/demo/views/demo.jade b/server/controllers/demo/views/demo.jade new file mode 100644 index 0000000..21d2c0f --- /dev/null +++ b/server/controllers/demo/views/demo.jade @@ -0,0 +1,65 @@ +extends ../../../views/withjs + +block title + title #{title} - Prototype + +block prepend js + script BD_DISABLED = true; + +block extrajs + script(src="/static/js/l3dp.min.js") + block configjs + script. + initMainScene = #{scene}; + Recommendation = #{bookmark}; + prefetch = "#{prefetch}"; + locked = #{session.locked === undefined ? 'true' : session.locked}; + coinsId=[]; + + script(src="/static/js/prototypeinteractive.min.js") + script document.getElementById('music').volume = 0.5; + + +block extrahead + link(rel="stylesheet" href="/static/css/prototype.css") + +block content + #main-div.panel-group(style={'margin-top':'10px', 'margin-bottom':'10px'}) + block description + #alert-placeholder + .progress + .progress-bar.progress-bar-striped.active(role='progress-bar', aria-valuenow='0',aria-valuemin="0", aria-valuemax="100", style={width:'0%'}) + #percentage 0% + + div(style="margin:5px") + #container(style={'padding': '0px', 'margin': '0px'}, tabindex="1") + + nav.navbar.navbar-default.navbar-fixed-bottom + .container + button#reset.btn.btn-primary.navbar-btn(style={'margin-right': '10px', 'margin-bottom':'10px'}) Reset camera + block extrabutton + + button#undo.btn.btn-default.navbar-btn(style={'margin-right': '10px', 'margin-bottom': '10px'}) + span.glyphicon.glyphicon-triangle-left('aria-hidden'="true") + + button#redo.btn.btn-default.navbar-btn(style={'margin-right': '10px', 'margin-bottom':'10px'}) + span.glyphicon.glyphicon-triangle-right('aria-hidden'="true") + + //-input#fullarrow(type="checkbox", style={'margin-right': '10px', 'margin-bottom': '10px'}) + //-label(for="fullarrow" style={'margin-right':'10px'}) Full arrow + + input#lock(type="checkbox", style={'zoom':'1.7'}, checked) + label(for="lock" style={'margin-right':'10px', 'zoom': '1.7'}) Pointer lock + + input#showarrows(type="checkbox", style={'margin-right': '10px', 'margin-bottom': '10px', 'display':'none'}, checked) + label(for="showarrows" style={'margin-right':'10px', 'display': 'none'}) Show arrows + + //- block lastbutton + + //-input#recommendation(type="checkbox", style={'margin-right': '10px', 'margin-bottom': '10px'}) + //-label(for="recommendation" style={'margin-right':'10px'}) Fixed prev + + audio#music(controls, volume=0.5) + source(src="/static/data/music/bobomb.ogg") + source(src="/static/data/music/bobomb.mp3") + diff --git a/server/geo/ConfigGenerators/ConfigGenerator.js b/server/geo/ConfigGenerators/ConfigGenerator.js new file mode 100644 index 0000000..bf20532 --- /dev/null +++ b/server/geo/ConfigGenerators/ConfigGenerator.js @@ -0,0 +1,33 @@ +/** + * Creates an empty config generator (generating always empty configs) + * @constructor + * @param streamer {geo.MeshStreamer} the parent mesh streamer + */ +geo.ConfigGenerator = function(streamer) { + + this.streamer = streamer; + this.beginning = true; + +}; + +/** + * Generates an empty configuration + * @return {Object[]} an empty array + */ +geo.ConfigGenerator.prototype.generateMainConfig = function() { + + process.stderr.write('Warning : empty config generator used\n'); + return []; + +}; + +/** + * Generates an empty configuration + * @return {Object[]} an empty array + */ +geo.ConfigGenerator.prototype.generateFillingConfig = function() { + + process.stderr.write('Warning : empty config generator used\n'); + return []; + +}; diff --git a/server/geo/ConfigGenerators/ConfigGeneratorEnd.js b/server/geo/ConfigGenerators/ConfigGeneratorEnd.js new file mode 100644 index 0000000..b5dd585 --- /dev/null +++ b/server/geo/ConfigGenerators/ConfigGeneratorEnd.js @@ -0,0 +1,24 @@ +/** + * Creates a configuration generator from a string that can be 'NV-PN', 'V-PP', 'V-PD', or 'V-PP-PD' + * @param prefetchingPolicy {String} the string corresponding to the prefetching policy + * @param streamer {Reference to the {@link geo.MeshStreamer} + * @return {geo.ConfigGenerator} An instance of one of the subclasses of {@link geo.ConfigGenerator} + */ +geo.ConfigGenerator.createFromString = function(prefetchingPolicy, streamer) { + + // Convert arguments into an array + var args = Array.prototype.slice.call(arguments); + args[0] = null; + + // Shift that array in order to create a generator easily + switch (prefetchingPolicy) { + case 'NV-PN': return new (Function.prototype.bind.apply(geo.NV_PN_Generator,args)); + case 'V-PD': return new (Function.prototype.bind.apply(geo.V_PD_Generator,args)); + case 'V-PP': return new (Function.prototype.bind.apply(geo.V_PP_Generator,args)); + case 'V-PP-PD': return new (Function.prototype.bind.apply(geo.V_PP_PD_Generator,args)); + default: + process.stderr.write('Warning : prefetch type not recognized, using default...\n'); + return new geo.ConfigGenerator(); + } + +}; diff --git a/server/geo/ConfigGenerators/NV_PN.js b/server/geo/ConfigGenerators/NV_PN.js new file mode 100644 index 0000000..db0ba34 --- /dev/null +++ b/server/geo/ConfigGenerators/NV_PN.js @@ -0,0 +1,40 @@ +/** + * Class that represents a generator that streams first the frustum of the + * camera, and then linearly according to the .obj file + * @constructor + * @augments geo.ConfigGenerator + * @param streamer {geo.MeshStreamer} the parent mesh streamer + */ +geo.NV_PN_Generator = function(streamer) { + + geo.ConfigGenerator.apply(this, arguments); + +}; + +geo.NV_PN_Generator.prototype = Object.create(geo.ConfigGenerator); +geo.NV_PN_Generator.prototype.constructor = geo.NV_PN_Generator; + +/** + * Generates a configuration with only the camera frustum, with proportion of 1 + * @returns {Object[]} an array with one element corresponding to the camera frustum + */ +geo.NV_PN_Generator.prototype.generateMainConfig = function(cameraFrustum, recommendationClicked) { + + var config; + + // Case without prefetch + console.log("No prefetching"); + config = [{ frustum: cameraFrustum, proportion: 1}]; + + return config; +}; + +/** + * Generates an empty configuration + * @returns {Object[]} an empty array + */ +geo.NV_PN_Generator.prototype.generateFillingConfig = function(previousConfig, previousData, cameraFrustum, recommendationClicked) { + + return []; + +}; diff --git a/server/geo/ConfigGenerators/V_PD.js b/server/geo/ConfigGenerators/V_PD.js new file mode 100644 index 0000000..7ca2cd6 --- /dev/null +++ b/server/geo/ConfigGenerators/V_PD.js @@ -0,0 +1,61 @@ +/** + * Class that represents a generator that streams the recommendation clicked if any, of the frustum + * @constructor + * @augments geo.ConfigGenerator + * @param streamer {geo.MeshStreamer} the parent mesh streamer + */ +geo.V_PD_Generator = function() { + + geo.ConfigGenerator.apply(this, arguments); + +}; + +geo.V_PD_Generator.prototype = Object.create(geo.ConfigGenerator); +geo.V_PD_Generator.prototype.constructor = geo.V_PD_Generator; + +/** + * Generates a config that streams everything on the recommendation clicked if any, or full on the frustum + * @param cameraFrustum {Object} the frustum of the camera (with its position, target, and planes) + * @param recommendationClicked {Number|null} id of the recommendation (can be null if no recommendations are clicked) + * @returns {Object[]} an array with one element corresponding to the recommendation clicked, or the camera frustum if there are no recommendations clicked + */ +geo.V_PD_Generator.prototype.generateMainConfig = function(cameraFrustum, recommendationClicked) { + + var config; + if (recommendationClicked != null) { + + if (this.streamer.beginning === true) { + this.streamer.beginning = false; + } + + // Case full reco + console.log("Going to " + recommendationClicked); + console.log("Recommendation is clicking : full for " + JSON.stringify(this.streamer.mesh.recommendations[recommendationClicked].position)); + config = [{recommendationId : recommendationClicked + 1, proportion: 1, smart:true}]; + + } else if (this.streamer.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; +}; + +/** + * Generates a configuration with only the camera frustum, with proportion of 1 + * @returns {Object[]} an array with one element corresponding to the camera frustum + */ +geo.V_PD_Generator.prototype.generateFillingConfig = function() { + + return [{proportion:1, frustum: cameraFrustum}]; + +}; diff --git a/server/geo/ConfigGenerators/V_PP.js b/server/geo/ConfigGenerators/V_PP.js new file mode 100644 index 0000000..44929c0 --- /dev/null +++ b/server/geo/ConfigGenerators/V_PP.js @@ -0,0 +1,109 @@ +/** + * Class that represents a generator that streams the frustum, and tries to preload recommendations that might be clicked + * @constructor + * @augments geo.ConfigGenerator + * @param streamer {geo.MeshStreamer} the parent mesh streamer + */ +geo.V_PP_Generator = function() { + + geo.ConfigGenerator.apply(this, arguments); + +}; + +geo.V_PP_Generator.prototype = Object.create(geo.ConfigGenerator); +geo.V_PP_Generator.prototype.constructor = geo.V_PP_Generator; + +/** + * Generates a config that streams partly the frustum, and splits the rest of the chunk among the recommendations that are likely to be clicked + * @param cameraFrustum {Object} the frustum of the camera (with its position, target, and planes) + * @returns {Object[]} an array with one element corresponding the camera frustum, and other for eventual recommendations to preload + */ +geo.V_PP_Generator.prototype.generateMainConfig = function(cameraFrustum) { + + var config; + + if (this.streamer.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.streamer.frustumPercentage}]; + + if (this.streamer.predictionTable !== undefined) { + + var sum = 0; + + for (var i = 1; i <= this.streamer.mesh.recommendations.length; i++) { + + sum += this.streamer.predictionTable[this.streamer.previousReco][i]; + + } + + for (var i = 1; i <= this.streamer.mesh.recommendations.length; i++) { + + if (this.streamer.predictionTable[this.streamer.previousReco][i] > 0) { + + config.push({ + + proportion : this.streamer.predictionTable[this.streamer.previousReco][i] * this.streamer.prefetchPercentage / sum, + recommendationId : i, + smart: true + + }); + + } + + } + + } else { + + process.stderr.write('ERROR : PREDICTION TABLE IF UNDEFINED'); + + } + + } + + return config; + +}; + +/** + * Generates a config that depends on the previous configuration and that tries to fill the recommendations that were not already filled. + * @param previousConfig {Object} the previous configuration list (that was launched on generateMainConfig + * @param previousData {Object} the data that were given by the nextElements method on {@link geo.MeshStreamer} + * @param cameraFrustum {Object} the frustum of the camera, containing its position, target and planes + * @returns {Object[]} a configuration that tries to fill what was not filled before + */ +geo.V_PP_Generator.prototype.generateFillingConfig = function(previousConfig, previousData, cameraFrustum) { + + var sum = 0; + var newConfig = []; + + for (var i = 0; i < previousConfig.length; i++) { + + // Check if previousConfig was full + if (previousResult.configSizes[i] >= this.streamer.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; + +}; diff --git a/server/geo/ConfigGenerators/V_PP_PD.js b/server/geo/ConfigGenerators/V_PP_PD.js new file mode 100644 index 0000000..718ff72 --- /dev/null +++ b/server/geo/ConfigGenerators/V_PP_PD.js @@ -0,0 +1,128 @@ +/** + * Class that represents a generator that streams the current recommendation clicked if any, or the frustum, and tries to preload recommendations that might be clicked + * @constructor + * @augments geo.V_PP_Generator + * @param streamer {geo.MeshStreamer} the parent mesh streamer + */ +geo.V_PP_PD_Generator = function() { + + geo.V_PP_Generator.apply(this, arguments); + +}; + +geo.V_PP_PD_Generator.prototype = Object.create(geo.V_PP_Generator); +geo.V_PP_PD_Generator.prototype.constructor = geo.V_PP_PD_Generator; + +/** + * Generates a config that streams partly the frustum, and splits the rest of the chunk among the recommendations that are likely to be clicked + * @param cameraFrustum {Object} the frustum of the camera (with its position, target, and planes) + * @param recommendationClicked {Number|null} id of the recommendation (can be null if no recommendations are clicked) + * @returns {Object[]} an array with one element corresponding the current recommendation or the camera frustum, and others for eventual recommendations to preload + */ +geo.V_PP_PD_Generator.prototype.generateMainConfig = function(cameraFrustum, recommendationClicked) { + + var config; + + if (recommendationClicked != null) { + + if (this.streamer.beginning === true) { + this.streamer.beginning = false; + } + + // Case full reco + console.log("Going to " + recommendationClicked); + console.log("Recommendation is clicking : full for " + JSON.stringify(this.streamer.mesh.recommendations[recommendationClicked].position)); + config = [{recommendationId : recommendationClicked + 1, proportion: 1, smart:true}]; + + + + } else if (this.streamer.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.streamer.frustumPercentage}]; + + // Find best recommendation + var bestReco; + var bestScore = -Infinity; + var bestIndex = null; + + if (this.streamer.predictionTable !== undefined) { + + var sum = 0; + + for (var i = 1; i <= this.streamer.mesh.recommendations.length; i++) { + + sum += this.streamer.predictionTable[this.streamer.previousReco][i]; + + } + + for (var i = 1; i <= this.streamer.mesh.recommendations.length; i++) { + + if (this.streamer.predictionTable[this.streamer.previousReco][i] > 0) { + + config.push({ + + proportion : this.streamer.predictionTable[this.streamer.previousReco][i] * this.streamer.prefetchPercentage / sum, + recommendationId : i, + smart: true + + }); + + } + + } + + } else { + + process.stderr.write('ERROR : PREDICTION TABLE IF UNDEFINED'); + + } + + } + + return config; + +}; + +/** + * Generates a config that depends on the previous configuration and that tries to fill the recommendations that were not already filled. + * @param previousConfig {Object} the previous configuration list (that was launched on generateMainConfig + * @param previousData {Object} the data that were given by the nextElements method on {@link geo.MeshStreamer} + * @param cameraFrustum {Object} the frustum of the camera, containing its position, target and planes + * @returns {Object[]} a configuration that tries to fill what was not filled before + */ +geo.V_PP_PD_Generator.prototype.generateFillingConfig = function(previousConfig, previousData, cameraFrustum) { + + var sum = 0; + var newConfig = []; + + for (var i = 0; i < previousConfig.length; i++) { + + // Check if previousConfig was full + if (previousResult.configSizes[i] >= this.streamer.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; + +};