Some cleaning 😢
This commit is contained in:
17
server/403/index.html
Normal file
17
server/403/index.html
Normal 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
BIN
server/403/working.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 MiB |
9
server/controllers/before-begin/index.js
Normal file
9
server/controllers/before-begin/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
|
||||
3
server/controllers/before-begin/urls.js
Normal file
3
server/controllers/before-begin/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/before-begin': 'index',
|
||||
};
|
||||
24
server/controllers/before-begin/views/index.jade
Normal file
24
server/controllers/before-begin/views/index.jade
Normal 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';
|
||||
}
|
||||
|
||||
7
server/controllers/bouncing/index.js
Normal file
7
server/controllers/bouncing/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
3
server/controllers/bouncing/urls.js
Normal file
3
server/controllers/bouncing/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/bouncing' : 'index'
|
||||
};
|
||||
13
server/controllers/bouncing/views/index.jade
Normal file
13
server/controllers/bouncing/views/index.jade
Normal 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
|
||||
12
server/controllers/feedback/index.js
Normal file
12
server/controllers/feedback/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
|
||||
3
server/controllers/feedback/urls.js
Normal file
3
server/controllers/feedback/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/feedback': 'index',
|
||||
};
|
||||
85
server/controllers/feedback/views/index.jade
Normal file
85
server/controllers/feedback/views/index.jade
Normal 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
|
||||
|
||||
7
server/controllers/index/index.js
Normal file
7
server/controllers/index/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
3
server/controllers/index/urls.js
Normal file
3
server/controllers/index/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/': 'index'
|
||||
};
|
||||
41
server/controllers/index/views/index.jade
Normal file
41
server/controllers/index/views/index.jade
Normal 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 !
|
||||
12
server/controllers/intro/index.js
Normal file
12
server/controllers/intro/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
|
||||
4
server/controllers/intro/urls.js
Normal file
4
server/controllers/intro/urls.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
'/intro': 'index',
|
||||
'/intro/:workerId': 'index',
|
||||
};
|
||||
20
server/controllers/intro/views/index.jade
Normal file
20
server/controllers/intro/views/index.jade
Normal 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');
|
||||
}
|
||||
7
server/controllers/list/index.js
Normal file
7
server/controllers/list/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
3
server/controllers/list/urls.js
Normal file
3
server/controllers/list/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/list': 'index'
|
||||
};
|
||||
10
server/controllers/list/views/index.jade
Normal file
10
server/controllers/list/views/index.jade
Normal 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
|
||||
7
server/controllers/logout/index.js
Normal file
7
server/controllers/logout/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports.index = function(req, res) {
|
||||
|
||||
req.session = null;
|
||||
res.locals.session = null;
|
||||
res.redirect('/');
|
||||
|
||||
};
|
||||
3
server/controllers/logout/urls.js
Normal file
3
server/controllers/logout/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/logout': 'index'
|
||||
};
|
||||
7
server/controllers/multisphere/index.js
Normal file
7
server/controllers/multisphere/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
3
server/controllers/multisphere/urls.js
Normal file
3
server/controllers/multisphere/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/multisphere': 'index'
|
||||
};
|
||||
19
server/controllers/multisphere/views/index.jade
Normal file
19
server/controllers/multisphere/views/index.jade
Normal 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
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
278
server/controllers/prototype/index.js
vendored
Normal 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
15
server/controllers/prototype/urls.js
vendored
Normal 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'
|
||||
};
|
||||
17
server/controllers/prototype/views/index.jade
Normal file
17
server/controllers/prototype/views/index.jade
Normal 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>.
|
||||
54
server/controllers/prototype/views/prototype.jade
Normal file
54
server/controllers/prototype/views/prototype.jade
Normal 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")
|
||||
|
||||
15
server/controllers/prototype/views/prototype_checker.jade
Normal file
15
server/controllers/prototype/views/prototype_checker.jade
Normal 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
|
||||
|
||||
14
server/controllers/prototype/views/prototype_clicker.jade
Normal file
14
server/controllers/prototype/views/prototype_clicker.jade
Normal 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
|
||||
|
||||
@@ -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 !
|
||||
@@ -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.
|
||||
21
server/controllers/prototype/views/prototype_replays.jade
Normal file
21
server/controllers/prototype/views/prototype_replays.jade
Normal 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")
|
||||
17
server/controllers/prototype/views/prototype_reverse.jade
Normal file
17
server/controllers/prototype/views/prototype_reverse.jade
Normal 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.
|
||||
|
||||
14
server/controllers/prototype/views/prototype_viewer.jade
Normal file
14
server/controllers/prototype/views/prototype_viewer.jade
Normal 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
|
||||
|
||||
13
server/controllers/prototype/views/replay_index.jade
Normal file
13
server/controllers/prototype/views/replay_index.jade
Normal 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>
|
||||
22
server/controllers/prototype/views/sponza.jade
Normal file
22
server/controllers/prototype/views/sponza.jade
Normal 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.
|
||||
15
server/controllers/prototype/views/tutorial.jade
Normal file
15
server/controllers/prototype/views/tutorial.jade
Normal 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
|
||||
107
server/controllers/prototype/views/user_study.jade
Normal file
107
server/controllers/prototype/views/user_study.jade
Normal 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") ×
|
||||
<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;
|
||||
}
|
||||
}
|
||||
25
server/controllers/stream/index.js
Normal file
25
server/controllers/stream/index.js
Normal 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);
|
||||
});
|
||||
};
|
||||
3
server/controllers/stream/urls.js
Normal file
3
server/controllers/stream/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/stream/:res?': 'index'
|
||||
};
|
||||
48
server/controllers/stream/views/index.jade
Normal file
48
server/controllers/stream/views/index.jade
Normal 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
|
||||
25
server/controllers/thankyou/index.js
Normal file
25
server/controllers/thankyou/index.js
Normal 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);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
3
server/controllers/thankyou/urls.js
Normal file
3
server/controllers/thankyou/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/thankyou': 'index',
|
||||
};
|
||||
8
server/controllers/thankyou/views/normal.jade
Normal file
8
server/controllers/thankyou/views/normal.jade
Normal 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")
|
||||
|
||||
36
server/controllers/thankyou/views/vcode.jade
Normal file
36
server/controllers/thankyou/views/vcode.jade
Normal 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();
|
||||
39
server/controllers/vcode/index.js
Normal file
39
server/controllers/vcode/index.js
Normal 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');
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
3
server/controllers/vcode/urls.js
Normal file
3
server/controllers/vcode/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/vcode': 'index',
|
||||
};
|
||||
12
server/geo/Geo.js
Normal file
12
server/geo/Geo.js
Normal 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
17
server/geo/Makefile
Normal 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
504
server/geo/Mesh.js
Normal 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
381
server/geo/MeshContainer.js
Normal 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
553
server/geo/MeshStreamer.js
Normal 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
1
server/geo/mat1.json
Normal 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
1
server/geo/mat1.json.bak
Normal 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
1
server/geo/mat2.json
Normal 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
1
server/geo/mat2.json.bak
Normal 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
1
server/geo/mat3.json
Normal 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
1
server/geo/mat3.json.bak
Normal 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]]
|
||||
1
server/geo/matt1.json.bak
Normal file
1
server/geo/matt1.json.bak
Normal 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/geo/matt2.json.bak
Normal file
1
server/geo/matt2.json.bak
Normal 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/geo/matt3.json.bak
Normal file
1
server/geo/matt3.json.bak
Normal 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
141
server/lib/Matrix.js
Normal 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
85
server/lib/NodeLog.js
Normal 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
101
server/lib/Serial.js
Normal 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
43
server/lib/controllers.js
Normal 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
6
server/lib/filterInt.js
Normal 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
1
server/lib/mat1.json
Normal 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
1
server/lib/mat2.json
Normal 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
1
server/lib/mat3.json
Normal 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
1
server/lib/matt1.json
Normal 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
1
server/lib/matt2.json
Normal 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
1
server/lib/matt3.json
Normal 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
43
server/lib/posts.js
Normal 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);
|
||||
});
|
||||
};
|
||||
1
server/lib/tests/myMatrix.json
Normal file
1
server/lib/tests/myMatrix.json
Normal file
@@ -0,0 +1 @@
|
||||
[[0,0,0],[0,0,3]]
|
||||
9
server/lib/vcode.js
Normal file
9
server/lib/vcode.js
Normal 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
1040
server/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
server/package.json
Normal file
22
server/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
21
server/posts/arrow-clicked/index.js
Normal file
21
server/posts/arrow-clicked/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/arrow-clicked/urls.js
Normal file
3
server/posts/arrow-clicked/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/arrow-clicked': 'index'
|
||||
};
|
||||
21
server/posts/coin-clicked/index.js
Normal file
21
server/posts/coin-clicked/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/coin-clicked/urls.js
Normal file
3
server/posts/coin-clicked/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/coin-clicked': 'index'
|
||||
};
|
||||
19
server/posts/coin-info/index.js
Normal file
19
server/posts/coin-info/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/coin-info/urls.js
Normal file
3
server/posts/coin-info/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/coin-info': 'index'
|
||||
};
|
||||
43
server/posts/feedback-target/index.js
Normal file
43
server/posts/feedback-target/index.js
Normal 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');
|
||||
|
||||
};
|
||||
3
server/posts/feedback-target/urls.js
Normal file
3
server/posts/feedback-target/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/feedback-target': 'index'
|
||||
};
|
||||
21
server/posts/fps/index.js
Normal file
21
server/posts/fps/index.js
Normal 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
3
server/posts/fps/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/fps': 'index'
|
||||
};
|
||||
27
server/posts/hovered/index.js
Normal file
27
server/posts/hovered/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/hovered/urls.js
Normal file
3
server/posts/hovered/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/hovered': 'index'
|
||||
};
|
||||
32
server/posts/identification/index.js
Normal file
32
server/posts/identification/index.js
Normal 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');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
3
server/posts/identification/urls.js
Normal file
3
server/posts/identification/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/identification': 'index'
|
||||
};
|
||||
36
server/posts/keyboard-event/index.js
Normal file
36
server/posts/keyboard-event/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/keyboard-event/urls.js
Normal file
3
server/posts/keyboard-event/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/keyboard-event': 'index'
|
||||
};
|
||||
21
server/posts/pointer-locked/index.js
Normal file
21
server/posts/pointer-locked/index.js
Normal 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("");
|
||||
};
|
||||
3
server/posts/pointer-locked/urls.js
Normal file
3
server/posts/pointer-locked/urls.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/posts/pointer-locked': 'index'
|
||||
};
|
||||
33
server/posts/previous-next-clicked/index.js
Normal file
33
server/posts/previous-next-clicked/index.js
Normal 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("");
|
||||
|
||||
};
|
||||
3
server/posts/previous-next-clicked/urls.js
Normal file
3
server/posts/previous-next-clicked/urls.js
Normal 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
Reference in New Issue
Block a user