Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
479 lines (370 sloc) 14.7 KB
<!doctype html>
<html lang="en">
<head>
<title>Castelloscopi</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link href="css/font-awesome.min.css" rel="stylesheet">
<script src="js/jquery-1.9.1.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="css/bootstrap.min.css" >
<!-- Optional theme -->
<link rel="stylesheet" href="css/bootstrap-theme.min.css" >
<link rel=stylesheet href="css/base.css"/>
<!-- Latest compiled and minified JavaScript -->
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<!-- Button trigger modal -->
<div class="modal fade" id="videoModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button ontouchstart="closeDialog()" onclick="closeDialog()" type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h2 class="modal-title" id="casteller-name"></h2>
</div>
<div class="modal-body">
<div id="casteller-video"></div>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div id="castelloscopi_virtual">
<h1>castelloscopi virtual</h1>
<p>totes les mirades d'un castell</p>
</div>
<div id="loading">
<i class="icon-cog icon-spin"></i> carregant les animacions
</div>
<div id="footer">
<p>Si els castells són una activitat integradora accessible per a tothom, el Castelloscopi també!</p>
</div>
<div id="castelloscopi_logo">
<img src="./images/logo_castelloscopi.png" />
</div>
<!-- ------------------------------------------------------------ -->
<div id="ThreeJS" style="position: absolute; left:0px; top:0px"></div>
<script type="text/javascript">
$(window).load(function(){
$('#loading').remove()
})
</script>
<script type="x-shader/x-vertex" id="vertexShader">
varying vec3 vWorldPosition;
void main() {
vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
vWorldPosition = worldPosition.xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script type="x-shader/x-fragment" id="fragmentShader">
uniform vec3 topColor;
uniform vec3 bottomColor;
uniform float offset;
uniform float exponent;
varying vec3 vWorldPosition;
void main() {
float h = normalize( vWorldPosition + offset ).y;
gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );
}
</script>
<script>
// standard global variables
var container, scene, camera, light, renderer, cameraControls, stats;
var clock = new THREE.Clock();
// custom global variables
var casteller_textures = [];
var castellers;
var INTERSECTED;
var raycaster;
var mouse;
var objects = [];
var projector;
var touchX = null;
var touchY = null;
init();
animate();
// FUNCTIONS
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 10000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(0,250,600);
// SCENE
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
scene.fog.color.setHSL( 0.6, 0, 1 );
scene.add( camera );
camera.name = "camera";
// LIGHTS
hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
hemiLight.color.setHSL( 0.6, 1, 0.6 );
hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
hemiLight.position.set( 0, 500, 0 );
scene.add( hemiLight );
dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
dirLight.color.setHSL( 0.1, 1, 0.95 );
dirLight.position.set( -1, 1.75, 1 );
dirLight.position.multiplyScalar( 50 );
scene.add( dirLight );
dirLight.castShadow = true;
dirLight.shadowMapWidth = 2048;
dirLight.shadowMapHeight = 2048;
var d = 50;
dirLight.shadowCameraLeft = -d;
dirLight.shadowCameraRight = d;
dirLight.shadowCameraTop = d;
dirLight.shadowCameraBottom = -d;
dirLight.shadowCameraFar = 3500;
dirLight.shadowBias = -0.0001;
// GROUND
var groundGeo = new THREE.PlaneBufferGeometry( 10000, 10000 );
var groundMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x050505 } );
groundMat.color.setHSL( 0.095, 1, 0.75 );
var ground = new THREE.Mesh( groundGeo, groundMat );
ground.rotation.x = -Math.PI/2;
ground.position.y = -33;
scene.add( ground );
ground.receiveShadow = true;
// SKYDOME
var vertexShader = document.getElementById( 'vertexShader' ).textContent;
var fragmentShader = document.getElementById( 'fragmentShader' ).textContent;
var uniforms = {
topColor: { type: "c", value: new THREE.Color( 0x0077ff ) },
bottomColor: { type: "c", value: new THREE.Color( 0xffffff ) },
offset: { type: "f", value: 33 },
exponent: { type: "f", value: 0.6 }
};
uniforms.topColor.value.copy( hemiLight.color );
scene.fog.color.copy( uniforms.bottomColor.value );
var skyGeo = new THREE.SphereGeometry( 4000, 32, 15 );
var skyMat = new THREE.ShaderMaterial( { vertexShader: vertexShader, fragmentShader: fragmentShader, uniforms: uniforms, side: THREE.BackSide } );
var sky = new THREE.Mesh( skyGeo, skyMat );
scene.add( sky );
// RENDERER
renderer = new THREE.WebGLRenderer( );
renderer.setClearColor( scene.fog.color );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
container.appendChild( renderer.domElement );
// CONTROLS
cameraControls = new THREE.OrbitControls( camera, renderer.domElement );
cameraControls.target.set( 0, 50, 0 );
// EVENTS
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchend', onDocumentTouchEnd, false );
// initialize object to perform world/screen calculations
raycaster = new THREE.Raycaster();
projector = new THREE.Projector();
mouse = new THREE.Vector2();
// CHARACTERS
loadJSON(function(response) {
// Parse JSON string into object
castellers = JSON.parse(response);
// ANIMATED TEXTURES!
for (var i = 0; i < castellers.length; i++) {
var castellerMaterial = '';
if(castellers[i].image){
//video screen
var castellerTexture = new THREE.ImageUtils.loadTexture( 'images/castellers/'+castellers[i].image);
castellerMaterial = new THREE.MeshBasicMaterial( { map: castellerTexture, side:THREE.DoubleSide, overdraw: true } );
} else {
//black screen
//canvas texture (casteller id)
// create a canvas element
var bkackscreen_canvas = document.createElement('canvas');
var bkackscreen_context = bkackscreen_canvas.getContext('2d');
bkackscreen_context.font = "Bold 30px Arial";
bkackscreen_context.fillStyle = "rgba(255,255,255,1)";
bkackscreen_context.fillText(castellers[i].name, 10, castellers[i].size);
// canvas contents will be used for a texture
var bkackscreen_texture = new THREE.Texture(bkackscreen_canvas)
bkackscreen_texture.needsUpdate = true;
castellerMaterial = new THREE.MeshBasicMaterial( { map: bkackscreen_texture, color: 0xFDFDFD, overdraw: true } );
}
var canvas_2d_text = '';
if (castellers[i].id == 6 || castellers[i].id == 38 || castellers[i].id == 39) {
canvas_2d_text = castellers[i].name;
} else {
canvas_2d_text = castellers[i].id;
}
casteller_textures[i] = new TextureAnimator( castellerTexture, 64, 1, 64, 200 ); // texture, #horiz, #vert, #total, duration.
var casteller_size = castellers[i].size;
//canvas texture (casteller id)
// create a canvas element
var casteller_id_canvas = document.createElement('canvas');
var casteller_id_context = casteller_id_canvas.getContext('2d');
casteller_id_context.font = "Bold 30px Arial";
casteller_id_context.fillStyle = "rgba(255,255,255,1)";
casteller_id_context.fillText(canvas_2d_text, 10, casteller_size);
// canvas contents will be used for a texture
var casteller_id_texture = new THREE.Texture(casteller_id_canvas)
casteller_id_texture.needsUpdate = true;
var materials = []
materials.push(new THREE.MeshBasicMaterial( { color: 0x816183, overdraw: true } ));
materials.push(new THREE.MeshBasicMaterial( { color: 0x816183, overdraw: true } ));
materials.push(new THREE.MeshBasicMaterial( { color: 0x816183, overdraw: true } ));
materials.push(new THREE.MeshBasicMaterial( { color: 0x816183, overdraw: true } ));
materials.push(castellerMaterial);
materials.push(new THREE.MeshBasicMaterial( { map: casteller_id_texture, color: 0xFDFDFD, overdraw: true } ));
var castellerGeometry = new THREE.CubeGeometry(casteller_size, casteller_size, 1, 1, 1, 1 );
var facesMaterial = new THREE.MeshFaceMaterial(materials);
var casteller = new THREE.Mesh(castellerGeometry, facesMaterial);
casteller.name = castellers[i].name;
casteller.casteller_id = castellers[i].id;
casteller.overdraw = true;
casteller.rotation.y = Math.PI * castellers[i].position.rotation_y;
casteller.rotation.x = Math.PI * castellers[i].position.rotation_x;
casteller.position.set(
castellers[i].position.axis_x,
castellers[i].position.axis_y,
castellers[i].position.axis_z
);
scene.add(casteller);
objects.push(casteller);
};
});
}
function onWindowResize() {
SCREEN_WIDTH = window.innerWidth;
SCREEN_HEIGHT = window.innerHeight;
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
camera.aspect = SCREEN_WIDTH/ SCREEN_HEIGHT;
camera.updateProjectionMatrix();
}
function animate()
{
requestAnimationFrame( animate );
render();
update();
}
function update()
{
var delta = clock.getDelta();
for (var i = 0; i < casteller_textures.length; i++) {
casteller_textures[i].update(1000 * delta);
};
cameraControls.update();
}
function onDocumentTouchStart( event ) {
touchX = event.changedTouches[0].clientX;
touchY = event.changedTouches[0].clientY;
event.preventDefault();
}
function onDocumentTouchEnd( event ) {
if ($("#casteller-video video").length === 0) {
event.clientX = event.changedTouches[0].clientX;
event.clientY = event.changedTouches[0].clientY;
var diffX = Math.abs( event.clientX - touchX );
var diffY = Math.abs( event.clientY - touchY );
if (diffX < 2 && diffY < 2) {
touchX = 0;
touchY = 0;
openVideoDialog( event );
}
}
event.preventDefault();
}
function openVideoDialog( event ) {
if ($("#casteller-video video").length === 0) {
event.preventDefault();
// update the mouse variable
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects( objects );
if ( intersects.length > 0 ) {
// store reference to closest object as current intersection object
INTERSECTED = intersects[ 0 ].object;
var casteller_id = INTERSECTED.casteller_id;
var casteller;
for (var i = 0; i < castellers.length; i++) {
if (castellers[i].id==casteller_id){
casteller = castellers[i];
}
}
if (casteller.video !== '') {
console.log("Environment.getExternalStorageState()");
console.log(Environment.getExternalStorageState());
$("#casteller-video").empty();
$("#casteller-video").append("<video poster='images/logo_castelloscopi.png' width='1067px' height='600px' src='file:///storage/sdcard1/castelloscopi/videos/"+casteller.video+"' controls autoplay loop></video>");
$("#casteller-name").empty();
$("#casteller-name").append(casteller.name);
$('#videoModal').css('display','block');
$('#videoModal').addClass("in");
}
} else {
closeDialog();
}
}
}
function render()
{
renderer.render( scene, camera );
}
function TextureAnimator(texture, tilesHoriz, tilesVert, numTiles, tileDispDuration)
{
// note: texture passed by reference, will be updated by the update function.
this.tilesHorizontal = tilesHoriz;
this.tilesVertical = tilesVert;
// how many images does this spritesheet contain?
// usually equals tilesHoriz * tilesVert, but not necessarily,
// if there at blank tiles at the bottom of the spritesheet.
this.numberOfTiles = numTiles;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1 / this.tilesHorizontal, 1 / this.tilesVertical );
// how long should each image be displayed?
this.tileDisplayDuration = tileDispDuration;
// how long has the current image been displayed?
this.currentDisplayTime = 0;
// which image is currently being displayed?
this.currentTile = 0;
this.update = function( milliSec )
{
this.currentDisplayTime += milliSec;
while (this.currentDisplayTime > this.tileDisplayDuration)
{
this.currentDisplayTime -= this.tileDisplayDuration;
this.currentTile++;
if (this.currentTile == this.numberOfTiles)
this.currentTile = 0;
var currentColumn = this.currentTile % this.tilesHorizontal;
texture.offset.x = currentColumn / this.tilesHorizontal;
var currentRow = Math.floor( this.currentTile / this.tilesHorizontal );
texture.offset.y = currentRow / this.tilesVertical;
}
};
}
function loadJSON(callback) {
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'castellers.json', true);
xobj.onreadystatechange = function () {
if (xobj.readyState == 4 && xobj.status == "200") {
// Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
callback(xobj.responseText);
}
};
xobj.send(null);
}
function closeDialog() {
$("#casteller-video").empty();
$('#videoModal').css('display','none');
$('#videoModal').removeClass("in");
}
</script>
</body>
</html>