// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
var container, stats;
var camera, controls, scene, projector, renderer;
var plane;
var lastSceneDescription;
var skipSceneUpdates = 0;
var hold = false;
var holdObjectIndex = -1;
var mouse = new THREE.Vector2();
var offset = new THREE.Vector3();
var INTERSECTED, SELECTED;
var sceneDescription = [];
var shapes = {};
var objects = [];
function clearWorld() {
for (var i = 0; i < objects.length; i++) {
scene.remove(objects[i]);
}
objects = [];
shapes = {};
// Make sure we drop the object.
hold = false;
SELECTED = undefined;
NaClAMBulletDropObject();
}
function loadShape(shape) {
if (shapes[shape.name] != undefined) {
return shapes[shape.name];
}
if (shape.type == "cube") {
shapes[shape.name] = new THREE.CubeGeometry(shape['wx'], shape['wy'], shape['wz']);
return shapes[shape.name];
}
if (shape.type == "convex") {
var vertices = [];
for (var i = 0; i < shape['points'].length; i++) {
vertices.push(new THREE.Vector3(shape['points'][i][0], shape['points'][i][1], shape['points'][i][2]));
}
shapes[shape.name] = new THREE.ConvexGeometry(vertices);
return shapes[shape.name];
}
if (shape.type == "cylinder") {
shapes[shape.name] = new THREE.CylinderGeometry(shape['radius'], shape['radius'], shape['height'])
return shapes[shape.name];
}
if (shape.type == "sphere") {
shapes[shape.name] = new THREE.SphereGeometry(shape['radius']);
return shapes[shape.name];
}
return undefined;
}
function loadBody(body) {
var shape = shapes[body.shape];
if (shape == undefined) {
return shape;
}
var object = new THREE.Mesh( shape, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
object.material.ambient = object.material.color;
object.position.x = body.position.x;
object.position.y = body.position.y;
object.position.z = body.position.z;
object.rotation.x = body.rotation.x;
object.rotation.y = body.rotation.y;
object.rotation.z = body.rotation.z;
object.updateMatrixWorld(true);
var T = [object.matrixWorld.elements[0],
object.matrixWorld.elements[1],
object.matrixWorld.elements[2],
object.matrixWorld.elements[3],
object.matrixWorld.elements[4],
object.matrixWorld.elements[5],
object.matrixWorld.elements[6],
object.matrixWorld.elements[7],
object.matrixWorld.elements[8],
object.matrixWorld.elements[9],
object.matrixWorld.elements[10],
object.matrixWorld.elements[11],
object.matrixWorld.elements[12],
object.matrixWorld.elements[13],
object.matrixWorld.elements[14],
object.matrixWorld.elements[15]];
body.transform = T;
object.castShadow = false;
object.receiveShadow = false;
object.matrixAutoUpdate = false;
object.objectTableIndex = objects.length;
scene.add(object);
objects.push(object);
return object;
}
function loadWorld(worldDescription) {
clearWorld();
var i;
var shapes = worldDescription['shapes'];
var bodies = worldDescription['bodies'];
for (i = 0; i < shapes.length; i++) {
if (loadShape(shapes[i]) == undefined) {
console.log('Could not load shape ' + shapes[i].name);
}
}
for (i = 0; i < bodies.length; i++) {
if (loadBody(bodies[i]) == undefined) {
console.log('Could not make body.');
}
}
var r = verifyWorldDescription(worldDescription);
if (r == false) {
alert('Invalid scene description. See console.');
return;
}
skipSceneUpdates = 4;
NaClAMBulletLoadScene(worldDescription);
lastSceneDescription = worldDescription;
}
function reloadScene() {
if (lastSceneDescription)
loadWorld(lastSceneDescription);
}
function $(id) {
return document.getElementById(id);
}
function init() {
var rendererContainer = $('rendererContainer');
var rcW = rendererContainer.clientWidth;
var rcH = rendererContainer.clientHeight;
camera = new THREE.PerspectiveCamera(
70,
rcW / rcH, 1, 10000);
camera.position.y = 20.0;
camera.position.z = 40;
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x505050 ) );
var light = new THREE.SpotLight( 0xffffff, 1.5 );
light.position.set( 0, 500, 2000 );
light.castShadow = true;
light.shadowCameraNear = 200;
light.shadowCameraFar = camera.far;
light.shadowCameraFov = 50;
light.shadowBias = -0.00022;
light.shadowDarkness = 0.5;
light.shadowMapWidth = 2048;
light.shadowMapHeight = 2048;
scene.add( light );
plane = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200, 100, 100), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) );
plane.rotation.x = Math.PI * 0.5;
plane.visible = true;
scene.add( plane );
projector = new THREE.Projector();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.sortObjects = false;
renderer.setSize( rcW, rcH );
lastRendererWidth = rcW;
lastRendererWidth = rcH;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
rendererContainer.appendChild(renderer.domElement);
var idFuncHash = {
jenga10: loadJenga10,
jenga20: loadJenga20,
randomShapes: loadRandomShapes,
randomCube250: load250RandomCubes,
randomCylinder500: load500RandomCylinders,
randomCube1000: load1000RandomCubes,
randomCube2000: load2000RandomCubes
};
for (var id in idFuncHash) {
var func = idFuncHash[id];
$(id).addEventListener('click', func, false);
}
$('reload').addEventListener('click', reloadScene, false);
rendererContainer.addEventListener('mousedown', onMouseDown, false);
rendererContainer.addEventListener('mouseup', onMouseUp, false);
rendererContainer.addEventListener('mouseleave', onMouseUp, false);
renderer.domElement.addEventListener('mousemove', onMouseMove, false);
// Add the OrbitControls after our own listeners -- that way we can prevent
// the camera rotation when dragging an object.
controls = new THREE.OrbitControls(camera, rendererContainer);
window.setInterval(pollForRendererResize, 10);
}
function pollForRendererResize() {
var rendererContainer = $('rendererContainer');
var w = rendererContainer.clientWidth;
var h = rendererContainer.clientHeight;
if (w == lastRendererWidth && h == lastRendererHeight)
return;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
lastRendererWidth = w;
lastRendererHeight = h;
}
function onMouseDown(event) {
event.preventDefault();
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( objects );
if (intersects.length > 0) {
if (intersects[0].object != plane) {
hold = true;
SELECTED = intersects[0].object;
//console.log(SELECTED.objectTableIndex);
NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
// stopImmediatePropagation() will prevent other event listeners on the
// same element from firing -- in this case, the OrbitControls camera
// rotation.
event.stopImmediatePropagation();
}
}
}
function onMouseUp(event) {
if (hold) {
hold = false;
SELECTED = undefined;
NaClAMBulletDropObject();
event.stopImmediatePropagation();
}
}
function onMouseMove( event ) {
event.preventDefault();
var clientRect = $('rendererContainer').getClientRects()[0];
var x = event.clientX - clientRect.left;
var y = event.clientY - clientRect.top;
var w = clientRect.width;
var h = clientRect.height;
mouse.x = ( x / w ) * 2 - 1;
mouse.y = -( y / h ) * 2 + 1;
var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
projector.unprojectVector( vector, camera );
offset.x = vector.x;
offset.y = vector.y;
offset.z = vector.z;
}
//
function animate() {
window.requestAnimationFrame(animate);
aM.sendMessage('stepscene', {rayFrom: [camera.position.x, camera.position.y, camera.position.z], rayTo: [offset.x, offset.y, offset.z]});
render();
}
function render() {
controls.update();
renderer.render( scene, camera );
}