1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 var camera, controls, scene, projector, renderer;
8 var lastSceneDescription;
9 var skipSceneUpdates = 0;
11 var holdObjectIndex = -1;
13 var mouse = new THREE.Vector2();
14 var offset = new THREE.Vector3();
15 var INTERSECTED, SELECTED;
17 var sceneDescription = [];
22 function clearWorld() {
23 for (var i = 0; i < objects.length; i++) {
24 scene.remove(objects[i]);
28 // Make sure we drop the object.
31 NaClAMBulletDropObject();
34 function loadShape(shape) {
35 if (shapes[shape.name] != undefined) {
36 return shapes[shape.name];
39 if (shape.type == "cube") {
40 shapes[shape.name] = new THREE.CubeGeometry(shape['wx'], shape['wy'], shape['wz']);
41 return shapes[shape.name];
44 if (shape.type == "convex") {
46 for (var i = 0; i < shape['points'].length; i++) {
47 vertices.push(new THREE.Vector3(shape['points'][i][0], shape['points'][i][1], shape['points'][i][2]));
49 shapes[shape.name] = new THREE.ConvexGeometry(vertices);
50 return shapes[shape.name];
53 if (shape.type == "cylinder") {
54 shapes[shape.name] = new THREE.CylinderGeometry(shape['radius'], shape['radius'], shape['height'])
55 return shapes[shape.name];
58 if (shape.type == "sphere") {
59 shapes[shape.name] = new THREE.SphereGeometry(shape['radius']);
60 return shapes[shape.name];
66 function loadBody(body) {
67 var shape = shapes[body.shape];
68 if (shape == undefined) {
72 var object = new THREE.Mesh( shape, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
74 object.material.ambient = object.material.color;
76 object.position.x = body.position.x;
77 object.position.y = body.position.y;
78 object.position.z = body.position.z;
80 object.rotation.x = body.rotation.x;
81 object.rotation.y = body.rotation.y;
82 object.rotation.z = body.rotation.z;
84 object.updateMatrixWorld(true);
85 var T = [object.matrixWorld.elements[0],
86 object.matrixWorld.elements[1],
87 object.matrixWorld.elements[2],
88 object.matrixWorld.elements[3],
89 object.matrixWorld.elements[4],
90 object.matrixWorld.elements[5],
91 object.matrixWorld.elements[6],
92 object.matrixWorld.elements[7],
93 object.matrixWorld.elements[8],
94 object.matrixWorld.elements[9],
95 object.matrixWorld.elements[10],
96 object.matrixWorld.elements[11],
97 object.matrixWorld.elements[12],
98 object.matrixWorld.elements[13],
99 object.matrixWorld.elements[14],
100 object.matrixWorld.elements[15]];
103 object.castShadow = false;
104 object.receiveShadow = false;
105 object.matrixAutoUpdate = false;
106 object.objectTableIndex = objects.length;
108 objects.push(object);
113 function loadWorld(worldDescription) {
116 var shapes = worldDescription['shapes'];
117 var bodies = worldDescription['bodies'];
118 for (i = 0; i < shapes.length; i++) {
119 if (loadShape(shapes[i]) == undefined) {
120 console.log('Could not load shape ' + shapes[i].name);
124 for (i = 0; i < bodies.length; i++) {
125 if (loadBody(bodies[i]) == undefined) {
126 console.log('Could not make body.');
130 var r = verifyWorldDescription(worldDescription);
132 alert('Invalid scene description. See console.');
135 skipSceneUpdates = 4;
136 NaClAMBulletLoadScene(worldDescription);
137 lastSceneDescription = worldDescription;
140 function reloadScene() {
141 if (lastSceneDescription)
142 loadWorld(lastSceneDescription);
146 return document.getElementById(id);
150 var rendererContainer = $('rendererContainer');
151 var rcW = rendererContainer.clientWidth;
152 var rcH = rendererContainer.clientHeight;
154 camera = new THREE.PerspectiveCamera(
156 rcW / rcH, 1, 10000);
157 camera.position.y = 20.0;
158 camera.position.z = 40;
160 scene = new THREE.Scene();
162 scene.add( new THREE.AmbientLight( 0x505050 ) );
164 var light = new THREE.SpotLight( 0xffffff, 1.5 );
165 light.position.set( 0, 500, 2000 );
166 light.castShadow = true;
168 light.shadowCameraNear = 200;
169 light.shadowCameraFar = camera.far;
170 light.shadowCameraFov = 50;
172 light.shadowBias = -0.00022;
173 light.shadowDarkness = 0.5;
175 light.shadowMapWidth = 2048;
176 light.shadowMapHeight = 2048;
180 plane = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200, 100, 100), new THREE.MeshBasicMaterial( { color: 0x000000, opacity: 0.25, transparent: true, wireframe: true } ) );
181 plane.rotation.x = Math.PI * 0.5;
182 plane.visible = true;
184 projector = new THREE.Projector();
186 renderer = new THREE.WebGLRenderer( { antialias: true } );
187 renderer.sortObjects = false;
188 renderer.setSize( rcW, rcH );
189 lastRendererWidth = rcW;
190 lastRendererWidth = rcH;
192 renderer.shadowMapEnabled = true;
193 renderer.shadowMapSoft = true;
195 rendererContainer.appendChild(renderer.domElement);
198 jenga10: loadJenga10,
199 jenga20: loadJenga20,
200 randomShapes: loadRandomShapes,
201 randomCube250: load250RandomCubes,
202 randomCylinder500: load500RandomCylinders,
203 randomCube1000: load1000RandomCubes,
204 randomCube2000: load2000RandomCubes
207 for (var id in idFuncHash) {
208 var func = idFuncHash[id];
209 $(id).addEventListener('click', func, false);
212 $('reload').addEventListener('click', reloadScene, false);
214 rendererContainer.addEventListener('mousedown', onMouseDown, false);
215 rendererContainer.addEventListener('mouseup', onMouseUp, false);
216 rendererContainer.addEventListener('mouseleave', onMouseUp, false);
217 renderer.domElement.addEventListener('mousemove', onMouseMove, false);
219 // Add the OrbitControls after our own listeners -- that way we can prevent
220 // the camera rotation when dragging an object.
221 controls = new THREE.OrbitControls(camera, rendererContainer);
223 window.setInterval(pollForRendererResize, 10);
226 function pollForRendererResize() {
227 var rendererContainer = $('rendererContainer');
228 var w = rendererContainer.clientWidth;
229 var h = rendererContainer.clientHeight;
230 if (w == lastRendererWidth && h == lastRendererHeight)
233 camera.aspect = w / h;
234 camera.updateProjectionMatrix();
235 renderer.setSize( w, h );
236 lastRendererWidth = w;
237 lastRendererHeight = h;
240 function onMouseDown(event) {
241 event.preventDefault();
243 var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
244 projector.unprojectVector( vector, camera );
245 var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
246 var intersects = ray.intersectObjects( objects );
247 if (intersects.length > 0) {
248 if (intersects[0].object != plane) {
250 SELECTED = intersects[0].object;
251 //console.log(SELECTED.objectTableIndex);
252 NaClAMBulletPickObject(SELECTED.objectTableIndex, camera.position, intersects[0].point);
253 // stopImmediatePropagation() will prevent other event listeners on the
254 // same element from firing -- in this case, the OrbitControls camera
256 event.stopImmediatePropagation();
261 function onMouseUp(event) {
264 SELECTED = undefined;
265 NaClAMBulletDropObject();
266 event.stopImmediatePropagation();
270 function onMouseMove( event ) {
271 event.preventDefault();
273 var clientRect = $('rendererContainer').getClientRects()[0];
274 var x = event.clientX - clientRect.left;
275 var y = event.clientY - clientRect.top;
276 var w = clientRect.width;
277 var h = clientRect.height;
279 mouse.x = ( x / w ) * 2 - 1;
280 mouse.y = -( y / h ) * 2 + 1;
281 var vector = new THREE.Vector3( mouse.x, mouse.y, 0.5 );
282 projector.unprojectVector( vector, camera );
291 window.requestAnimationFrame(animate);
292 aM.sendMessage('stepscene', {rayFrom: [camera.position.x, camera.position.y, camera.position.z], rayTo: [offset.x, offset.y, offset.z]});
298 renderer.render( scene, camera );