Home | History | Annotate | Download | only in bullet
      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.
      4 
      5 var container, stats;
      6 var camera, controls, scene, projector, renderer;
      7 var plane;
      8 var lastSceneDescription;
      9 var skipSceneUpdates = 0;
     10 var hold = false;
     11 var holdObjectIndex = -1;
     12 
     13 var mouse = new THREE.Vector2();
     14 var offset = new THREE.Vector3();
     15 var INTERSECTED, SELECTED;
     16 
     17 var sceneDescription = [];
     18 
     19 var shapes = {};
     20 var objects = [];
     21 
     22 function clearWorld() {
     23   for (var i = 0; i < objects.length; i++) {
     24     scene.remove(objects[i]);
     25   }
     26   objects = [];
     27   shapes = {};
     28   // Make sure we drop the object.
     29   hold = false;
     30   SELECTED = undefined;
     31   NaClAMBulletDropObject();
     32 }
     33 
     34 function loadShape(shape) {
     35   if (shapes[shape.name] != undefined) {
     36     return shapes[shape.name];
     37   }
     38 
     39   if (shape.type == "cube") {
     40     shapes[shape.name] = new THREE.CubeGeometry(shape['wx'], shape['wy'], shape['wz']);
     41     return shapes[shape.name];
     42   }
     43 
     44   if (shape.type == "convex") {
     45     var vertices = [];
     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]));
     48     }
     49     shapes[shape.name] = new THREE.ConvexGeometry(vertices);
     50     return shapes[shape.name];
     51   }
     52 
     53   if (shape.type == "cylinder") {
     54     shapes[shape.name] = new THREE.CylinderGeometry(shape['radius'], shape['radius'], shape['height'])
     55       return shapes[shape.name];
     56   }
     57 
     58   if (shape.type == "sphere") {
     59     shapes[shape.name] = new THREE.SphereGeometry(shape['radius']);
     60     return shapes[shape.name];
     61   }
     62 
     63   return undefined;
     64 }
     65 
     66 function loadBody(body) {
     67   var shape = shapes[body.shape];
     68   if (shape == undefined) {
     69     return shape;
     70   }
     71 
     72   var object = new THREE.Mesh( shape, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );
     73 
     74   object.material.ambient = object.material.color;
     75 
     76   object.position.x = body.position.x;
     77   object.position.y = body.position.y;
     78   object.position.z = body.position.z;
     79 
     80   object.rotation.x = body.rotation.x;
     81   object.rotation.y = body.rotation.y;
     82   object.rotation.z = body.rotation.z;
     83 
     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]];
    101   body.transform = T;
    102 
    103   object.castShadow = false;
    104   object.receiveShadow = false;
    105   object.matrixAutoUpdate = false;
    106   object.objectTableIndex = objects.length;
    107   scene.add(object);
    108   objects.push(object);
    109 
    110   return object;
    111 }
    112 
    113 function loadWorld(worldDescription) {
    114   clearWorld();
    115   var i;
    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);
    121     }
    122   }
    123 
    124   for (i = 0; i < bodies.length; i++) {
    125     if (loadBody(bodies[i]) == undefined) {
    126       console.log('Could not make body.');
    127     }
    128   }
    129 
    130   var r = verifyWorldDescription(worldDescription);
    131   if (r == false) {
    132     alert('Invalid scene description. See console.');
    133     return;
    134   }
    135   skipSceneUpdates = 4;
    136   NaClAMBulletLoadScene(worldDescription);
    137   lastSceneDescription = worldDescription;
    138 }
    139 
    140 function reloadScene() {
    141   if (lastSceneDescription)
    142     loadWorld(lastSceneDescription);
    143 }
    144 
    145 function $(id) {
    146   return document.getElementById(id);
    147 }
    148 
    149 function init() {
    150   var rendererContainer = $('rendererContainer');
    151   var rcW = rendererContainer.clientWidth;
    152   var rcH = rendererContainer.clientHeight;
    153 
    154   camera = new THREE.PerspectiveCamera(
    155       70,
    156       rcW / rcH, 1, 10000);
    157   camera.position.y = 20.0;
    158   camera.position.z = 40;
    159 
    160   scene = new THREE.Scene();
    161 
    162   scene.add( new THREE.AmbientLight( 0x505050 ) );
    163 
    164   var light = new THREE.SpotLight( 0xffffff, 1.5 );
    165   light.position.set( 0, 500, 2000 );
    166   light.castShadow = true;
    167 
    168   light.shadowCameraNear = 200;
    169   light.shadowCameraFar = camera.far;
    170   light.shadowCameraFov = 50;
    171 
    172   light.shadowBias = -0.00022;
    173   light.shadowDarkness = 0.5;
    174 
    175   light.shadowMapWidth = 2048;
    176   light.shadowMapHeight = 2048;
    177 
    178   scene.add( light );
    179 
    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;
    183   scene.add( plane );
    184   projector = new THREE.Projector();
    185 
    186   renderer = new THREE.WebGLRenderer( { antialias: true } );
    187   renderer.sortObjects = false;
    188   renderer.setSize( rcW, rcH );
    189   lastRendererWidth = rcW;
    190   lastRendererWidth = rcH;
    191 
    192   renderer.shadowMapEnabled = true;
    193   renderer.shadowMapSoft = true;
    194 
    195   rendererContainer.appendChild(renderer.domElement);
    196 
    197   var idFuncHash = {
    198     jenga10: loadJenga10,
    199     jenga20: loadJenga20,
    200     randomShapes: loadRandomShapes,
    201     randomCube250: load250RandomCubes,
    202     randomCylinder500: load500RandomCylinders,
    203     randomCube1000: load1000RandomCubes,
    204     randomCube2000: load2000RandomCubes
    205   };
    206 
    207   for (var id in idFuncHash) {
    208     var func = idFuncHash[id];
    209     $(id).addEventListener('click', func, false);
    210   }
    211 
    212   $('reload').addEventListener('click', reloadScene, false);
    213 
    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);
    218 
    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);
    222 
    223   window.setInterval(pollForRendererResize, 10);
    224 }
    225 
    226 function pollForRendererResize() {
    227   var rendererContainer = $('rendererContainer');
    228   var w = rendererContainer.clientWidth;
    229   var h = rendererContainer.clientHeight;
    230   if (w == lastRendererWidth && h == lastRendererHeight)
    231     return;
    232 
    233   camera.aspect = w / h;
    234   camera.updateProjectionMatrix();
    235   renderer.setSize( w, h );
    236   lastRendererWidth = w;
    237   lastRendererHeight = h;
    238 }
    239 
    240 function onMouseDown(event) {
    241   event.preventDefault();
    242 
    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) {
    249       hold = true;
    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
    255       // rotation.
    256       event.stopImmediatePropagation();
    257     }
    258   }
    259 }
    260 
    261 function onMouseUp(event) {
    262   if (hold) {
    263     hold = false;
    264     SELECTED = undefined;
    265     NaClAMBulletDropObject();
    266     event.stopImmediatePropagation();
    267   }
    268 }
    269 
    270 function onMouseMove( event ) {
    271   event.preventDefault();
    272 
    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;
    278 
    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 );
    283   offset.x = vector.x;
    284   offset.y = vector.y;
    285   offset.z = vector.z;
    286 }
    287 
    288 //
    289 
    290 function animate() {
    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]});
    293   render();
    294 }
    295 
    296 function render() {
    297   controls.update();
    298   renderer.render( scene, camera );
    299 }
    300