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
);