Some cleaning 😢

This commit is contained in:
Thomas FORGIONE
2015-11-13 10:36:54 +01:00
parent 59518eb702
commit 5e0a6c3121
113 changed files with 433 additions and 67 deletions

17
server/403/index.html Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Deploy in progress. Please try again in few minutes</title>
<style type="text/css" />
body {color: #666; text-align: center; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; sans-serif; margin:0; width: 800px; margin: auto; font-size: 14px; }
h1 { font-size: 56px; line-height: 100px; font-weight: normal; color: #456; }
h2 { font-size: 24px; color: #666; line-height: 1.5em; }
h3 { color: #456; font-size: 20px; font-weight: normal; line-height: 28px; }
hr { margin: 18px 0; border: 0; border-top: 1px solid #EEE; border-bottom: 1px solid white; }
</style>
</head>
<body>
<h1><center><img alt="" src="https://raw.githubusercontent.com/tforgione/3dinterface/master/403/working.gif"/></center>I'm working on it</h1>
<h3>Please try again in few minutes.</h3>
</body>
</html>

BIN
server/403/working.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

View File

@@ -0,0 +1,9 @@
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/before-begin': 'index',
};

View File

@@ -0,0 +1,24 @@
extends ../../../views/base.jade
block content
h1 Now, things are getting serious
p.
You have successfully completed the tutorial ! Congratulations ! Now, things are getting
serious.
p.
You will be prompted with three successive scenes, each of which
containing 8 red coins. Your mission is simple: you have to collect the
8 red coins.
p.
There may be recommendations like the ones you saw in the tutorial :
they are here to help you navigate in the scene. Use them or ignore
them at your convenience.
button#next.btn.btn-success.navbar-btn(style={'margin-right':'10px', 'margin-bottom':'10px'})
span Go to the next step
script.
document.getElementById('next').onclick = function() {
document.getElementById('next').disabled = true;
window.location = '/prototype/play';
}

View File

@@ -0,0 +1,7 @@
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/bouncing' : 'index'
};

View File

@@ -0,0 +1,13 @@
extends ../../../views/withjs
block title
title #{title} - Bouncing cube
block extrajs
script(src="/static/js/bouncing.min.js")
block content
h2 Bouncing cube
p Click on the cube to make it jump !
#container

View File

@@ -0,0 +1,12 @@
var db = require('../prototype/dbrequests.js');
module.exports.index = function(req, res) {
db.verifyUser(req.session.userId, function() {});
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/feedback': 'index',
};

View File

@@ -0,0 +1,85 @@
extends ../../../views/base.jade
mixin message
span(style={'margin-bottom':'10px', 'margin-right': '10px'})
block
br
mixin question(id, qu, info)
label(for="#{id}", style={'margin-right':'10px'}) #{qu}
if (info !== undefined)
span.glyphicon.glyphicon-question-sign(type='button', data-toggle='tooltip', data-placement='top', title='#{info}')
input.form-control(name="answer#{id}", type="text", placeholder="Answer")
mixin rate(id, qu, info)
div
label(for="anwser#{id}", style={'margin-right':'10px'}) #{qu}
if (info !== undefined)
span.glyphicon.glyphicon-question-sign(type='button', data-toggle='tooltip', data-placement='top', title='#{info}')
//-input.rating(id="answer#{id}", name="answer#{id}", type="number", min='0', max='5', step='1', default='3')
br
input(type='radio', name='answerItem#{id}', value='1', style={'margin-right':'10px'})
+message Very easy
input(type='radio', name='answerItem#{id}', value='2', style={'margin-right':'10px'})
+message Easy
input(type='radio', name='answerItem#{id}', value='3', style={'margin-right':'10px'})
+message Medium
input(type='radio', name='answerItem#{id}', value='4', style={'margin-right':'10px'})
+message Hard
input(type='radio', name='answerItem#{id}', value='5', style={'margin-right':'10px'})
+message Very hard
div(style={'margin-bottom':'10px'})
block extrahead
link(rel="stylesheet", href="/static/css/feedback.css")
link(rel="stylesheet", href="/static/css/star-rating.min.css")
//-block extrajs
script(src="/static/js/star-rating.min.js")
script $(function () { $('[data-toggle="tooltip"]').tooltip() })
script.
var liste = [1,2];
for (var i = 0; i < liste.length; i++) {
$("#answer" + liste[i]).rating({showClear: false, showCaption: false, size:'xs'});
$("#answer" + liste[i]).rating('update', 3);
}
block content
script.
function checkForm() {
var allAnswered = true;
$("input:radio").each(function(){
var name = $(this).attr("name");
if($("input:radio[name="+name+"]:checked").length == 0)
{
allAnswered = false;
}
});
$("input:text").each(function(){
if ($(this).val().length === 0) {
allAnswered = false;
}
});
if (!allAnswered) {
alert('You did not answer all the questions');
return false;
}
}
form.form-signin(method="POST", action='/feedback-target', onsubmit='return checkForm()')
h2 Please give us your feedback
+rate(1, "What was the difficulty level WITHOUT recommendation ?")
+rate(2, "What was the difficulty level WITH recommendation ?")
+question(3, "Did the recommendations help you to find the coins ?")
+question(4, "Did the recommendations help you to browse the scene ?")
+question(5, "Do you think recommendations can be helpful ?")
+question(6, "Which recommendation style do you prefer and why ?")
+question(7, "Did you enjoy this ?")
//-label(for='input1') Did you have trouble to find the coins during the first step ?
//-input#input1.form-control(name="input1", type="text", placeholder='Id')
button.btn.btn-lg.btn-primary.btn-block(type='submit') Submit

View File

@@ -0,0 +1,7 @@
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, out) {
res.send(out);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/': 'index'
};

View File

@@ -0,0 +1,41 @@
extends ../../../views/main
block title
title #{title} - Index
block content
h2 Index
ul
li
a(href="#{urls.bouncing}") A bouncing cube that jumps when you click on it
p.
Jumps and bounce when you click on it.
li
a(href="#{urls.multisphere}") Sphere with multi-resolution
p.
Lots of obj files loaded and displayed. When you click
somewhere, the current obj is hidden and the next one, with a
better resolution is shown.
li
a(href="#{urls.prototype}") A proto of the real thing
p.
You can move the camera with the arrow keys and move the angle of
the camera with 2, 4, 6 and 8 (the arrows of the numpad), or you
can do a drag-and-drop like (click on the mouse to grap the scene,
and move the mouse to rotate the camera). You can also select a
camera by clicking on the red part of it, and get back to the free
camera by clicking again. You can also select a camera by simply
clicking on the object you want to see. The program will choose the
camera that you want, and move to it progressively.
li
a(href="#{urls.stream}") Sphere streaming
p.
Streaming of 3D obj model of sphere
li
a(href="#{urls.sponza}") Sponza streaming
p.
If you like streaming big models !

View File

@@ -0,0 +1,12 @@
module.exports.index = function(req, res) {
req.session.workerId = req.params.workerId;
req.session.save();
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,4 @@
module.exports = {
'/intro': 'index',
'/intro/:workerId': 'index',
};

View File

@@ -0,0 +1,20 @@
extends ../../../views/base.jade
block content
h1 Welcome !
p This study consists in four consecutive steps :
ol
li Enter some personal information that we will use for statistics purposes
li Complete a tutorial to learn how to use the 3D navigation interface
li Play a game in which you have to find coins hidden in a 3D world. You need to play the game in 3 different scenes.
li Complete a short questionnaire to give us feedback on the 3D navigation interface
h2#start
block extrajs
script.
var isOpera = window.navigator.userAgent.indexOf("OPR") > -1 || window.navigator.userAgent.indexOf("Opera") > -1;
if (($.browser.chrome || $.browser.mozilla) && !isOpera) {
$('#start').html('You can now <a href="/user-study">start when you are ready</a>');
} else {
$('#start').html('Sorry, your browser is not compatible... please try again with Firefox or Chrome');
}

View File

@@ -0,0 +1,7 @@
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, out) {
res.send(out);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/list': 'index'
};

View File

@@ -0,0 +1,10 @@
extends ../../../views/main
block title
title #{title} - Test
block extrajs
script(src='/static/js/ListTest.min.js')
block content
Hello

View File

@@ -0,0 +1,7 @@
module.exports.index = function(req, res) {
req.session = null;
res.locals.session = null;
res.redirect('/');
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/logout': 'index'
};

View File

@@ -0,0 +1,7 @@
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/multisphere': 'index'
};

View File

@@ -0,0 +1,19 @@
extends ../../../views/main.jade
block title
title #{title} - Multi-sphere
block extrajs
script(src="/static/js/three.min.js")
script(src="/static/js/l3d.min.js")
script(src="/static/js/multisphere.min.js")
block content
h2 Multiresolution sphere
p.
This is the first test of multi-resolution. In fact, it's not really one
multi-resolution sphere but many spheres with different resolutions. You
can change resolution by clicking on the canvas.
#container

1650
server/controllers/prototype/dbrequests.js vendored Normal file

File diff suppressed because it is too large Load Diff

278
server/controllers/prototype/index.js vendored Normal file
View File

@@ -0,0 +1,278 @@
var tools = require('../../lib/filterInt');
var pg = require('pg');
var pgc = require('../../private');
var db = require('./dbrequests');
module.exports.index = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};
var sceneToFunction = function(scene) {
switch (scene) {
case 2:
return 'L3D.initBobomb';
case 3:
return 'L3D.initMountain';
case 4:
return 'L3D.initWhomp';
default:
return 'L3D.initPeach';
}
};
module.exports.game = function(req, res) {
req.session.experiments = req.session.experiments || [];
req.session.save();
db.checkUserId(req.session.userId, function(ok) {
if (ok) {
db.createExp(
req.session.userId,
req.session.experiments,
function(expId, sceneId, coinCombinationId, recommendationStyle, coins) {
// if (expId === undefined) {
// req.session.finished = true;
// req.session.save();
// return;
// }
// req.session.expId = expId;
// req.session.save();
// res.locals.scene = sceneToFunction(sceneId);
// res.locals.recommendationStyle = recommendationStyle;
// res.locals.coins = coins;
// res.setHeader('Content-Type','text/html');
// res.send("Ok");
});
} else {
}
});
};
module.exports.play = function(req, res) {
req.session.counter = req.session.counter === undefined ? 0 : req.session.counter + 1;
req.session.save();
if (req.session.counter > 2) {
res.redirect('/feedback');
return;
}
req.session.experiments = req.session.experiments || [];
db.getLastExp(req.session.userId, function(expId, sceneId, coinId, recoStyle, coins) {
// if (coinId === undefined) {
// console.log("=== ERROR : COIN_ID IS UNDEFINED ===");
// process.exit(-1)
// }
res.locals.scene = sceneToFunction(sceneId);
res.locals.recommendationStyle = recoStyle;
res.locals.coins = coins;
// var elt = req.session.experiments.find(function(elt) {
// return elt.coinCombinationId === coinId;
// });
// if (elt !== undefined) {
// console.log("=== ERROR DETECTED === user " + req.session.userId);
// console.log(req.session.experiments);
// console.log(coinId);
// process.exit(-1)
// }
req.session.experiments.push({
sceneId: sceneId,
recommendationStyle: recoStyle,
coinCombinationId : coinId
});
req.session.expId = expId;
req.session.save();
// Prepare next experiment
module.exports.game(req, null);
res.setHeader('Content-Type', 'text/html');
res.render('prototype_recommendation.jade', res.locals, function(err, result) {
res.send(result);
});
});
};
module.exports.sponza = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.render('sponza.jade', res.locals, function(err, result) {
res.send(result);
});
};
module.exports.replayInfo = function(req, res) {
res.setHeader('Content-Type', 'text/plain');
// Parse id
var id = tools.filterInt(req.params.id);
db.getInfo(id, function(results) {
res.send(JSON.stringify(results));
});
};
module.exports.replay = function(req, res, next) {
// Get id parameter
res.locals.id = tools.filterInt(req.params.id);
if (res.locals.id <= 0) {
var err = new Error("This replay does not exist");
err.status = 404;
next(err);
return;
}
db.checkExpId(res.locals.id, function(sceneId) {
if (sceneId === null) {
var err = new Error("This replay does not exist");
err.status = 404;
next(err);
} else {
res.locals.initjs = sceneToFunction(sceneId);
res.setHeader('Content-Type', 'text/html');
res.render('prototype_replays.jade', res.locals, function(err, result) {
res.send(result);
});
}
});
};
module.exports.replayIndex = function(req, res, next) {
db.getAllExps(function(result) {
res.locals.users = result;
res.setHeader('Content-Type', 'text/html');
res.render("replay_index.jade", res.locals, function(err, result) {
res.send(result);
});
});
};
module.exports.tutorial = function(req, res) {
if (req.session.tutorialDone) {
res.redirect('/before-begin');
return;
}
db.checkUserId(req.session.userId, function(ok) {
if (ok) {
// 1 is the ID of peach scene
db.createTutorial(req.session.userId, function(id, coins) {
// Generate next experiment
module.exports.game(req, null);
req.session.tutorialDone = true;
req.session.expId = id;
res.locals.coins = coins;
req.session.save();
res.setHeader('Content-Type', 'text/html');
res.render('tutorial.jade', res.locals, function(err, result) {
res.send(result);
});
});
} else {
res.redirect('/');
}
});
};
function editorHelper(templateName) {
return 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(templateName, res.locals, function(err, result) {
res.send(result);
});
};
}
module.exports.clicker = editorHelper('prototype_clicker.jade');
module.exports.viewer = editorHelper('prototype_viewer.jade');
module.exports.checker = editorHelper('prototype_checker.jade');
module.exports.userstudy = function(req, res) {
if (req.session.userId !== undefined) {
res.redirect('/prototype/tutorial');
return;
}
res.locals.identificationFailed = req.session.identificationFailed;
req.session.identificationFailed = false;
req.session.save();
res.locals.workerId = req.session.workerId;
res.setHeader('Content-Type', 'text/html');
res.render('user_study.jade', res.locals, function(err, result) {
res.send(result);
});
};
module.exports.next = function(req, res) {
res.redirect('/prototype/game');
};

15
server/controllers/prototype/urls.js vendored Normal file
View File

@@ -0,0 +1,15 @@
module.exports = {
'/prototype': 'index',
'/prototype/game': 'game',
'/prototype/replay': 'replayIndex',
'/prototype/replay/:id': 'replay',
'/prototype/replay-info/:id': 'replayInfo',
'/prototype/tutorial': 'tutorial',
'/prototype/sponza': 'sponza',
'/prototype/coin-creator/:scene': 'clicker',
'/prototype/coin-viewer/:scene': 'viewer',
'/prototype/coin-checker/:scene': 'checker',
'/user-study': 'userstudy',
'/prototype/next': 'next',
'/prototype/play': 'play'
};

View File

@@ -0,0 +1,17 @@
extends ../../../views/main
block title
title #{title} - Prototype
block content
h2 Index
p The tutorial is available <a href="#{urls.tutorial}">here</a>.
p There are three prototypes here :
ul
li
a(href="arrows/") Arrows
li
a(href="reverse/") Reversed arrows looking like funnel
li
a(href="viewports/") Viewports
p You can also watch replays of previous experiences <a href="#{urls.replayIndex}">here</a>.

View File

@@ -0,0 +1,54 @@
extends ../../../views/withjs
block title
title #{title} - Prototype
block extrajs
script(src="/static/js/l3dp.min.js")
block configjs
block mainjs
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")

View File

@@ -0,0 +1,15 @@
extends ./prototype
block title
title #{title} - Prototype
block mainjs
script initMainScene = #{scene};
script Recommendation = L3D.ArrowRecommendation;
script(src="/static/js/coinchecker.min.js")
block extrabutton
//-button#save.btn.btn-primary.navbar-btn(style={'margin-right': '10px', 'margin-bottom':'10px'}, onclick="saveCoins();") Save coins
button#coins-remaining.btn.btn-primary.navbar-btn(style={'margin-right':'10px', 'margin-bottom':'10px'}) Lol coins remaining

View File

@@ -0,0 +1,14 @@
extends ./prototype
block title
title #{title} - Prototype
block mainjs
script initMainScene = #{scene};
script Recommendation = L3D.ArrowRecommendation;
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

View File

@@ -0,0 +1,53 @@
extends ./prototype
block title
title #{title} - Prototype
block mainjs
script initMainScene = #{scene};
script locked = #{session.locked === undefined ? 'true' : session.locked};
script(src="/static/js/prototypeinteractive.min.js")
block description
//-#instructions.panel.panel-default
.panel-heading
h4.panel-title
a(href="#", data-target="#collapseInstructions", data-toggle="collapse",onclick="setTimeout(onWindowResize,500);") Instructions
.panel-collapse.collapse.in#collapseInstructions
.panel-body
p
| This is the prototype of a 3D interface. You can move
| the camera with the arrow keys of your keyboard (or
| WASD if you like FPS-games, and by the way, if you
| use azerty keyboard, you can also use ZQSD instead),
| and change the angle of the camera by dragging and
| dropping the scene around it (you can also use your
| numpad, 2 to look lower, 8 to look higher, 4 to look
| on the left and 6 to look on the right, but if you're
| more comfortable with non-numpad keys, you can also
| use i for up, j for left, k for down, and l for
| right).
p
| This is a re-creation of the Bob-omb Battlefield
| level from Super Mario 64, and with its 8 red coins.
| You can click on them to get them, and once you got
| them all, you get... well you get nothing but the
| sound of the star is played (but the star doesn't
| appear... sorry guys)
p
| It contains <em>recommended views</em> : 3D objects
| here to guide you through this coin search.
block preciseDescription
p
| You can click on a recommendation to move to the
| recommended viewpoint. The recommendation will become
| more and more transparent as you come closer, and
| will disappear when you reach it.
p
| You may now <a href="#" data-target="#collapseInstructions" data-toggle="collapse" onclick="setTimeout(onWindowResize,500);">hide this panel</a> and start playing !

View File

@@ -0,0 +1,18 @@
extends ./prototype_interactive
block title
title #{title} - Prototype - Arrows
block configjs
script Recommendation = #{recommendationStyle}; coinsId = [#{coins}];
block lastbutton
button#next.btn.btn-success.navbar-btn(style={'margin-right':'10px', 'margin-bottom':'10px', 'display':'none'})
span Go to the next step
//-block preciseDescription
p
| Recommended views are displayed with a
| transparent blue arrow. They disappear when you
| come closer to them, and shows the motion between
| your current position and the recommendation.

View File

@@ -0,0 +1,21 @@
extends ../../../views/withjs
block title
title #{title} - Prototype
block prepend js
script DB_DISABLED = true;
block extrajs
script Recommendation = L3D.ArrowRecommendation;
script var params = params || {}; params.get = params.get || {}; params.get.id = #{id};
script initMainScene = #{initjs}
script(src="/static/js/l3dp.min.js")
script(src="/static/js/replay.min.js")
block extrahead
link(rel="stylesheet" href="/static/css/prototype.css")
block content
#main-div.panel-group(style={'margin-top':'10px', 'margin-bottom':'10px'})
#container(style={'padding': '0px', 'margin': '0px'}, tabindex="1")

View File

@@ -0,0 +1,17 @@
extends ./prototype_interactive
block title
title #{title} - Prototype - Reverse
block configjs
script Recommendation = L3D.ReverseRecommendation;
//-block preciseDescription
p
| Recommended views are displayed with a strange
| blue object. Basically, the curve at the
| begining of this weird object shows the motion
| that starts from where you are and leads to the
| recommended view, and the extremity is in fact an
| object representing a camera.

View File

@@ -0,0 +1,14 @@
extends ./prototype
block title
title #{title} - Prototype
block mainjs
script initMainScene = #{scene};
script Recommendation = L3D.ArrowRecommendation;
script(src="/static/js/coinviewer.min.js")
block extrabutton
button#save.btn.btn-primary.navbar-btn(style={'margin-right': '10px', 'margin-bottom':'10px'}, onclick="saveCoins();") Save coins

View File

@@ -0,0 +1,13 @@
extends ../../../views/main
block title
title #{title} - Prototype - Replays
block content
h2 Replays available
if users.length == 0
p Sorry, there are no replays available... try later or do an experiment !
else
ol
each elt in users
li <a href="/prototype/replay/#{elt.expId}">User <em>#{elt.username} (#{elt.userId})</em> for scene <em>#{elt.scenename}</em></a>

View File

@@ -0,0 +1,22 @@
extends ./prototype_interactive
block title
title #{title} - Prototype - Arrows
block prepend js
script window.DB_DISABLED = true;
block mainjs
script locked = false;
script(src="/static/js/prototypeinteractive.min.js")
script initMainScene = L3D.initSponza
block configjs
script Recommendation = L3D.ArrowRecommendation;
//-block preciseDescription
p
| Recommended views are displayed with a
| transparent blue arrow. They disappear when you
| come closer to them, and shows the motion between
| your current position and the recommendation.

View File

@@ -0,0 +1,15 @@
extends ./prototype
block append extrahead
link(rel="stylesheet", href="/static/css/tutorial.css")
block title
title #{title} - Prototype - Tutorial
block configjs
script Recommendation = L3D.ArrowRecommendation; coinsId = [#{coins}];
script(src="/static/js/tutorial.min.js")
block lastbutton
button#next.btn.btn-success.navbar-btn(style={'margin-right':'10px', 'margin-bottom':'10px', 'display':'none'})
span Go to the next step

View File

@@ -0,0 +1,107 @@
extends ../../../views/base.jade
block extrahead
link(rel="stylesheet", href="/static/css/signin.css")
link(rel="stylesheet", href="/static/css/star-rating.min.css")
block extrajs
script(src="/static/js/star-rating.min.js")
script.
$('#3dgames').rating({
showClear: false,
showCaption: false,
size: 'xs'
});
$('#3dgames').rating('update', 3);
script $(function () { $('[data-toggle="tooltip"]').tooltip() })
block extrabody
if identificationFailed
.container
.alert.alert-danger.alert-dismissible(role="alert", style={'margin-top':'20px'})
button.close(type="button", data-dismiss="alert", aria-label="Close")
span(aria-hidden="true") &times;
<strong>Error</strong> : this id is already used !
block content
script.
function validateForm() {
if (document.getElementById('sel1').selectedIndex === -1) {
alert('Select a correct age please');
return false;
}
if (document.getElementById('sel2').selectedIndex === -1) {
alert('Select a correct date for the last time you played please');
return false;
}
return true;
}
form#form.form-signin(method="POST", action='/identification')
h2 Please sign in
label(for='inputId').sr-only Id
if (workerId === undefined)
input#inputId.form-control(name="inputId", type="text", placeholder='Id', required, autofocus)
else
input#inputId.form-control(name="inputId", type="text", placeholder='Id', required, autofocus, disabled, value="#{workerId}")
.form-group
label Gender
.form-group
label.radio-inline
input(type='radio', name='inputGender', value="male", checked)
| Male
label.radio-inline
input(type='radio', name='inputGender', value="female")
| Female
.form-group
label(for='sel1') How old are you ?
select.form-control#sel1(name="inputAge")
option(value='-15') Less than 15
option(value='15-20') Between 15 and 18
option(value='18-25') Between 18 and 25
option(value='25-30') Between 25 and 30
option(value='30-35') Between 30 and 35
option(value='35-40') Between 35 and 40
option(value='40-45') Between 40 and 45
option(value='45-50') Between 45 and 50
option(value='50-55') Between 50 and 55
option(value='55-60') Between 55 and 60
option(value='60-') More than 60
script.
document.getElementById('sel1').selectedIndex = -1;
.form-group
label(for='se21', style={'margin-right':'10px'}) When is the last time you played a 3D video game ?
span.glyphicon.glyphicon-question-sign(type='button', data-toggle='tooltip', data-placement='top', title='Any game will count (PC or console, old or recent)')
select.form-control#sel2(name="inputLastTime")
option(value='3') This week
option(value='2') This month
option(value='1') This year
option(value='0') I never played a 3D video game
script.
document.getElementById('sel2').selectedIndex = -1;
label(for='3dgames', style={'margin-right':'10px'}) Rate your 3D game skills
ul
li 1 star if you never play video games
li 2 stars if you rarely play games
li 3 stars if you are used to play console (PlayStation, Xbox, Nintendo, portable devices included)
li 4 stars if you are used to play first-person-view games
li 5 stars if you are good at first-person-view games
input#3dgames(type='number', class='rating', min='0', max='5', step='1', default='3', name='input3dskills')
button#submitButton.btn.btn-lg.btn-primary.btn-block(type='submit') Sign in
script.
document.getElementById('submitButton').onclick = function(event) {
event.preventDefault();
document.getElementById('submitButton').disabled = true;
if (validateForm()) {
document.getElementById('form').submit();
} else {
document.getElementById('submitButton').disabled = false;
}
}

View File

@@ -0,0 +1,25 @@
var tools = require('../../lib/filterInt');
module.exports.index = function(req, res, next) {
// Parse get argument res
res.locals.resolution = req.params.res;
if (res.locals.resolution === undefined) {
res.locals.resolution = 5;
} else {
res.locals.resolution = tools.filterInt(res.locals.resolution);
}
if (isNaN(res.locals.resolution) || res.locals.resolution < 1 || res.locals.resolution > 25) {
var error = new Error("Resolution was not set properly");
error.status = 404;
next(error);
return;
}
res.setHeader('Content-Type', 'text/html');
res.render('index.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/stream/:res?': 'index'
};

View File

@@ -0,0 +1,48 @@
extends ../../../views/main
block title
title #{title} - Sphere streaming
block extrajs
script params = {}; params.get= {}; params.get.res = #{resolution}
script(src="/static/js/three.min.js")
script(src="/static/js/socket.io.min.js")
script(src="/static/js/l3d.min.js")
script(src="/static/js/streamingsimulator.min.js")
script(type='text/javascript').
$(function() {
var filterInt = function (value) {
if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value))
return Number(value);
return NaN;
}
$('#form').submit(function(e) {
e.preventDefault();
var val = filterInt(document.getElementById('num').value);
window.location.href = "/stream/" + val;
});
});
block content
h2 Sphere streaming
p.
<s>In fact, it's not really streaming. The sphere is fully preloaded
and then, a mesh is created and vertices and faces are dynamically
added to this mesh as time goes by.</s>
p.
In fact, it is acutally streaming. If you web browser supports
WebSocket, you'll connect to the server and the mesh will be streamed
onto the socket and the faces will be displayed as soon as you receive
them.
form.form-inline#form
.form-group
label Try another resolution (between 1 and 25)
input#num(type='number', min=1, max=25, value=5, style={"margin-left":"10px"})
.form-group
button#submit.btn.btn-primary(type='submit', style={"margin-left":"10px"}) Go
#container

View File

@@ -0,0 +1,25 @@
var db = require('../prototype/dbrequests.js');
var vcode = require('../../lib/vcode.js');
module.exports.index = function(req, res) {
// If not micro-worker
if (req.session.workerId === undefined) {
res.setHeader('Content-Type', 'text/html');
res.render('normal.jade', res.locals, function(err, result) {
res.send(result);
});
return;
}
res.setHeader('Content-Type', 'text/html');
res.render('vcode.jade', res.locals, function(err, result) {
res.send(result);
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/thankyou': 'index',
};

View File

@@ -0,0 +1,8 @@
extends ../../../views/base.jade
block content
h1 Thank you for everything !
audio(autoplay)
source(src="/static/data/music/thankyou.ogg")
source(src="/static/data/music/thankyou.mp3")

View File

@@ -0,0 +1,36 @@
extends ../../../views/base.jade
block content
h1 Thank you for everything !
audio(autoplay)
source(src="/static/data/music/thankyou.ogg")
source(src="/static/data/music/thankyou.mp3")
p We are verifying that the experiment was correctly done...
#vcode
script.
function tryVcode() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/vcode', true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if(xhr.status == 200) {
changeHtml(xhr.responseText);
}
}
};
xhr.send(null);
}
function changeHtml(vcode) {
if (vcode === 'not ready') {
setTimeout(tryVcode, 1000);
} else if (vcode === 'no vcode') {
$('#vcode').html('Sorry, the experiment has not been correctly done ! You have no vcode.');
} else {
$('#vcode').html('Your vcode is ' + vcode);
}
}
tryVcode();

View File

@@ -0,0 +1,39 @@
var db = require('../prototype/dbrequests.js');
var vcode = require('../../lib/vcode.js');
module.exports.index = function(req, res) {
// If not micro-worker
if (req.session.workerId === undefined) {
res.setHeader('Content-Type', 'text/html');
res.send(null);
return;
}
// Else, check that exp was correctly done
db.getUser(req.session.userId, function(workerId, ok) {
res.setHeader('Content-Type', 'text/html');
if (ok === true) {
var code = vcode(req.session.workerId);
res.send(code);
} else if (ok === false) {
res.send('no vcode');
} else {
res.send('not ready');
}
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/vcode': 'index',
};

12
server/geo/Geo.js Normal file
View File

@@ -0,0 +1,12 @@
var fs = require('fs');
/**
* @namespace
*/
var geo = {};
if (typeof module === 'object') {
module.exports = geo;
}

17
server/geo/Makefile Normal file
View File

@@ -0,0 +1,17 @@
OPT=--compilation_level SIMPLE_OPTIMIZATIONS
ifeq ($(TYPE),RELEASE)
CLOSURE=java -jar ../../utils/closure-compiler/closure-compiler.jar
else
CLOSURE=../../utils/simple-compiler/compiler.sh
endif
all: Geo
Geo:
$(CLOSURE) $(OPT) \
--js Geo.js \
--js Mesh.js \
--js MeshContainer.js \
--js MeshStreamer.js \
--js_output_file ../lib/geo.min.js

504
server/geo/Mesh.js Normal file
View File

@@ -0,0 +1,504 @@
/**
* Reprensents a mesh
* @constructor
* @memberOf geo
*/
geo.Mesh = function() {
this.vertices = [];
this.faces = [];
this.texCoords = [];
this.normals = [];
this.faceIndex = 0;
this.material = null;
this.started = false;
this.finished = false;
};
/**
* Checks if there are normals in the mesh
* @returns {Boolean} true if there are normals in the mesh, false otherwise
*/
geo.Mesh.prototype.hasNormals = function() {
return this.normals.length > 0;
};
/**
* Checks if there are texture coordinates in the mesh
* @returns {Boolean} true if there are texture coordinates in the mesh, false otherwise
*/
geo.Mesh.prototype.hasTexCoords = function() {
return this.texCoords.length > 0;
};
/**
* Adds a vertex to a mesh
* @param {geo.Vertex|String} A Vertex object or its string representation
*/
geo.Mesh.prototype.addVertex = function(vertex) {
if (vertex instanceof geo.Vertex) {
this.vertices.push(vertex);
} else if (typeof vertex === 'string' || vertex instanceof String) {
this.vertices.push(new geo.Vertex(vertex));
} else {
console.error("Can only add vertex from geo.Vertex or string");
return;
}
return this.vertices[this.vertices.length - 1];
};
/**
* Adds a face to a mesh
* @param {geo.Face|String} A Face object or its string representation
*/
geo.Mesh.prototype.addFaces = function(face) {
var faces;
if (face instanceof geo.Face) {
this.faces.push(face);
} else if (typeof face === 'string' || face instanceof String) {
faces = parseFace(face);
this.faces = this.faces.concat(faces);
} else {
console.error("Can only add face from geo.Face or string");
return;
}
if (faces === undefined) {
return this.faces[this.faces.length - 1];
} else {
return faces;
}
};
/**
* Adds a texture coordinate to a mesh
* @param {geo.TexCoord|String} A TexCoord object or its string representation
*/
geo.Mesh.prototype.addTexCoord = function(texCoord) {
if (texCoord instanceof geo.TexCoord) {
this.texCoords.push(texCoord);
} else if (typeof texCoord === 'string' || texCoord instanceof String) {
this.texCoords.push(new geo.TexCoord(texCoord));
} else {
console.error("Can only add texCoord from geo.TexCoord or string");
return;
}
return this.texCoords[this.texCoords.length - 1];
};
/**
* Adds a normal to a mesh
* @param {geo.Normal|String} A Normal object or its string representation
*/
geo.Mesh.prototype.addNormal = function(normal) {
if (normal instanceof geo.Normal) {
this.normals.push(normal);
} else if (typeof normal === 'string' || normal instanceof String) {
this.normals.push(new geo.Normal(normal));
} else {
console.error("Can only add normal from geo.Normal of string");
return;
}
return this.normals[this.normals.length - 1];
};
geo.Mesh.prototype.isFinished = function() {
return this.faceIndex === this.faces.length;
};
/**
* Represent a 3D vertex
* @constructor
* @memberOf geo
*/
geo.Vertex = function() {
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
/**
* x coordinate of the vertex
* @type {Number}
*/
this.x = parseFloat(split[1]);
/**
* y coordinate of the vertex
* @type {Number}
*/
this.y = parseFloat(split[2]);
/**
* z coordinate of the vertex
* @type {Number}
*/
this.z = parseFloat(split[3]);
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Gives a list representation of the vertex
* @returns {Array} An array representing the vertex
*
* @example
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
* vertex.index = 5;
* console.log(vertex.toList()); // Prints ['v', 5, 3.5, 3.6, 3.7]
*/
geo.Vertex.prototype.toList = function() {
return ['v', this.index, this.x, this.y, this.z];
};
/**
* Gives a string representation of the vertex
* @returns {string} A string representing the vertex
*
* @example
* var vertex = new geo.Vertex('v 3.5 3.6 3.7');
* console.log(vertex.toString()); // Prints v 3.5 3.6 3.7
*/
geo.Vertex.prototype.toString = function() {
return 'v ' + this.x + ' ' + this.y + ' ' + this.z;
};
/**
* Represent a 3D normal
* @constructor
* @memberOf geo
* @augments geo.Vertex
*/
geo.Normal = function() {
geo.Vertex.apply(this, arguments);
};
geo.Normal.prototype = Object.create(geo.Vertex.prototype);
geo.Normal.prototype.constructor = geo.Normal;
/**
* Gives a list representation of the normal
* @returns {Array} An array representing the normal
*
* @example
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
* normal.index = 5;
* console.log(normal.toList()); // Prints ['vn', 5, 3.5, 3.6, 3.7]
*/
geo.Normal.prototype.toList = function() {
var superObject = geo.Vertex.prototype.toList.call(this);
superObject[0] = 'vn';
return superObject;
};
/**
* Gives a string representation of the normal
* @returns {string} A string representing the normal
*
* @example
* var normal = new geo.Normal('vn 3.5 3.6 3.7');
* console.log(normal.toString()); // Prints vn 3.5 3.6 3.7
*/
geo.Normal.prototype.toString = function() {
var superObject = geo.Vertex.prototype.toString.call(this);
superObject.replace('v', 'vn');
return superObject;
};
/**
* Represent a texture coordinate element
* @constructor
* @memberOf geo
*/
geo.TexCoord = function() {
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
var split = arguments[0].replace(/\s+/g, " ").split(' ');
/**
* x coordinate of the texture
* @type {Number}
*/
this.x = parseFloat(split[1]);
/**
* y coordinate of the texture
* @type {Number}
*/
this.y = parseFloat(split[2]);
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Gives a list representation of the texture coordinate
* @returns {Array} An array representing the texture coordinate
*
* @example
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['vt', 5, 3.5, 3.6]
*/
geo.TexCoord.prototype.toList = function() {
return ['vt', this.index, this.x, this.y];
};
/**
* Gives a string representation of the texture coordinate
* @returns {string} A string representing the texture coordinate
*
* @example
* var texCoord = new geo.TexCoord('vt 3.5 3.6');
* console.log(texCoord.toString()); // Prints vt 3.5 3.6
*/
geo.TexCoord.prototype.toString = function() {
return 'vt ' + this.x + ' ' + this.y;
};
/**
* Represents a face
* @constructor
* @memberOf geo
*/
geo.Face = function() {
var split;
if (typeof arguments[0] === 'string' || arguments[0] instanceof String) {
if (arguments[0].indexOf('/') === -1) {
// No / : easy win : "f 1 2 3" or "f 1 2 3 4"
split = arguments[0].replace(/\s+/g, ' ').split(' ');
this.a = parseInt(split[1]) - 1;
this.b = parseInt(split[2]) - 1;
this.c = parseInt(split[3]) - 1;
} else {
// There might be textures coords
split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
// Split elements
var split1 = split[1].split('/');
var split2 = split[2].split('/');
var split3 = split[3].split('/');
var vIndex = 0;
var tIndex = 1;
var nIndex = 2;
/**
* index of the first vertex of the face
* @type {Number}
*/
this.a = parseInt(split1[vIndex]) - 1;
/**
* index of the second vertex of the face
* @type {Number}
*/
this.b = parseInt(split2[vIndex]) - 1;
/**
* index of the third vertex of the face
* @type {Number}
*/
this.c = parseInt(split3[vIndex]) - 1;
/**
* index of the texture coordinate of the first vertex of the face
* @type {Number}
*/
this.aTexture = parseInt(split1[tIndex]) - 1;
/**
* index of the texture coordinate of the second vertex of the face
* @type {Number}
*/
this.bTexture = parseInt(split2[tIndex]) - 1;
/**
* index of the texture coordinate of the third vertex of the face
* @type {Number}
*/
this.cTexture = parseInt(split3[tIndex]) - 1;
/**
* index of the normal of the first vertex of the face
* @type {Number}
*/
this.aNormal = parseInt(split1[nIndex]) - 1;
/**
* index of the normal of the second vertex of the face
* @type {Number}
*/
this.bNormal = parseInt(split2[nIndex]) - 1;
/**
* index of the normal of the third vertex of the face
* @type {Number}
*/
this.cNormal = parseInt(split3[nIndex]) - 1;
}
}
/**
* Indicates if the vertex has been sent or not
* @type {Boolean}
*/
this.sent = false;
};
/**
* Parse a face line and returns an array of faces
*
* @private
* @param {String} a string representing a face
* @returns {Face[]} a single 3-vertices face or two 3-vertices face if it was
* a 4-vertices face
*/
var parseFace = function(arg) {
var split = arg.trim().split(' ');
var ret = [];
// Face3
if (split.length >= 4) {
ret.push(new geo.Face(arg));
}
// Face3 == 2 * Face3
if (split.length >= 5) {
ret.push(new geo.Face(
[
split[0],
split[1],
split[3],
split[4]
].join(' ')
));
}
return ret;
};
/**
* Returns the max index of the vertices of the face
* @returns {Number} the max index of the vertices
*/
geo.Face.prototype.max = function() {
if (this.d !== undefined) {
return Math.max(this.a, this.b, this.c, this.d);
} else {
return Math.max(this.a, this.b, this.c);
}
};
/**
* Returns the max index of the texture coordinates of the face
* @returns {Number} the max index of the texture coordinates
*/
geo.Face.prototype.maxTexture = function() {
if (this.dTexture) {
return Math.max(this.aTexture, this.bTexture, this.cTexture, this.dTexture);
} else {
return Math.max(this.aTexture, this.bTexture, this.cTexture);
}
};
/**
* Gives a list representation of the face
* @returns {Array} An array representing the texture coordinate
* <ol start=0>
* <li>'f'</li>
* <li>the index of the face</li>
* <li>a list containing the indices of the vertex of the face</li>
* <li>a list containing the indices of the texture coordinates</li>
* <li>a list containing the indices of the normals</li>
* </ol>
*
* @example
* var face = new geo.Face('f 1/2/3 4/5/6 7/8/9');
* texture coordinate.index = 5;
* console.log(texture coordinate.toList()); // Prints ['f', 5, [1,4,7], [2,5,8], [3,6,9]]
*/
geo.Face.prototype.toList = function() {
var l = ['f', this.index, this.meshIndex,
[this.a, this.b, this.c ],
isNaN(this.aTexture) ? [] : [this.aTexture, this.bTexture, this.cTexture],
isNaN(this.aNormal ) ? [] : [this.aNormal, this.bNormal, this.cNormal ]
];
// if (this.d !== undefined)
// l.push(this.d);
// if (this.aTexture !== undefined) {
// l.push(this.aTexture);
// l.push(this.bTexture);
// l.push(this.cTexture);
// }
// if (this.dTexture !== undefined)
// l.push(this.dTexture);
return l;
};
/**
* Gives a string representation of the face
* @returns {string} A string representing the face
*
* @example
* var face = new geo.Face('f 3 5 6');
* console.log(face.toString()); // Prints f 3 5 6
*/
geo.Face.prototype.toString = function() {
return 'f ' + this.a + ' ' + this.b + ' ' + this.c + (this.d !== undefined ? ' ' + this.d : '');
};
/**
* Represents a material name
* @constructor
* @param {string} line the string representing the material
* @memberOf geo
*/
geo.Material = function() {
var split = arguments[0].replace(/\s+/g, ' ').trim().split(' ');
/**
* The name of the material
* @type {string}
*/
this.name = split[1];
};
/**
* Gives a string representation of the material
* @returns {string} obj representation of usemtl
*/
geo.Material.prototype.toString = function() {
return 'usemtl ' + this.name;
};
/**
* Gives a list representation of the material
* @returns {array} an array representing the material
* @example
* var material = new geo.Material('usemtl MyMaterial');
* console.log(material.toList()); // Logs ['u', 'MyMaterial']
*/
geo.Material.prototype.toList = function() {
return ['u', this.name];
};

381
server/geo/MeshContainer.js Normal file
View File

@@ -0,0 +1,381 @@
var Log = require('../lib/NodeLog.js');
var L3D = require('../../static/js/l3d.min.js');
var THREE = require('three');
function clone(vec) {
return {x : vec.x, y : vec.y, z : vec.z};
}
function rotation(vec1, x, y, z) {
var cos = Math.cos(z);
var sin = Math.sin(z);
var newVec = {x:0, y:0, z:0};
oldVec = clone(vec1);
newVec.x = cos * oldVec.x - sin * oldVec.y;
newVec.y = sin * oldVec.x + cos * oldVec.y;
newVec.z = oldVec.z;
oldVec = clone(newVec);
cos = Math.cos(y);
sin = Math.sin(y);
newVec.x = cos * oldVec.x + sin * oldVec.z;
newVec.y = oldVec.y;
newVec.z = - sin * oldVec.x + cos * oldVec.z;
cos = Math.cos(x);
sin = Math.sin(x);
oldVec = clone(newVec);
newVec.x = oldVec.x;
newVec.y = oldVec.y * cos - oldVec.z * sin;
newVec.z = oldVec.y * sin + oldVec.z * cos;
return clone(newVec);
}
function applyTransformation(vector, transfo) {
var ret = rotation(vector, transfo.rotation.x, transfo.rotation.y, transfo.rotation.z);
var scale = transfo.scale || 1;
return {
x: (ret.x + transfo.translation.x) * scale,
y: (ret.y + transfo.translation.y) * scale,
z: (ret.z + transfo.translation.z) * scale
};
}
/**
* Represents a mesh. All meshes are loaded once in geo.availableMesh to avoid
* loading at each mesh request
* @constructor
* @memberOf geo
*/
geo.MeshContainer = function(path, transfo, callback) {
if (callback === undefined && typeof transfo === 'function') {
callback = transfo;
transfo = {translation: {x:0,y:0,z:0}, rotation: {x:0,y:0,z:0}};
}
if (transfo === undefined) {
transfo = {translation: {x:0,y:0,z:0}, rotation: {x:0,y:0,z:0}};
}
/**
* array of each part of the mesh
* @type {geo.Mesh[]}
*/
this.meshes = [];
/**
* array of the vertices of the meshes (all merged)
* @type {geo.Vertex[]}
*/
this.vertices = [];
/**
* array of the faces of the meshes (all merged)
* @type {geo.Face[]}
*/
this.faces = [];
/**
* array of the normals of the meshes (all merged)
* @type {geo.Normal[]}
*/
this.normals = [];
/**
* array of the texture coordinates (all merged)
* @type {geo.TexCoord[]}
*/
this.texCoords = [];
/**
* Number of elements to stream in the mesh
* @type {Number}
*/
this.numberOfFaces = 0;
this.transfo = transfo;
this.callback = callback;
if (path !== undefined) {
this.loadFromFile('../' + path);
}
};
/**
* Loads a obj file
* @param {string} path the path to the file
*/
geo.MeshContainer.prototype.loadFromFile = function(path) {
var self = this;
fs.readFile(path, {encoding: 'utf-8'}, function(err, data) {
var currentMesh;
// Get lines from file
var lines = data.toString('utf-8').split("\n");
// For each line
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
if (line[0] === 'v') {
if (line[1] === 't') {
// Texture coord
var texCoord = new geo.TexCoord(line);
texCoord.index = self.texCoords.length;
self.texCoords.push(texCoord);
} else if (line[1] === 'n') {
var normal = new geo.Normal(line);
normal.index = self.normals.length;
self.normals.push(normal);
} else {
// Just a simple vertex
var vertex = new geo.Vertex(line);
var vertexTransformed = applyTransformation(vertex, self.transfo);
vertex.x = vertexTransformed.x;
vertex.y = vertexTransformed.y;
vertex.z = vertexTransformed.z;
vertex.index = self.vertices.length;
self.vertices.push(vertex);
}
} else if (line[0] === 'f') {
self.numberOfFaces++;
// Create mesh if it doesn't exist
if (currentMesh === undefined) {
currentMesh = new geo.Mesh();
self.meshes.push(currentMesh);
}
// Create faces (two if Face4)
var faces = currentMesh.addFaces(line);
faces[0].index = self.faces.length;
faces[0].meshIndex = self.meshes.length - 1;
self.faces.push(faces[0]);
if (faces.length === 2) {
self.numberOfFaces++;
faces[1].index = self.faces.length;
faces[1].meshIndex = self.meshes.length - 1;
self.faces.push(faces[1]);
}
} else if (line[0] === 'u') {
// usemtl
// If a current mesh exists, finish it
// Create a new mesh
currentMesh = new geo.Mesh();
self.meshes.push(currentMesh);
currentMesh.material = (new geo.Material(line)).name;
// console.log(currentMesh.material);
}
}
if (typeof self.callback === 'function') {
self.callback();
}
});
};
function trySetLoaded() {
for (var name in availableMeshNames) {
if (availableMeshNames[name].done === false) {
return;
}
}
Log.ready("Meshes loaded in " + (Date.now() - start) + 'ms');
}
var availableMeshNames = {
'/static/data/castle/princess peaches castle (outside).obj': {
done: false,
recommendations : L3D.createPeachRecommendations(1134, 768)
},
'/static/data/mountain/coocoolmountain.obj': {
done: false,
recommendations : L3D.createMountainRecommendations(1134, 768)
},
'/static/data/mountain/coocoolmountain_sub.obj': {
done: false,
recommendations : L3D.createMountainRecommendations(1134, 768)
},
'/static/data/whomp/Whomps Fortress.obj': {
done: false,
transfo: {
rotation: {
x: -Math.PI / 2,
y: 0,
z: Math.PI / 2
},
translation: {
x: 0,
y: 0,
z: 0
},
scale: 0.1
},
recommendations : L3D.createWhompRecommendations(1134, 768)
},
'/static/data/whomp/Whomps Fortress_sub.obj': {
done: false,
transfo: {
rotation: {
x: -Math.PI / 2,
y: 0,
z: Math.PI / 2
},
translation: {
x: 0,
y: 0,
z: 0
},
scale: 0.1
},
recommendations : L3D.createWhompRecommendations(1134, 768)
},
'/static/data/bobomb/bobomb battlefeild.obj': {
done: false,
transfo: {
rotation: {
x: 0,
y: Math.PI - 0.27,
z: 0
},
translation: {
x: 0,
y: 0,
z: 0
}
},
recommendations : L3D.createBobombRecommendations(1134, 768)
},
'/static/data/bobomb/bobomb battlefeild_sub.obj': {
done: false,
transfo: {
rotation: {
x: 0,
y: Math.PI - 0.27,
z: 0
},
translation: {
x: 0,
y: 0,
z: 0
}
},
recommendations : L3D.createBobombRecommendations(1134, 768)
},
'/static/data/sponza/sponza.obj': {
done: false
}
};
for (var i = 1; i < 26; i++) {
availableMeshNames['/static/data/spheres/' + i + '.obj'] = { done: false};
}
geo.availableMeshes = {};
var start = Date.now();
function pushMesh(name) {
geo.availableMeshes[name] = new geo.MeshContainer(
name.substring(1, name.length),
availableMeshNames[name].transfo,
function() {
geo.availableMeshes[name].recommendations = [];
if (availableMeshNames[name].recommendations !== undefined) {
for (var i = 0; i < availableMeshNames[name].recommendations.length; i++) {
var reco = availableMeshNames[name].recommendations[i].camera;
reco.lookAt(reco.target);
reco.updateMatrix();
reco.updateProjectionMatrix();
reco.updateMatrixWorld();
reco.matrixWorldInverse.getInverse( reco.matrixWorld );
var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse);
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse));
geo.availableMeshes[name].recommendations.push({
position: reco.position,
frustum: frustum.planes
});
}
}
availableMeshNames[name].done = true;
trySetLoaded();
}
);
}
for (var name in availableMeshNames) {
pushMesh(name);
}

553
server/geo/MeshStreamer.js Normal file
View File

@@ -0,0 +1,553 @@
var THREE = require('three');
var L3D = require('../../static/js/l3d.min.js');
function isInFrustum(element, planes) {
if (element instanceof Array) {
var outcodes = [];
for (var i = 0; i < element.length; i++) {
var vertex = element[i];
var currentOutcode = "";
for (var j = 0; j < planes.length; j++) {
var plane = planes[j];
distance =
plane.normal.x * vertex.x +
plane.normal.y * vertex.y +
plane.normal.z * vertex.z +
plane.constant;
// if (distance < 0) {
// exitToContinue = true;
// break;
// }
currentOutcode += distance > 0 ? '0' : '1';
}
outcodes.push(parseInt(currentOutcode,2));
}
// http://vterrain.org/LOD/culling.html
// I have no idea what i'm doing
// http://i.kinja-img.com/gawker-media/image/upload/japbcvpavbzau9dbuaxf.jpg
// But it seems to work
// EDIT : Not, this should be ok http://www.cs.unc.edu/~blloyd/comp770/Lecture07.pdf
if ((outcodes[0] | outcodes[1] | outcodes[2]) === 0) {
return true;
} else if ((outcodes[0] & outcodes[1] & outcodes[2]) !== 0) {
return false;
} else {
// part of the triangle is inside the viewing volume
return true;
}
}
}
/**
* @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
* @memberOf geo
* @constructor
* @param {string} path to the mesh
*/
geo.MeshStreamer = function(path) {
/**
* array of array telling if the jth face of the ith mesh has already been sent
*
* For each mesh, there is an object containing
* <ul>
* <li>`counter` : the number of faces currently sent</li>
* <li>`array` : an array boolean telling if the ith face has already been sent</li>
* </ul>
* @type {Object[]}
*/
this.meshFaces = [];
/**
* array of booleans telling if the ith vertex has already been sent
* @type {Boolean[]}
*/
this.vertices = [];
/**
* array of booleans telling if the ith face has already been sent
* @type {Boolean[]}
*/
this.faces = [];
/**
* array of booleans telling if the ith normal has already been sent
* @type {Boolean[]}
*/
this.normals = [];
/**
* array of booleans telling if the ith texCoord has already been sent
* @type {Boolean[]}
*/
this.texCoords = [];
/**
* Number of element to send by packet
* @type {Number}
*/
this.chunk = 1000;
if (path !== undefined) {
this.mesh = geo.availableMeshes[path];
}
};
geo.MeshStreamer.prototype.isBackFace = function(camera, face) {
var directionCamera = L3D.Tools.diff(camera.target, camera.position);
var v1 = L3D.Tools.diff(this.mesh.vertices[face.b], this.mesh.vertices[face.a]);
var v2 = L3D.Tools.diff(this.mesh.vertices[face.c], this.mesh.vertices[face.a]);
var normal = L3D.Tools.cross(v1, v2);
return L3D.Tools.dot(directionCamera, normal) > 0;
};
/**
* Compute a function that can compare two faces
* @param {Camera} camera a camera seeing or not face
* @returns {function} the function that compares two faces : the higher face is the most interesting for the camera
*/
geo.MeshStreamer.prototype.faceComparator = function(camera) {
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) {
var center1 = {
x: (self.mesh.vertices[face1.a].x + self.mesh.vertices[face1.b].x + self.mesh.vertices[face1.b].x) / 3,
y: (self.mesh.vertices[face1.a].y + self.mesh.vertices[face1.b].y + self.mesh.vertices[face1.b].y) / 3,
z: (self.mesh.vertices[face1.a].z + self.mesh.vertices[face1.b].z + self.mesh.vertices[face1.b].z) / 3
};
var dir1 = {
x: center1.x - camera.position.x,
y: center1.y - camera.position.y,
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 = direction.x * dir1.x + direction.y * dir1.y + direction.z * dir1.z;
var center2 = {
x: (self.mesh.vertices[face2.a].x + self.mesh.vertices[face2.b].x + self.mesh.vertices[face2.b].x) / 3,
y: (self.mesh.vertices[face2.a].y + self.mesh.vertices[face2.b].y + self.mesh.vertices[face2.b].y) / 3,
z: (self.mesh.vertices[face2.a].z + self.mesh.vertices[face2.b].z + self.mesh.vertices[face2.b].z) / 3
};
var dir2 = {
x: center2.x - camera.position.x,
y: center2.y - camera.position.y,
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 = direction.x * dir2.x + direction.y * dir2.y + direction.z * dir2.z;
// Decreasing order
if (dot1 > dot2) {
return -1;
}
if (dot1 < dot2) {
return 1;
}
return 0;
};
};
/**
* Initialize the socket.io callback
* @param {socket} socket the socket to initialize
*/
geo.MeshStreamer.prototype.start = function(socket) {
this.meshIndex = 0;
this.socket = socket;
var self = this;
socket.on('request', function(path, laggy) {
if (laggy === true) {
self.chunk = 1;
}
self.mesh = geo.availableMeshes[path];
if (self.mesh === undefined) {
process.stderr.write('Wrong path for model : ' + path);
socket.emit('refused');
socket.disconnect();
return;
}
self.meshFaces = new Array(self.mesh.meshes.length);
for (var i = 0; i < self.meshFaces.length; i++) {
self.meshFaces[i] = {
counter: 0,
array: new Array(self.mesh.meshes[i].faces.length)
};
}
socket.emit('ok');
});
socket.on('materials', function() {
var data = self.nextMaterials();
socket.emit('elements', data);
});
socket.on('next', function(camera) {
// Send next elements
var next = self.nextElements(camera);
if (next.data.length === 0) {
// If nothing, just serve stuff
var tmp = self.nextElements(camera, true);
next.data = tmp.data;
}
socket.emit('elements', next.data);
if (next.finished) {
socket.disconnect();
}
});
};
/**
* Prepare the array of materials
* @return array the array to send with all materials of the current mesh
*/
geo.MeshStreamer.prototype.nextMaterials = function() {
var data = [];
data.push(['g', this.mesh.numberOfFaces]);
for (var i = 0; i < this.mesh.meshes.length; i++) {
var currentMesh = this.mesh.meshes[i];
// Send usemtl
data.push([
'u',
currentMesh.material,
currentMesh.vertices.length,
currentMesh.faces.length,
this.mesh.texCoords.length > 0,
this.mesh.normals.length > 0
]);
}
return data;
};
/**
* Prepare the next elements
* @param {camera} _camera a camera that can be usefull to do smart streaming (stream
* only interesting parts according to the camera
* @returns {array} an array of elements ready to send
*/
geo.MeshStreamer.prototype.nextElements = function(_camera, force) {
var i;
if (force === undefined) {
force = false;
}
// Prepare camera (and scale to model)
var camera = null;
var planes = [];
var direction;
if (_camera !== null) {
camera = {
position: {
x: _camera[0][0],
y: _camera[0][1],
z: _camera[0][2]
},
target: {
x: _camera[1][0],
y: _camera[1][1],
z: _camera[1][2]
}
};
for (i = 2; i < _camera.length; i++) {
planes.push({
normal: {
x: _camera[i][0],
y: _camera[i][1],
z: _camera[i][2]
},
constant: _camera[i][3]
});
}
// Compute camera direction
direction = {
x: camera.target.x - camera.position.x,
y: camera.target.y - camera.position.y,
z: camera.target.z - camera.position.z
};
}
var sent = 0;
var data = [];
var mightBeCompletetlyFinished = true;
// BOOM
// if (camera != null)
// this.mesh.faces.sort(this.faceComparator(camera));
for (var faceIndex = 0; faceIndex < this.mesh.faces.length; faceIndex++) {
var currentFace = this.mesh.faces[faceIndex];
if (this.faces[currentFace.index] === true) {
continue;
}
mightBeCompletetlyFinished = false;
var vertex1 = this.mesh.vertices[currentFace.a];
var vertex2 = this.mesh.vertices[currentFace.b];
var vertex3 = this.mesh.vertices[currentFace.c];
if (!force && camera !== null) {
var display = false;
var exitToContinue = false;
threeVertices = [vertex1, vertex2, vertex3];
// Frustum culling
if (!isInFrustum(threeVertices, planes)) {
continue;
}
// Backface culling
if (this.isBackFace(camera, currentFace)) {
continue;
}
}
if (!this.vertices[currentFace.a]) {
data.push(vertex1.toList());
this.vertices[currentFace.a] = true;
sent++;
}
if (!this.vertices[currentFace.b]) {
data.push(vertex2.toList());
this.vertices[currentFace.b] = true;
sent++;
}
if (!this.vertices[currentFace.c]) {
data.push(vertex3.toList());
this.vertices[currentFace.c] = true;
sent++;
}
var normal1 = this.mesh.normals[currentFace.aNormal];
var normal2 = this.mesh.normals[currentFace.bNormal];
var normal3 = this.mesh.normals[currentFace.cNormal];
if (normal1 !== undefined && !this.normals[currentFace.aNormal]) {
data.push(normal1.toList());
this.normals[currentFace.aNormal] = true;
sent++;
}
if (normal2 !== undefined && !this.normals[currentFace.bNormal]) {
data.push(normal2.toList());
this.normals[currentFace.bNormal] = true;
sent++;
}
if (normal3 !== undefined && !this.normals[currentFace.cNormal]) {
data.push(normal3.toList());
this.normals[currentFace.cNormal] = true;
sent++;
}
var tex1 = this.mesh.texCoords[currentFace.aTexture];
var tex2 = this.mesh.texCoords[currentFace.bTexture];
var tex3 = this.mesh.texCoords[currentFace.cTexture];
if (tex1 !== undefined && !this.texCoords[currentFace.aTexture]) {
data.push(tex1.toList());
this.texCoords[currentFace.aTexture] = true;
sent++;
}
if (tex2 !== undefined && !this.texCoords[currentFace.bTexture]) {
data.push(tex2.toList());
this.texCoords[currentFace.bTexture] = true;
sent++;
}
if (tex3 !== undefined && !this.texCoords[currentFace.cTexture]) {
data.push(tex3.toList());
this.texCoords[currentFace.cTexture] = true;
sent++;
}
data.push(currentFace.toList());
// this.meshFaces[meshIndex] = this.meshFaces[meshIndex] || [];
this.faces[currentFace.index] = true;
// this.meshFaces[meshIndex].counter++;
// currentMesh.faceIndex++;
sent++;
if (sent > this.chunk) {
return {data: data, finished: false};
}
}
return {data: data, finished: mightBeCompletetlyFinished};
};
geo.MeshStreamer.prototype.isFinished = function(i) {
return this.meshFaces[i].counter === this.meshFaces[i].array.length;
};

1
server/geo/mat1.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.07894736842105263,0.18421052631578946,0,0.02631578947368421,0.02631578947368421,0,0.02631578947368421,0,0.13157894736842105,0.2894736842105263,0.2631578947368421],[0,0,0.10526315789473684,0.15789473684210525,0.18421052631578946,0.02631578947368421,0,0.07894736842105263,0.02631578947368421,0.05263157894736842,0.05263157894736842,0.05263157894736842],[0,0.02631578947368421,0,0.5,0.02631578947368421,0.02631578947368421,0.02631578947368421,0.07894736842105263,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.05263157894736842],[0,0.05263157894736842,0.07894736842105263,0,0.4473684210526316,0.02631578947368421,0.13157894736842105,0.02631578947368421,0,0.07894736842105263,0,0.13157894736842105],[0,0,0.02631578947368421,0.15789473684210525,0,0.3157894736842105,0.21052631578947367,0.05263157894736842,0,0.07894736842105263,0,0.10526315789473684],[0,0.10526315789473684,0,0.05263157894736842,0.13157894736842105,0,0.13157894736842105,0.05263157894736842,0.15789473684210525,0.02631578947368421,0.02631578947368421,0.02631578947368421],[0,0.15789473684210525,0.10526315789473684,0,0,0.10526315789473684,0,0.05263157894736842,0.21052631578947367,0.13157894736842105,0,0],[0,0.07894736842105263,0.05263157894736842,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.10526315789473684,0,0.07894736842105263,0.02631578947368421,0.02631578947368421,0.05263157894736842],[0,0,0.10526315789473684,0.02631578947368421,0.02631578947368421,0.18421052631578946,0.15789473684210525,0,0,0.21052631578947367,0.07894736842105263,0.07894736842105263],[0,0.07894736842105263,0.10526315789473684,0.02631578947368421,0,0,0.07894736842105263,0.15789473684210525,0.13157894736842105,0,0.21052631578947367,0.07894736842105263],[0,0.02631578947368421,0.10526315789473684,0.07894736842105263,0.05263157894736842,0.02631578947368421,0,0.02631578947368421,0.23684210526315788,0.07894736842105263,0,0.10526315789473684],[0,0.18421052631578946,0.13157894736842105,0.13157894736842105,0.10526315789473684,0.02631578947368421,0,0.13157894736842105,0.02631578947368421,0.05263157894736842,0.07894736842105263,0]]

1
server/geo/mat1.json.bak Normal file
View File

@@ -0,0 +1 @@
[[0,0,602,0,0,0,0,0,0,151,191,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1116,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,87,0,0,0,0,0,0,0,0,0,82],[0,0,0,0,0,0,0,0,195,0,0,0],[0,86,41,0,0,0,0,0,0,563,74,72],[0,0,59,0,0,0,0,0,0,0,0,49],[0,147,151,0,0,0,0,0,0,0,0,110],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0]]

1
server/geo/mat2.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.03125,0.09375,0.5,0.21875,0.03125,0.09375,0.1875,0,0.125,0.15625,0],[0,0,0.15625,0.0625,0.21875,0.0625,0.15625,0.09375,0,0.0625,0.03125,0],[0,0.21875,0,0.0625,0.0625,0,0,0,0,0,0.03125,0.0625],[0,0.09375,0.0625,0,0.25,0.03125,0.1875,0.1875,0.03125,0.25,0,0.03125],[0,0.125,0.0625,0.125,0,0.03125,0,0,0.1875,0.09375,0.15625,0.0625],[0,0.03125,0,0,0,0,0.21875,0,0.25,0,0,0.1875],[0,0.03125,0.0625,0.0625,0.03125,0.34375,0,0.125,0.34375,0,0.40625,0.0625],[0,0.125,0,0.15625,0,0.0625,0.25,0,0.03125,0.09375,0,0],[0,0.125,0.03125,0.0625,0,0.1875,0.15625,0.03125,0,0.0625,0,0.25],[0,0.1875,0,0.125,0.125,0,0.0625,0.03125,0,0,0.03125,0.125],[0,0.0625,0.0625,0.03125,0.09375,0,0.46875,0.09375,0.03125,0.09375,0,0.1875],[0,0,0.0625,0.0625,0,0,0,0.03125,0.1875,0.125,0.46875,0]]

1
server/geo/mat2.json.bak Normal file
View File

@@ -0,0 +1 @@
[[0,0,0,218,0,0,0,0,0,0,0,0],[0,0,0,106,36,0,0,182,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,3,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,72],[0,0,0,0,0,0,0,0,0,0,0,0]]

1
server/geo/mat3.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.05555555555555555,0.08333333333333333,0,0.16666666666666666,0.027777777777777776,0.5,0,0.05555555555555555,0.027777777777777776,0],[0,0,0.05555555555555555,0.08333333333333333,0.08333333333333333,0,0.08333333333333333,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0,0.1111111111111111,0.027777777777777776,0,0.027777777777777776,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0.027777777777777776,0,0.1111111111111111,0,0.027777777777777776,0.027777777777777776,0.08333333333333333,0.027777777777777776,0],[0,0.08333333333333333,0,0.1111111111111111,0,0.3888888888888889,0,0.16666666666666666,0.05555555555555555,0.027777777777777776,0.05555555555555555],[0,0,0,0.027777777777777776,0.25,0,0.1111111111111111,0.1388888888888889,0,0,0.2222222222222222],[0,0.05555555555555555,0.08333333333333333,0.1388888888888889,0,0.027777777777777776,0,0.027777777777777776,0.08333333333333333,0.16666666666666666,0.3055555555555556],[0,0.027777777777777776,0.027777777777777776,0,0.027777777777777776,0.1388888888888889,0.05555555555555555,0,0.08333333333333333,0.05555555555555555,0.027777777777777776],[0,0,0,0,0.08333333333333333,0.05555555555555555,0.1111111111111111,0.05555555555555555,0,0.1111111111111111,0.1111111111111111],[0,0.027777777777777776,0.027777777777777776,0.027777777777777776,0.16666666666666666,0,0.05555555555555555,0.027777777777777776,0.1388888888888889,0,0],[0,0,0.027777777777777776,0,0.1388888888888889,0.16666666666666666,0.1111111111111111,0.08333333333333333,0.1111111111111111,0,0]]

1
server/geo/mat3.json.bak Normal file
View File

@@ -0,0 +1 @@
[[0,0,0,0,0,0,70,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,12,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,10,0,0,0,0,0,0,0],[0,0,0,0,0,83,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,64],[0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,36,0,0,0,16,0,0]]

View File

@@ -0,0 +1 @@
[[0,0.1,0.3,0,0,0,0,0,0,0.1,0.4,0.5],[0,0,0.1,0.2,0.2,0,0,0.2,0,0.1,0.1,0],[0,0.1,0,0.4,0,0,0.1,0.3,0.1,0.1,0.1,0],[0,0.1,0,0,0.4,0.1,0.2,0,0,0.1,0,0.2],[0,0,0,0.2,0,0.5,0.1,0,0,0.1,0,0],[0,0,0,0,0.3,0,0.1,0,0.3,0.1,0.1,0.1],[0,0.3,0.1,0,0,0,0,0.1,0.4,0.1,0,0],[0,0.1,0.1,0,0.1,0,0.4,0,0,0,0.1,0.2],[0,0,0.3,0,0,0.3,0.1,0,0,0.3,0.1,0],[0,0.1,0.1,0,0,0,0.1,0.4,0,0,0.2,0.1],[0,0,0.2,0.2,0.1,0.1,0,0.1,0.3,0,0,0],[0,0.2,0.2,0.3,0,0,0,0.1,0,0.1,0.1,0]]

View File

@@ -0,0 +1 @@
[[0,0,0.1,0.5,0.3,0,0.1,0.1,0,0.2,0,0],[0,0,0.2,0.1,0.1,0,0.3,0.2,0,0.2,0,0],[0,0.2,0,0.1,0.2,0,0,0,0,0,0,0.1],[0,0.1,0.1,0,0.4,0,0,0.2,0,0.3,0,0],[0,0.2,0,0,0,0.1,0,0,0.4,0.1,0.2,0.1],[0,0.1,0,0,0,0,0.1,0,0.4,0,0,0.2],[0,0.1,0,0,0.1,0.4,0,0.1,0.1,0,0.3,0.1],[0,0,0,0.3,0,0.1,0.2,0,0,0,0,0],[0,0.2,0.1,0.1,0,0.2,0.2,0,0,0,0,0.2],[0,0.3,0,0.1,0.1,0,0.1,0,0,0,0.1,0],[0,0.1,0.1,0,0,0,0.3,0.1,0,0.1,0,0.2],[0,0,0.1,0.1,0,0,0,0,0.1,0,0.5,0]]

View File

@@ -0,0 +1 @@
[[0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0.5,0,0,0,0],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0,0,0],[0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0.16666666666666666,0],[0,0,0,0.3333333333333333,0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0],[0,0,0,0.16666666666666666,0.5,0,0,0,0,0,0.3333333333333333],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0,0,0.5],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0,0.16666666666666666,0,0],[0,0,0,0,0,0.16666666666666666,0.16666666666666666,0,0,0.5,0.16666666666666666],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0,0,0.3333333333333333,0,0],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0.3333333333333333,0.16666666666666666,0,0]]

141
server/lib/Matrix.js Normal file
View File

@@ -0,0 +1,141 @@
"use strict";
let fs = require('fs');
class OutOfBoundError extends Error {
constructor(matrix, i, j) {
super(`Index array out of bound (${i},${j}) exceeds (${matrix.lines}, ${matrix.columns}).`);
this.name = 'OutOfBoundError';
}
}
class Matrix {
constructor(lines, columns) {
// this.lines = lines;
// this.columns = columns;
this.data = [];
for (let i = 0; i < lines; i++) {
let line = [];
for (let j = 0; j < columns; j++) {
line.push(0);
}
this.data.push(line);
}
}
get(i, j) {
// if (i >= this.lines || j >= this.columns || i < 0 || j < 0 ) {
// this._throwOutOfBoundError(i,j);
// }
return this.data[i][j];
}
set(i, j, value) {
// if (i >= this.lines || j >= this.columns || i < 0 || j < 0 ) {
// this._throwOutOfBoundError(i,j);
// }
return this.data[i][j] = value;
}
print(type) {
if (type === 'matlab') {
let maxColumns = 0;
for (let i = 0; i < this.data.length; i++) {
if (this.data[i].length > maxColumns)
maxColumns = this.data[i].length;
}
let str = '[';
for (let i = 0; i < this.data.length; i++) {
str += '[';
for (let j = 0; j < maxColumns; j++) {
str +=
(this.data[i][j] !== undefined ? this.data[i][j] : 0) +
(j === maxColumns - 1 ? ']' : ',');
}
str += (i === this.data.length - 1 ? ']' : ';');
}
console.log(str + ';');
return;
}
// for (let i = 0; i < this.lines; i++) {
// for (let j = 0; j < this.columns; j++) {
// process.stdout.write(this.get(i,j) + ' ');
// }
// process.stdout.write('\n');
// }
}
toArray() {
return this.data;
}
fromArray(array) {
// if (! array instanceof Array)
// throw new TypeError('Parameter is not an array');
// let columns = null;
// for (let line of array) {
// if (! line instanceof Array)
// throw new TypeError('Parameter is not an array of array');
// if (columns === null) {
// columns = line.length;
// } else if (columns !== line.length) {
// throw new Typerror('The lines have not the same size');
// }
// }
this.data = array;
// this.columns = columns;
// this.lines = array.length;
}
saveToFile(path, type) {
if (type === 'matlab') {
fs.writeFileSync(path, JSON.stringify(this.data).replace('],', '];'));
return;
}
fs.writeFileSync(path, JSON.stringify(this.data));
}
loadFromFile(path) {
this.fromArray(JSON.parse(fs.readFileSync(path, 'utf-8')));
}
_throwOutOfBoundError(i,j) {
throw new OutOfBoundError(this, i, j);
}
};
module.exports = Matrix;
function main() {
var m = new Matrix(2,3);
m.set(1,2,3);
m.print();
m.saveToFile('tests/myMatrix.json');
console.log('----');
var m2 = new Matrix();
m2.loadFromFile('tests/myMatrix.json');
m2.print();
}
if (require.main === module) {
main();
}

85
server/lib/NodeLog.js Normal file
View File

@@ -0,0 +1,85 @@
var Log = {};
var Colors = Object.freeze({
DEFAULT: '\033[0m',
BLACK: '\033[30m',
RED: '\033[31m',
GREEN: '\033[32m',
YELLOW: '\033[33m',
BLUE: '\033[34m',
MAGENTA: '\033[35m',
CYAN: '\033[36m',
ORANGE: '\033[38;5;202m',
});
var isDev = require('express')().get('env') === 'development';
var log;
if (isDev) {
log = function(elt, color) {
console.log(color + elt + Colors.DEFAULT);
};
} else {
log = function(elt, color) {
console.log(elt);
};
}
Log.ready = function(msg) {
log('[RDY] ' + new Date() + ' ' + msg, Colors.GREEN);
};
Log.request = function(req, res, time) {
if (req.headers['x-forwarded-for'] !== undefined || isDev) {
log(
'[REQ] ' + new Date() + ' ' +
(req.headers['x-forwarded-for'] || req.connection.remoteAddress) +
(time !== undefined ? (' in ' + (" " + time).slice(-6) + ' ms') : '') +
' : ' + (req.static && req.url !== '/favicon.ico' ? '/static' + req.url : req.url),
req.static ? Colors.YELLOW : Colors.CYAN
);
}
};
Log.socket = {};
Log.socket.connection = function(socket) {
log(
'[SOK] ' + new Date() + ' ' +
(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address) + ' connection',
Colors.MAGENTA
);
};
Log.socket.disconnect = function(socket) {
log(
'[SOK] ' + new Date() + ' ' +
(socket.handshake.headers['x-forwarded-for'] || socket.handshake.address) + ' disconnect',
Colors.MAGENTA
);
};
Log.dberror = function(error) {
log(
'[DBE] ' + new Date() + ' ' + error,
Colors.RED
);
};
Log.mailerror = function(error) {
log(
'[MLE] ' + new Date() + ' ' + error,
Colors.RED
);
};
Log.debug = function(info, force) {
if (isDev || force === true) {
log(
'[DBG] ' + (info !== undefined ? info : ''),
Colors.ORANGE
);
}
};
module.exports = Log;

101
server/lib/Serial.js Normal file
View File

@@ -0,0 +1,101 @@
"use strict";
let fs = require('fs');
let THREE = require('three');
let L3D = require('../static/js/l3d.min.js');
function serialize(object) {
let data = {};
data.vertices = object.children[0].geometry.vertices;
data.children = [];
for (let objChild of object.children) {
let newChild = {};
// newChild.faceVertexUvs = objChild.geometry.faceVertexUvs;
newChild.faces = objChild.geometry.faces;
data.children.push(newChild);
}
return JSON.stringify(data);
}
function deserialize(str) {
let parse = JSON.parse(str);
let vertices = [];
let material = new THREE.MeshBasicMaterial();
let ret = new THREE.Object3D();
for (let vertex of parse.vertices) {
vertices.push(new THREE.Vector3(vertex.x, vertex.y, vertex.z));
}
for (let parseChild of parse.children) {
let geometry = new THREE.Geometry();
geometry.vertices = vertices;
for (let face of parseChild.faces) {
geometry.faces.push(new THREE.Face3(face.a, face.b, face.c));
}
geometry.computeBoundingSphere();
let newChild = new THREE.Mesh(geometry, material);
ret.children.push(newChild);
}
return ret;
}
function serializeToFile(path, obj) {
fs.writeFileSync(path, serialize(obj));
}
function loadFromFile(path) {
return deserialize(fs.readFileSync(path, 'utf-8'));
}
module.exports.serialize = serialize;
module.exports.deserialize = deserialize;
module.exports.serializeToFile = serializeToFile;
module.exports.loadFromFile = loadFromFile;
function main() {
let loader = new L3D.ProgressiveLoader(
'/static/data/castle/princess peaches castle (outside).obj',
new THREE.Object3D(),
null
);
loader.load(function() {
console.log("Loaded");
// console.log(loader.obj.children[0].geometry);
deserialize(serialize(loader.obj));
});
}
if (require.main === module) {
main();
}

43
server/lib/controllers.js Normal file
View File

@@ -0,0 +1,43 @@
/**
* Module dependencies.
*/
var express = require('express');
var fs = require('fs');
var Log = require('./NodeLog.js');
module.exports = function(parent){
Log.debug("Loading controllers :");
fs.readdirSync(__dirname + '/../controllers').forEach(function(name){
// index.js in controller, with function as pages (views.py for django)
var obj = require('./../controllers/' + name + '/index');
// urls.js, just like django urls.py
var urls = require('./../controllers/' + name + '/urls');
name = obj.name || name;
var app = express();
// allow specifying the view engine
if (obj.engine) app.set('view engine', obj.engine);
app.set('views', __dirname + '/../controllers/' + name + '/views');
// generate routes based
// on the exported methods
Log.debug(' ' + name + ':');
for (var key in urls) {
app.get(key, obj[urls[key]]);
Log.debug(' ' + key + ' -> ' + name + '.' + urls[key]);
}
Log.debug();
// mount the app
parent.use(app);
});
};

6
server/lib/filterInt.js Normal file
View File

@@ -0,0 +1,6 @@
// Strict parseInt
module.exports.filterInt = function(value) {
if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value))
return Number(value);
return NaN;
};

1
server/lib/mat1.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.07894736842105263,0.18421052631578946,0,0.02631578947368421,0.02631578947368421,0,0.02631578947368421,0,0.13157894736842105,0.2894736842105263,0.2631578947368421],[0,0,0.10526315789473684,0.15789473684210525,0.18421052631578946,0.02631578947368421,0,0.07894736842105263,0.02631578947368421,0.05263157894736842,0.05263157894736842,0.05263157894736842],[0,0.02631578947368421,0,0.5,0.02631578947368421,0.02631578947368421,0.02631578947368421,0.07894736842105263,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.05263157894736842],[0,0.05263157894736842,0.07894736842105263,0,0.4473684210526316,0.02631578947368421,0.13157894736842105,0.02631578947368421,0,0.07894736842105263,0,0.13157894736842105],[0,0,0.02631578947368421,0.15789473684210525,0,0.3157894736842105,0.21052631578947367,0.05263157894736842,0,0.07894736842105263,0,0.10526315789473684],[0,0.10526315789473684,0,0.05263157894736842,0.13157894736842105,0,0.13157894736842105,0.05263157894736842,0.15789473684210525,0.02631578947368421,0.02631578947368421,0.02631578947368421],[0,0.15789473684210525,0.10526315789473684,0,0,0.10526315789473684,0,0.05263157894736842,0.21052631578947367,0.13157894736842105,0,0],[0,0.07894736842105263,0.05263157894736842,0.02631578947368421,0.07894736842105263,0.07894736842105263,0.10526315789473684,0,0.07894736842105263,0.02631578947368421,0.02631578947368421,0.05263157894736842],[0,0,0.10526315789473684,0.02631578947368421,0.02631578947368421,0.18421052631578946,0.15789473684210525,0,0,0.21052631578947367,0.07894736842105263,0.07894736842105263],[0,0.07894736842105263,0.10526315789473684,0.02631578947368421,0,0,0.07894736842105263,0.15789473684210525,0.13157894736842105,0,0.21052631578947367,0.07894736842105263],[0,0.02631578947368421,0.10526315789473684,0.07894736842105263,0.05263157894736842,0.02631578947368421,0,0.02631578947368421,0.23684210526315788,0.07894736842105263,0,0.10526315789473684],[0,0.18421052631578946,0.13157894736842105,0.13157894736842105,0.10526315789473684,0.02631578947368421,0,0.13157894736842105,0.02631578947368421,0.05263157894736842,0.07894736842105263,0],]

1
server/lib/mat2.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.03125,0.09375,0.5,0.21875,0.03125,0.09375,0.1875,0,0.125,0.15625,0],[0,0,0.15625,0.0625,0.21875,0.0625,0.15625,0.09375,0,0.0625,0.03125,0],[0,0.21875,0,0.0625,0.0625,0,0,0,0,0,0.03125,0.0625],[0,0.09375,0.0625,0,0.25,0.03125,0.1875,0.1875,0.03125,0.25,0,0.03125],[0,0.125,0.0625,0.125,0,0.03125,0,0,0.1875,0.09375,0.15625,0.0625],[0,0.03125,0,0,0,0,0.21875,0,0.25,0,0,0.1875],[0,0.03125,0.0625,0.0625,0.03125,0.34375,0,0.125,0.34375,0,0.40625,0.0625],[0,0.125,0,0.15625,0,0.0625,0.25,0,0.03125,0.09375,0,0],[0,0.125,0.03125,0.0625,0,0.1875,0.15625,0.03125,0,0.0625,0,0.25],[0,0.1875,0,0.125,0.125,0,0.0625,0.03125,0,0,0.03125,0.125],[0,0.0625,0.0625,0.03125,0.09375,0,0.46875,0.09375,0.03125,0.09375,0,0.1875],[0,0,0.0625,0.0625,0,0,0,0.03125,0.1875,0.125,0.46875,0],]

1
server/lib/mat3.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.05555555555555555,0.08333333333333333,0,0.16666666666666666,0.027777777777777776,0.5,0,0.05555555555555555,0.027777777777777776,0],[0,0,0.05555555555555555,0.08333333333333333,0.08333333333333333,0,0.08333333333333333,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0,0.1111111111111111,0.027777777777777776,0,0.027777777777777776,0,0.027777777777777776,0.027777777777777776,0],[0,0.05555555555555555,0.027777777777777776,0,0.1111111111111111,0,0.027777777777777776,0.027777777777777776,0.08333333333333333,0.027777777777777776,0],[0,0.08333333333333333,0,0.1111111111111111,0,0.3888888888888889,0,0.16666666666666666,0.05555555555555555,0.027777777777777776,0.05555555555555555],[0,0,0,0.027777777777777776,0.25,0,0.1111111111111111,0.1388888888888889,0,0,0.2222222222222222],[0,0.05555555555555555,0.08333333333333333,0.1388888888888889,0,0.027777777777777776,0,0.027777777777777776,0.08333333333333333,0.16666666666666666,0.3055555555555556],[0,0.027777777777777776,0.027777777777777776,0,0.027777777777777776,0.1388888888888889,0.05555555555555555,0,0.08333333333333333,0.05555555555555555,0.027777777777777776],[0,0,0,0,0.08333333333333333,0.05555555555555555,0.1111111111111111,0.05555555555555555,0,0.1111111111111111,0.1111111111111111],[0,0.027777777777777776,0.027777777777777776,0.027777777777777776,0.16666666666666666,0,0.05555555555555555,0.027777777777777776,0.1388888888888889,0,0],[0,0,0.027777777777777776,0,0.1388888888888889,0.16666666666666666,0.1111111111111111,0.08333333333333333,0.1111111111111111,0,0],]

1
server/lib/matt1.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.1,0.3,0,0,0,0,0,0,0.1,0.4,0.5],[0,0,0.1,0.2,0.2,0,0,0.2,0,0.1,0.1,0],[0,0.1,0,0.4,0,0,0.1,0.3,0.1,0.1,0.1,0],[0,0.1,0,0,0.4,0.1,0.2,0,0,0.1,0,0.2],[0,0,0,0.2,0,0.5,0.1,0,0,0.1,0,0],[0,0,0,0,0.3,0,0.1,0,0.3,0.1,0.1,0.1],[0,0.3,0.1,0,0,0,0,0.1,0.4,0.1,0,0],[0,0.1,0.1,0,0.1,0,0.4,0,0,0,0.1,0.2],[0,0,0.3,0,0,0.3,0.1,0,0,0.3,0.1,0],[0,0.1,0.1,0,0,0,0.1,0.4,0,0,0.2,0.1],[0,0,0.2,0.2,0.1,0.1,0,0.1,0.3,0,0,0],[0,0.2,0.2,0.3,0,0,0,0.1,0,0.1,0.1,0],]

1
server/lib/matt2.json Normal file
View File

@@ -0,0 +1 @@
[[0,0,0.1,0.5,0.3,0,0.1,0.1,0,0.2,0,0],[0,0,0.2,0.1,0.1,0,0.3,0.2,0,0.2,0,0],[0,0.2,0,0.1,0.2,0,0,0,0,0,0,0.1],[0,0.1,0.1,0,0.4,0,0,0.2,0,0.3,0,0],[0,0.2,0,0,0,0.1,0,0,0.4,0.1,0.2,0.1],[0,0.1,0,0,0,0,0.1,0,0.4,0,0,0.2],[0,0.1,0,0,0.1,0.4,0,0.1,0.1,0,0.3,0.1],[0,0,0,0.3,0,0.1,0.2,0,0,0,0,0],[0,0.2,0.1,0.1,0,0.2,0.2,0,0,0,0,0.2],[0,0.3,0,0.1,0.1,0,0.1,0,0,0,0.1,0],[0,0.1,0.1,0,0,0,0.3,0.1,0,0.1,0,0.2],[0,0,0.1,0.1,0,0,0,0,0.1,0,0.5,0],]

1
server/lib/matt3.json Normal file
View File

@@ -0,0 +1 @@
[[0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0.5,0,0,0,0],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0.16666666666666666,0,0,0,0],[0,0.16666666666666666,0.16666666666666666,0,0,0,0,0.16666666666666666,0.16666666666666666,0.16666666666666666,0],[0,0,0,0.3333333333333333,0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0],[0,0,0,0.16666666666666666,0.5,0,0,0,0,0,0.3333333333333333],[0,0,0.16666666666666666,0.16666666666666666,0,0,0,0,0,0,0.5],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0,0.16666666666666666,0,0],[0,0,0,0,0,0.16666666666666666,0.16666666666666666,0,0,0.5,0.16666666666666666],[0,0.16666666666666666,0,0.16666666666666666,0.16666666666666666,0,0,0,0.3333333333333333,0,0],[0,0,0,0,0,0.3333333333333333,0.16666666666666666,0.3333333333333333,0.16666666666666666,0,0],]

43
server/lib/posts.js Normal file
View File

@@ -0,0 +1,43 @@
/**
* Module dependencies.
*/
var express = require('express');
var fs = require('fs');
var Log = require('./NodeLog.js');
module.exports = function(parent){
Log.debug("Loading controllers :");
fs.readdirSync(__dirname + '/../posts').forEach(function(name){
// index.js in controller, with function as pages (views.py for django)
var obj = require('./../posts/' + name + '/index');
// urls.js, just like django urls.py
var urls = require('./../posts/' + name + '/urls');
name = obj.name || name;
var app = express();
// allow specifying the view engine
if (obj.engine) app.set('view engine', obj.engine);
app.set('views', __dirname + '/../posts/' + name + '/views');
// generate routes based
// on the exported methods
Log.debug(' ' + name + ':');
for (var key in urls) {
app.post(key, obj[urls[key]]);
Log.debug(' ' + key + ' -> ' + name + '.' + urls[key]);
}
Log.debug();
// mount the app
parent.use(app);
});
};

View File

@@ -0,0 +1 @@
[[0,0,0],[0,0,3]]

9
server/lib/vcode.js Normal file
View File

@@ -0,0 +1,9 @@
var hash = require('sha256');
var secretKey = require('../private.js').microSecretKey;
var campaignId = require('../private.js').microCampaignId;
module.exports = function(workerId) {
return 'mw-' + hash(campaignId + workerId + secretKey);
};

1040
server/npm-shrinkwrap.json generated Normal file

File diff suppressed because it is too large Load Diff

22
server/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name" : "3d-interface",
"version" : "2.0.0",
"dependencies" : {
"express" : "4.0",
"jade" : "1.9.2",
"pg" : "4.3.0",
"body-parser" : "1.12.4",
"cookie-parser" : "1.3.4",
"cookie-session" : "1.1.0",
"socket.io" : "1.3.5",
"serve-favicon": "2.3.0",
"emailjs":"0.3.16",
"three":"0.71.0",
"sha256":"0.2.0",
"async":"1.4.2"
},
"repository" : {
"type" : "git",
"url" : "https://github.com/tforgione/3dinterface.git"
}
}

View File

@@ -0,0 +1,21 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO arrowclicked(exp_id, arrow_id, time) VALUES($1,$2, to_timestamp($3));",
[req.session.expId, req.body.arrowId, req.body.time],
function(err, result) {
if (err !== null)
Log.dberror(err + ' arrow-clicked');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/arrow-clicked': 'index'
};

View File

@@ -0,0 +1,21 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO coinclicked(exp_id, coin_id, time) VALUES($1,$2, to_timestamp($3));",
[req.session.expId, req.body.coinId, req.body.time],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in coin-clicked');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/coin-clicked': 'index'
};

View File

@@ -0,0 +1,19 @@
var mail = require('../../lib/mail.js');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
mail.send({
from: req.body.name + " <" + req.body.name + "@toto.tata>",
to: "Thomas <thomas.forgione@gmail.com>",
subject: req.body.scene + " by " + req.body.name,
text: JSON.stringify(req.body.coins)
}, function(err, message) {
if (err !== null) {
Log.mailerror(err);
}
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/coin-info': 'index'
};

View File

@@ -0,0 +1,43 @@
var pg = require('pg');
var pgc = require('../../private.js');
var db = require('../../controllers/prototype/dbrequests.js');
var mail = require('../../lib/mail.js');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
var text = 'id : ' + req.session.userId + '\n';
pg.connect(pgc.url, function(err, client, release) {
client.query(
'SELECT Users.worker_id AS name FROM Users WHERE Users.id = $1;',
[req.session.userId],
function(err, result) {
text += 'workerId : ' + result.rows[0].name + '\n';
for (var i in req.body) {
text += i + ' : ' + req.body[i] + '\n';
}
mail.send({
from: result.rows[0].name + " <" + req.session.userId + "@toto.tata>",
to: "Thomas <dragonrock.django@gmail.com>",
subject: "By " + result.rows[0].name,
text: text
}, function(err, message) {
if (err !== null) {
Log.mailerror(err);
}
});
}
);
});
res.redirect('/thankyou');
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/feedback-target': 'index'
};

21
server/posts/fps/index.js Normal file
View File

@@ -0,0 +1,21 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO fpscounter(exp_id, fps, time) VALUES($1,$2,to_timestamp($3));",
[req.session.expId, req.body.fps, req.body.time],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in fps');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

3
server/posts/fps/urls.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/fps': 'index'
};

View File

@@ -0,0 +1,27 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO hovered(exp_id, time, start, arrow_id)" +
"VALUES($1, to_timestamp($2), $3, $4);" ,
[
req.session.expId,
req.body.time,
req.body.start ? true : false,
req.body.arrowId
],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in hovered');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/hovered': 'index'
};

View File

@@ -0,0 +1,32 @@
var pg = require('pg');
var secret = require('../../private');
var db = require('../../controllers/prototype/dbrequests.js');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
var workerId = req.session.workerId || req.body.inputId;
db.checkUserName(workerId, function(ok) {
if (!ok) {
db.createUser(
workerId,
req.body.inputAge,
req.body.inputGender === 'male',
req.body.input3dskills,
req.body.inputLastTime,
function(id) {
req.session.userId = id;
req.session.save();
res.redirect('/prototype/tutorial');
}
);
} else {
req.session.identificationFailed = true;
res.redirect('/user-study');
}
});
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/identification': 'index'
};

View File

@@ -0,0 +1,36 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO keyboardevent(exp_id, camera, time, keycode, keypressed)" +
"VALUES($1, ROW(ROW($2,$3,$4),ROW($5,$6,$7)), to_timestamp($8), $9, $10);" ,
[
req.session.expId,
req.body.camera.position.x,
req.body.camera.position.y,
req.body.camera.position.z,
req.body.camera.target.x,
req.body.camera.target.y,
req.body.camera.target.z,
req.body.time,
req.body.keycode,
req.body.keypressed
],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in keyboard-event');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/keyboard-event': 'index'
};

View File

@@ -0,0 +1,21 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO pointerlocked(exp_id, locked, time) VALUES($1,$2,to_timestamp($3));",
[req.session.expId, req.body.locked, req.body.time],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in pointer-lock');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/pointer-locked': 'index'
};

View File

@@ -0,0 +1,33 @@
var pg = require('pg');
var secret = require('../../private');
var Log = require('../../lib/NodeLog.js');
module.exports.index = function(req, res) {
pg.connect(secret.url, function(err, client, release) {
client.query(
"INSERT INTO previousnextclicked(exp_id, previousnext, time, camera)" +
"VALUES($1, $2, to_timestamp($3), ROW(ROW($4,$5,$6), ROW($7,$8,$9)));" ,
[
req.session.expId,
req.body.previous ? 'p' : 'n',
req.body.time,
req.body.camera.position.x,
req.body.camera.position.y,
req.body.camera.position.z,
req.body.camera.target.x,
req.body.camera.target.y,
req.body.camera.target.z
],
function(err, result) {
if (err !== null)
Log.dberror(err + ' in previousnext');
release();
}
);
});
res.setHeader('Content-Type', 'text/html');
res.send("");
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/posts/previous-next-clicked': 'index'
};

Some files were not shown because too many files have changed in this diff Show More