From b397a18bea6ce12e890bf63373d6c66fb0c9038f Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Fri, 17 Jul 2015 11:32:57 +0200 Subject: [PATCH] Added coin creator --- controllers/prototype/index.js | 26 ++ controllers/prototype/urls.js | 3 +- controllers/prototype/views/prototype.jade | 1 + .../prototype/views/prototype_clicker.jade | 15 + js/Makefile | 10 +- js/filesaver.min.js | 2 + js/l3d/apps/prototype/GlobalFunctions.js | 7 +- js/l3d/apps/prototype/coin-creator/main.js | 258 ++++++++++++++++++ .../recommendations/ArrowRecommendation.js | 1 - js/l3d/src/scenes/initScene.js | 16 +- js/l3d/src/utils/ObjectClicker.js | 16 +- 11 files changed, 338 insertions(+), 17 deletions(-) create mode 100644 controllers/prototype/views/prototype_clicker.jade create mode 100644 js/filesaver.min.js create mode 100644 js/l3d/apps/prototype/coin-creator/main.js diff --git a/controllers/prototype/index.js b/controllers/prototype/index.js index cd13fd2..1f6ce15 100644 --- a/controllers/prototype/index.js +++ b/controllers/prototype/index.js @@ -145,3 +145,29 @@ module.exports.tutorial = function(req, res) { res.send(result); }); }; + +module.exports.clicker = function(req, res, next) { + + var scene = req.params.scene; + + switch (scene) { + + case 'peach': res.locals.scene = "L3D.initPeach"; break; + case 'coolcoolmountain': res.locals.scene = "L3D.initMountain"; break; + case 'whomp': res.locals.scene = "L3D.initWhomp"; break; + case 'bobomb': res.locals.scene = "L3D.initBobomb"; break; + default: + // 404 + var err = new Error('Incorrect scene'); + err.status = 404; + next(err); + break; + + } + + res.setHeader('Content-Type', 'text/html'); + res.render('prototype_clicker.jade', res.locals, function(err, result) { + res.send(result); + }); + +} diff --git a/controllers/prototype/urls.js b/controllers/prototype/urls.js index 17ad99b..aec4ae4 100644 --- a/controllers/prototype/urls.js +++ b/controllers/prototype/urls.js @@ -7,5 +7,6 @@ module.exports = { '/prototype/replay/:id': 'replay', '/prototype/replay_info/:id': 'replay_info', '/prototype/tutorial': 'tutorial', - '/prototype/sponza': 'sponza' + '/prototype/sponza': 'sponza', + '/prototype/coin-creator/:scene': 'clicker' }; diff --git a/controllers/prototype/views/prototype.jade b/controllers/prototype/views/prototype.jade index c22055f..8eb3e28 100644 --- a/controllers/prototype/views/prototype.jade +++ b/controllers/prototype/views/prototype.jade @@ -26,6 +26,7 @@ block content 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") diff --git a/controllers/prototype/views/prototype_clicker.jade b/controllers/prototype/views/prototype_clicker.jade new file mode 100644 index 0000000..1f24e73 --- /dev/null +++ b/controllers/prototype/views/prototype_clicker.jade @@ -0,0 +1,15 @@ +extends ./prototype + +block title + title #{title} - Prototype + +block mainjs + script initMainScene = #{scene}; + script Recommendation = L3D.ArrowRecommendation; + + script(src="/static/js/filesaver.min.js") + script(src="/static/js/coincreator.min.js") + +block extrabutton + button#save.btn.btn-primary.navbar-btn(style={'margin-right': '10px', 'margin-bottom':'10px'}, onclick="saveCoins();") Save coins + diff --git a/js/Makefile b/js/Makefile index ba11874..0268302 100644 --- a/js/Makefile +++ b/js/Makefile @@ -6,7 +6,10 @@ else CLOSURE=../utils/simple-compiler/compiler.sh endif -all: L3D L3DP Socket Three Stats Bouncing Multisphere StreamingSimulator PrototypeReplay PrototypeInteractive Tutorial TestList +all: L3D L3DP Socket Three Stats Bouncing Multisphere StreamingSimulator PrototypeReplay PrototypeInteractive Tutorial TestList CoinCreator FileSaver + +FileSaver: + cp filesaver.min.js ../static/js/filesaver.min.js L3D: $(CLOSURE) $(OPT) \ @@ -84,6 +87,11 @@ PrototypeInteractive: --js l3d/apps/prototype/interactive/main.js \ --js_output_file ../static/js/prototypeinteractive.min.js +CoinCreator: + $(CLOSURE) $(OPT) \ + --js l3d/apps/prototype/coin-creator/main.js \ + --js_output_file ../static/js/coincreator.min.js + PrototypeReplay: $(CLOSURE) $(OPT) \ --js l3d/apps/prototype/ButtonManager.js \ diff --git a/js/filesaver.min.js b/js/filesaver.min.js new file mode 100644 index 0000000..b629099 --- /dev/null +++ b/js/filesaver.min.js @@ -0,0 +1,2 @@ +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ +var saveAs=saveAs||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},a=e.webkitRequestFileSystem,c=e.requestFileSystem||a||e.mozRequestFileSystem,u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},f="application/octet-stream",s=0,d=500,l=function(t){var o=function(){"string"==typeof t?n().revokeObjectURL(t):t.remove()};e.chrome?o():setTimeout(o,d)},v=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(i){u(i)}}},p=function(e){return/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob(["",e],{type:e.type}):e},w=function(t,u,d){d||(t=p(t));var w,y,m,S=this,h=t.type,O=!1,R=function(){v(S,"writestart progress write writeend".split(" "))},b=function(){if((O||!w)&&(w=n().createObjectURL(t)),y)y.location.href=w;else{var o=e.open(w,"_blank");void 0==o&&"undefined"!=typeof safari&&(e.location.href=w)}S.readyState=S.DONE,R(),l(w)},g=function(e){return function(){return S.readyState!==S.DONE?e.apply(this,arguments):void 0}},E={create:!0,exclusive:!1};return S.readyState=S.INIT,u||(u="download"),r?(w=n().createObjectURL(t),o.href=w,o.download=u,void setTimeout(function(){i(o),R(),l(w),S.readyState=S.DONE})):(e.chrome&&h&&h!==f&&(m=t.slice||t.webkitSlice,t=m.call(t,0,t.size,f),O=!0),a&&"download"!==u&&(u+=".download"),(h===f||a)&&(y=e),c?(s+=t.size,void c(e.TEMPORARY,s,g(function(e){e.root.getDirectory("saved",E,g(function(e){var n=function(){e.getFile(u,E,g(function(e){e.createWriter(g(function(n){n.onwriteend=function(t){y.location.href=e.toURL(),S.readyState=S.DONE,v(S,"writeend",t),l(e)},n.onerror=function(){var e=n.error;e.code!==e.ABORT_ERR&&b()},"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=S["on"+e]}),n.write(t),S.abort=function(){n.abort(),S.readyState=S.DONE},S.readyState=S.WRITING}),b)}),b)};e.getFile(u,{create:!1},g(function(e){e.remove(),n()}),g(function(e){e.code===e.NOT_FOUND_ERR?n():b()}))}),b)}),b)):void b())},y=w.prototype,m=function(e,t,n){return new w(e,t,n)};return"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob?function(e,t,n){return n||(e=p(e)),navigator.msSaveOrOpenBlob(e,t||"download")}:(y.abort=function(){var e=this;e.readyState=e.DONE,v(e,"abort")},y.readyState=y.INIT=0,y.WRITING=1,y.DONE=2,y.error=y.onwritestart=y.onprogress=y.onwrite=y.onabort=y.onerror=y.onwriteend=null,m)}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return saveAs}); \ No newline at end of file diff --git a/js/l3d/apps/prototype/GlobalFunctions.js b/js/l3d/apps/prototype/GlobalFunctions.js index 91dbf0e..c2dec9f 100644 --- a/js/l3d/apps/prototype/GlobalFunctions.js +++ b/js/l3d/apps/prototype/GlobalFunctions.js @@ -30,7 +30,9 @@ function objectClickerOnHover(camera1, previewer, recommendations, container) { var hoveredCamera = null; - return function(obj, x, y) { + return function(c, x, y) { + + var obj = c !== undefined ? c.object : undefined; // Check if the object is clickable var ok = obj instanceof Coin || obj instanceof L3D.BaseRecommendation; @@ -80,9 +82,10 @@ function objectClickerOnHover(camera1, previewer, recommendations, container) { function objectClickerOnClick(camera1, buttonManager, recommendations, coins) { - return function(obj, x, y) { + return function(c, x, y) { var event; + var obj = c !== undefined ? c.object : undefined; // Do stuff for click if (obj instanceof Coin) { diff --git a/js/l3d/apps/prototype/coin-creator/main.js b/js/l3d/apps/prototype/coin-creator/main.js new file mode 100644 index 0000000..35f4013 --- /dev/null +++ b/js/l3d/apps/prototype/coin-creator/main.js @@ -0,0 +1,258 @@ +// Let's be sure we avoid using global variables +var onWindowResize = (function() { + +// Disable scrolling +window.onscroll = function () { window.scrollTo(0, 0); }; +document.addEventListener('contextmenu', function(e) { + e.preventDefault(); +}); +window.onload = main; + +var stats; +var renderer, scene, container; +var clickableObjects = []; +var recommendations, objectClicker; +var previewer; +var camera1; +var coins = []; +var previousTime; +var pointer; +var startCanvas; + +saveCoins = function() { + + var result = '['; + + for (var i = 0; i < coins.length - 1; i++) { + result += JSON.stringify(coins[i].mesh.position) + ','; + } + result += JSON.stringify(coins[coins.length-1].mesh.position) + ']'; + + var blob = new Blob([result], {type: "text/plain;charset=utf-8"}); + saveAs(blob, "coins.js"); + +}; + +function main() { + + // Main container that holds everything + container = document.getElementById('container'); + + // Initialization + initThreeElements(); + initCanvases(); + initModels(); + initListeners(); + + appendTo(container)(stats, startCanvas, pointer, previewer, renderer); + + // Set the good size of cameras + onWindowResize(); + + // Some config + if (initMainScene !== L3D.initPeach && initMainScene !== L3D.initSponza) + setInterval(function() {logfps(stats.getFps());}, 500); + else + L3D.BD.disable(); + + Coin.update(); + startCanvas.render(L3D.StartCanvas.Black); + + // Bind previewer to renderer (for fixed option) + function bind() { + if (document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement) { + // Lock event + previewer.fixed = true; + } else { + // Unlock event + previewer.fixed = false; + } + } + document.addEventListener('pointerlockchange', bind); + document.addEventListener('mozpointerlockchange', bind); + document.addEventListener('webkitpointerlockchange', bind); + + // Start rendering + setInterval(render, 20); + +} + +function initThreeElements() { + + // Initialize scene + scene = new THREE.Scene(); + renderer = new THREE.WebGLRenderer({alpha:true, antialias:true}); + renderer.setClearColor(0x87ceeb); + + // Initialize pointer camera + camera1 = new L3D.PointerCamera( + 50, + container_size.width() / container_size.height(), + 0.01, 100000, renderer, container + ); + +} + +function initCanvases() { + + // Initialize previewer + previewer = new L3D.Previewer(renderer, scene); + previewer.domElement.style.position ="absolute"; + previewer.domElement.style.cssFloat = 'top-left'; + + // Initialize stats counter + stats = new Stats(); + stats.setMode(0); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.cssFloat = "top-left"; + + // Initialize pointer for pointer lock + pointer = new L3D.MousePointer(camera1); + + // Init start canvas + startCanvas = new L3D.StartCanvas(camera1); + +} + +function initModels() { + + // Init recommendations + recommendations = initMainScene(camera1, scene, coins, clickableObjects); + + // Erase coins and recommendations + var i = 0; + for (i =0; i < recommendations.length; i++) + recommendations[i].traverse(function(obj) {obj.visible = false;}); + recommendations = []; + + // init clickable objects + function hide(coins, i) { + setTimeout(function() {coins[i].mesh.visible = false;}, 1000); + } + + for (i = 0; i < coins.length; i++) { + hide(coins, i); + } + // coins = []; + + +} + +function initListeners() { + + // Add listeners + window.addEventListener('resize', onWindowResize, false); + + // HTML Bootstrap buttons + buttonManager = new ButtonManager(camera1, recommendations, previewer); + + // Object clicker for hover and clicking recommendations + objectClicker = new L3D.ObjectClicker( + renderer, + camera1, + clickableObjects, + objectClickerOnHover(camera1, previewer, recommendations, container), // Create onHover function + + // onclick + function(c, x, y, event) { + + if (event.button !== 2) + return; + + if (c !== undefined) { + + if (c.object instanceof Coin) { + + c.object.mesh.visible = false; + c.object.raycastable = false; + + } else { + + var newPosition = c.point.clone(); + var direction = L3D.Tools.diff(newPosition, camera1.position); + direction.normalize(); + direction.multiplyScalar(0.2); + newPosition.sub(direction); + var coin = new Coin(newPosition.x, newPosition.y, newPosition.z, function() {}); + coin.addToScene(scene); + coins.push(coin); + clickableObjects.push(coin); + + } + + } + }, + container + ); + +} + +function render() { + + // Stats for render + stats.begin(); + + objectClicker.update(); + + // Update recommendations (set raycastable if shown) + recommendations.map(function(reco) { + if (reco instanceof Recommendation) { + reco.traverse(function(elt) { + elt.visible = elt.raycastable = buttonManager.showArrows; + }); + } + }); + + // Update coins + coins.forEach(function(coin) { coin.update(); }); + + // Update main camera + var currentTime = Date.now() - previousTime; + camera1.update(isNaN(currentTime) ? 20 : currentTime); + previousTime = Date.now(); + + // Update the recommendations + recommendations.map(function(reco) { reco.update(camera1);}); + + // Set current position of camera + camera1.look(); + + var left = 0, bottom = 0, width = container_size.width(), height = container_size.height(); + renderer.setScissor(left, bottom, width, height); + renderer.enableScissorTest(true); + renderer.setViewport(left, bottom, width, height); + renderer.render(scene, camera1); + + // Remove borders of preview + previewer.clear(); + + // Hide arrows in recommendation + recommendations.map(function(reco) { if (reco instanceof Recommendation) hide(reco); }); + + // Update transparent elements + THREEx.Transparency.update(camera1); + + // Render preview + previewer.render(container_size.width(), container_size.height()); + + // Finish stats + stats.end(); + +} + +function onWindowResize() { + + resizeElements(renderer, container, previewer, pointer, startCanvas); + + recommendations.forEach(function(reco) { + resetCameraAspect(reco.camera, container_size.width(), container_size.height()); + }); + + render(); + +} + +// onWindowResize will be the only global function +return onWindowResize; + +})(); diff --git a/js/l3d/src/recommendations/ArrowRecommendation.js b/js/l3d/src/recommendations/ArrowRecommendation.js index 9170998..46e384a 100644 --- a/js/l3d/src/recommendations/ArrowRecommendation.js +++ b/js/l3d/src/recommendations/ArrowRecommendation.js @@ -8,4 +8,3 @@ L3D.ArrowRecommendation = function(arg1, arg2, arg3, arg4, position, target) { }; L3D.ArrowRecommendation.prototype = Object.create(L3D.BaseRecommendation.prototype); L3D.ArrowRecommendation.prototype.constructor = L3D.ArrowRecommendation; - diff --git a/js/l3d/src/scenes/initScene.js b/js/l3d/src/scenes/initScene.js index 6b3141b..68e1093 100644 --- a/js/l3d/src/scenes/initScene.js +++ b/js/l3d/src/scenes/initScene.js @@ -277,20 +277,20 @@ L3D.createBobombRecommendations = function(width, height) { }; -L3D.initBobomb = function(recommendation, scene, coins, clickable) { +L3D.initBobomb = function(camera, scene, coins, clickable) { L3D.addLight(scene); var collidableObjects = []; - L3D.initBobombScene(scene, collidableObjects, recommendation, clickable); + L3D.initBobombScene(scene, collidableObjects, camera, clickable); - recommendation.resetElements = L3D.resetBobombElements(); - recommendation.collidableObjects = collidableObjects; + camera.resetElements = L3D.resetBobombElements(); + camera.collidableObjects = collidableObjects; - recommendation.speed = 0.005; - recommendation.reset(); - recommendation.save(); + camera.speed = 0.005; + camera.reset(); + camera.save(); - scene.add(recommendation); + scene.add(camera); Coin.init(); var tmp = L3D.createBobombCoins(); diff --git a/js/l3d/src/utils/ObjectClicker.js b/js/l3d/src/utils/ObjectClicker.js index 68ce5da..5255fc1 100644 --- a/js/l3d/src/utils/ObjectClicker.js +++ b/js/l3d/src/utils/ObjectClicker.js @@ -87,7 +87,15 @@ var ObjectClicker = function(renderer, camera, objects, onHover, onClick, domEle // Add event listeners var self = this; this.domElement.addEventListener('mousemove', function(event) { self.update(event); }); - this.domElement.addEventListener('click', function(event) { self.click(event); }); + + if (navigator.userAgent.indexOf("Firefox") > 0) { + // If firefox + this.domElement.addEventListener('mousedown', function(event) {self.click(event); }); + } else { + // If chrome + this.domElement.addEventListener('click', function(event) { self.click(event); }); + this.domElement.addEventListener('contextmenu', function(event) { event.button = 2; self.click(event); }); + } }; @@ -120,7 +128,7 @@ ObjectClicker.prototype.getPointedObject = function() { for (var i = 0; i < intersects.length && !intersects[i].object.raycastable; i++){} // Objects are sorted by distance in intersects, the best is the first - return intersects[i] !== undefined ? intersects[i].object : undefined; + return intersects[i]; }; @@ -158,9 +166,9 @@ ObjectClicker.prototype.update = function(event) { /** * Calls onClick on the current pointed element */ -ObjectClicker.prototype.click = function() { +ObjectClicker.prototype.click = function(event) { - this.onClick(this.currentPointedObject, this.mouse.x, this.mouse.y); + this.onClick(this.currentPointedObject, this.mouse.x, this.mouse.y, event); };