1 /*{# Copyright (c) 2011-2012 Turbulenz Limited #}*/ 2 /* 3 * @title: 3D Physics collision meshes 4 * @description: 5 * This sample shows how to create rigid body physics nodes with each of the collision mesh types (boxes, spheres, 6 * cones, cylinders, capsules and convex hulls) and a static triangle mesh. 7 * 8 * Rigid body cubes with an initial velocity can be fired into the scene from first person perspective by pressing 9 * space. Click on the rendering window to move and rotate the camera around. 10 */ 11 /*{{ javascript("jslib/aabbtree.js") }}*/ 12 /*{{ javascript("jslib/camera.js") }}*/ 13 /*{{ javascript("jslib/floor.js") }}*/ 14 /*{{ javascript("jslib/geometry.js") }}*/ 15 /*{{ javascript("jslib/material.js") }}*/ 16 /*{{ javascript("jslib/light.js") }}*/ 17 /*{{ javascript("jslib/scenenode.js") }}*/ 18 /*{{ javascript("jslib/scene.js") }}*/ 19 /*{{ javascript("jslib/vmath.js") }}*/ 20 /*{{ javascript("jslib/effectmanager.js") }}*/ 21 /*{{ javascript("jslib/shadermanager.js") }}*/ 22 /*{{ javascript("jslib/texturemanager.js") }}*/ 23 /*{{ javascript("jslib/renderingcommon.js") }}*/ 24 /*{{ javascript("jslib/defaultrendering.js") }}*/ 25 /*{{ javascript("jslib/resourceloader.js") }}*/ 26 /*{{ javascript("jslib/scenedebugging.js") }}*/ 27 /*{{ javascript("jslib/observer.js") }}*/ 28 /*{{ javascript("jslib/physicsmanager.js") }}*/ 29 /*{{ javascript("jslib/utilities.js") }}*/ 30 /*{{ javascript("jslib/vertexbuffermanager.js") }}*/ 31 /*{{ javascript("jslib/indexbuffermanager.js") }}*/ 32 /*{{ javascript("jslib/mouseforces.js") }}*/ 33 /*{{ javascript("jslib/utilities.js") }}*/ 34 /*{{ javascript("jslib/requesthandler.js") }}*/ 35 /*{{ javascript("jslib/services/turbulenzservices.js") }}*/ 36 /*{{ javascript("jslib/services/turbulenzbridge.js") }}*/ 37 /*{{ javascript("jslib/services/gamesession.js") }}*/ 38 /*{{ javascript("jslib/services/mappingtable.js") }}*/ 39 /*{{ javascript("scripts/htmlcontrols.js") }}*/ 40 /*{{ javascript("scripts/sceneloader.js") }}*/ 41 /*global TurbulenzEngine: true */ 42 /*global DefaultRendering: false */ 43 /*global RequestHandler: false */ 44 /*global SceneLoader: false */ 45 /*global SceneNode: false */ 46 /*global TurbulenzServices: false */ 47 /*global TextureManager: false */ 48 /*global ShaderManager: false */ 49 /*global EffectManager: false */ 50 /*global Scene: false */ 51 /*global Camera: false */ 52 /*global CameraController: false */ 53 /*global Floor: false */ 54 /*global MouseForces: false */ 55 /*global PhysicsManager: false */ 56 /*global HTMLControls: false */ 57 TurbulenzEngine.onload = function onloadFn() { 58 var errorCallback = function errorCallback(msg) { 59 window.alert(msg); 60 }; 61 TurbulenzEngine.onerror = errorCallback; 62 63 var warningCallback = function warningCallback(msg) { 64 window.alert(msg); 65 }; 66 TurbulenzEngine.onwarning = warningCallback; 67 68 var mathDeviceParameters = {}; 69 var mathDevice = TurbulenzEngine.createMathDevice(mathDeviceParameters); 70 71 var graphicsDeviceParameters = {}; 72 var graphicsDevice = TurbulenzEngine.createGraphicsDevice(graphicsDeviceParameters); 73 74 var physicsDeviceParameters = {}; 75 var physicsDevice = TurbulenzEngine.createPhysicsDevice(physicsDeviceParameters); 76 77 var dynamicsWorldParameters = {}; 78 var dynamicsWorld = physicsDevice.createDynamicsWorld(dynamicsWorldParameters); 79 80 var inputDeviceParameters = {}; 81 var inputDevice = TurbulenzEngine.createInputDevice(inputDeviceParameters); 82 83 var requestHandlerParameters = {}; 84 var requestHandler = RequestHandler.create(requestHandlerParameters); 85 86 var textureManager = TextureManager.create(graphicsDevice, requestHandler, null, errorCallback); 87 var shaderManager = ShaderManager.create(graphicsDevice, requestHandler, null, errorCallback); 88 var effectManager = EffectManager.create(); 89 var physicsManager = PhysicsManager.create(mathDevice, physicsDevice, dynamicsWorld); 90 91 var mappingTable; 92 var debugMode = true; 93 94 // Renderer and assets for the scene. 95 var renderer; 96 var scene = Scene.create(mathDevice); 97 var sceneLoader = SceneLoader.create(); 98 var duckMesh; 99 100 // Setup world space 101 var clearColor = mathDevice.v4Build(0.95, 0.95, 1.0, 1.0); 102 var loadingClearColor = mathDevice.v4Build(0.8, 0.8, 0.8, 1.0); 103 var worldUp = mathDevice.v3BuildYAxis(); 104 105 // Setup a camera to view a close-up object 106 var camera = Camera.create(mathDevice); 107 camera.nearPlane = 0.05; 108 var cameraDefaultPos = mathDevice.v3Build(14.5, 8.0, 18.1); 109 var cameraDefaultLook = mathDevice.v3Build(14.5, -(camera.farPlane / 2), -camera.farPlane); 110 111 // The objects needed to draw the crosshair 112 var technique2d; 113 var shader2d; 114 var techniqueParameters2d; 115 var chSemantics = graphicsDevice.createSemantics(['POSITION']); 116 var chFormats = [graphicsDevice.VERTEXFORMAT_FLOAT3]; 117 118 // The objects needed to draw the contact callbacks 119 var contactsTechnique; 120 var contactsShader; 121 var contactsTechniqueParameters; 122 var contactsSemantics = graphicsDevice.createSemantics(['POSITION']); 123 var contactsFormats = [graphicsDevice.VERTEXFORMAT_FLOAT3]; 124 var contactWorldTransform = mathDevice.m43BuildIdentity(); 125 var contactWorldPoint = mathDevice.v3BuildZero(); 126 var contacts = []; 127 var numContacts = 0; 128 129 // Setup world floor 130 var floor = Floor.create(graphicsDevice, mathDevice); 131 var cameraController = CameraController.create(graphicsDevice, inputDevice, camera); 132 133 // Mouse forces 134 var dragMin = mathDevice.v3Build(-50, -50, -50); 135 var dragMax = mathDevice.v3Build(50, 50, 50); 136 var mouseForces = MouseForces.create(graphicsDevice, inputDevice, mathDevice, physicsDevice, dragMin, dragMax); 137 mouseForces.clamp = 400; 138 139 // Control codes 140 var keyCodes = inputDevice.keyCodes; 141 var mouseCodes = inputDevice.mouseCodes; 142 143 // Setup the box firing objects, including the inertia 144 var boxes = []; 145 var numBoxes = 12; 146 var fireCount = 0; 147 var cubeExtents = mathDevice.v3Build(0.5, 0.5, 0.5); 148 var boxShape = physicsDevice.createBoxShape({ 149 halfExtents: cubeExtents, 150 margin: 0.001 151 }); 152 153 var inertia = mathDevice.v3Copy(boxShape.inertia); 154 inertia = mathDevice.v3ScalarMul(inertia, 1.0); 155 156 function reset() { 157 var halfPI = Math.PI / 2; 158 var halfExtents = duckMesh.localHalfExtents; 159 var yhalfExtent = halfExtents[1]; 160 var j = 1; 161 162 function resetTransform(node, rotationMatrix) { 163 var body = node.physicsNodes[0].body; 164 dynamicsWorld.removeRigidBody(body); 165 body.transform = mathDevice.m43BuildTranslation(j * 5, yhalfExtent, 0, body.transform); 166 if (rotationMatrix) { 167 body.transform = mathDevice.m43Mul(rotationMatrix, body.transform, body.transform); 168 } 169 body.linearVelocity = mathDevice.v3BuildZero(); 170 body.angularVelocity = mathDevice.v3BuildZero(); 171 body.active = true; 172 dynamicsWorld.addRigidBody(body); 173 j += 1; 174 } 175 ; 176 177 // Reset ducks 178 var rootNode = scene.findNode("DuckBoxPhys"); 179 resetTransform(rootNode); 180 rootNode = scene.findNode("DuckConePhys"); 181 resetTransform(rootNode); 182 rootNode = scene.findNode("DuckCylinderPhys"); 183 resetTransform(rootNode); 184 rootNode = scene.findNode("DuckSpherePhys"); 185 resetTransform(rootNode); 186 rootNode = scene.findNode("DuckCapsulePhys"); 187 var rot = mathDevice.m43FromAxisRotation(mathDevice.v3BuildXAxis(), halfPI); 188 mathDevice.m43SetAxisRotation(rot, mathDevice.v3BuildZAxis(), halfPI); 189 resetTransform(rootNode, rot); 190 rootNode = scene.findNode("DuckConvexHullPhys"); 191 resetTransform(rootNode); 192 193 // Reset boxes 194 var count = 0; 195 if (fireCount > 0 && fireCount < numBoxes) { 196 count = fireCount; 197 } else if (fireCount >= numBoxes) { 198 count = numBoxes; 199 } 200 201 for (var i = 0; i < count; i += 1) { 202 var box = boxes[i]; 203 var node = box.target; 204 physicsManager.deletePhysicsNode(box); 205 physicsManager.enableNode(node, false); 206 } 207 fireCount = 0; 208 209 // Reset camera 210 camera.lookAt(cameraDefaultLook, worldUp, cameraDefaultPos); 211 camera.updateViewMatrix(); 212 } 213 214 function fireBox() { 215 mouseForces.mouseX = 0.5; 216 mouseForces.mouseY = 0.5; 217 mouseForces.mouseZ = 0.0; 218 mouseForces.generatePickRay(camera.matrix, 1.0 / camera.recipViewWindowX, 1.0 / camera.recipViewWindowY, camera.aspectRatio, camera.farPlane); 219 220 var tr = mathDevice.m43BuildTranslation(mouseForces.pickRayFrom[0], mouseForces.pickRayFrom[1], mouseForces.pickRayFrom[2]); 221 222 var linVel = mathDevice.v3Build(mouseForces.pickRayTo[0] - mouseForces.pickRayFrom[0], mouseForces.pickRayTo[1] - mouseForces.pickRayFrom[1], mouseForces.pickRayTo[2] - mouseForces.pickRayFrom[2]); 223 mathDevice.v3Normalize(linVel, linVel); 224 mathDevice.v3ScalarMul(linVel, 50.0, linVel); 225 226 var box = boxes[fireCount % numBoxes]; 227 physicsManager.deletePhysicsNode(box); 228 var node = box.target; 229 var body = box.body; 230 if (fireCount > numBoxes - 1) { 231 physicsManager.enableNode(node, false); 232 } 233 body.transform = tr; 234 body.angularVelocity = mathDevice.v3BuildZero(); 235 body.linearVelocity = linVel; 236 body.active = true; 237 238 physicsManager.physicsNodes.push(box); 239 physicsManager.dynamicPhysicsNodes.push(box); 240 physicsManager.enableNode(node, true); 241 242 fireCount += 1; 243 } 244 245 var onMouseDown = function (button) { 246 if (mouseCodes.BUTTON_0 === button || mouseCodes.BUTTON_1 === button) { 247 mouseForces.onmousedown(); 248 } 249 }; 250 251 var onMouseUp = function (button) { 252 if (mouseCodes.BUTTON_0 === button || mouseCodes.BUTTON_1 === button) { 253 mouseForces.onmouseup(); 254 } 255 if (mouseCodes.BUTTON_2 === button) { 256 mouseForces.onmouseup(); 257 fireBox(); 258 } 259 }; 260 261 var onKeyUp = function physicsOnkeyupFn(keynum) { 262 if (keynum === keyCodes.R) { 263 reset(); 264 } 265 if (keynum === keyCodes.SPACE) { 266 fireBox(); 267 } else { 268 cameraController.onkeyup(keynum); 269 } 270 }; 271 272 // Add event listeners 273 inputDevice.addEventListener("keyup", onKeyUp); 274 inputDevice.addEventListener("mousedown", onMouseDown); 275 inputDevice.addEventListener("mouseup", onMouseUp); 276 277 // Controls 278 var htmlControls = HTMLControls.create(); 279 htmlControls.addCheckboxControl({ 280 id: "checkbox01", 281 value: "debugMode", 282 isSelected: debugMode, 283 fn: function () { 284 debugMode = !debugMode; 285 duckMesh.setDisabled(debugMode); 286 return debugMode; 287 } 288 }); 289 htmlControls.register(); 290 291 function drawCrosshair() { 292 if (!mouseForces.pickedBody) { 293 graphicsDevice.setTechnique(technique2d); 294 295 var screenWidth = graphicsDevice.width; 296 var screenHeight = graphicsDevice.height; 297 techniqueParameters2d.clipSpace = mathDevice.v4Build(2.0 / screenWidth, -2.0 / screenHeight, -1.0, 1.0); 298 graphicsDevice.setTechniqueParameters(techniqueParameters2d); 299 300 var writer = graphicsDevice.beginDraw(graphicsDevice.PRIMITIVE_LINES, 4, chFormats, chSemantics); 301 302 if (writer) { 303 var halfWidth = screenWidth * 0.5; 304 var halfHeight = screenHeight * 0.5; 305 writer([halfWidth - 10, halfHeight]); 306 writer([halfWidth + 10, halfHeight]); 307 writer([halfWidth, halfHeight - 10]); 308 writer([halfWidth, halfHeight + 10]); 309 310 graphicsDevice.endDraw(writer); 311 } 312 } 313 } 314 315 //function addContact(objectA, objectB, pairContact) 316 //{ 317 // if (debugMode) 318 // { 319 // objectB.calculateTransform(contactWorldTransform); 320 // mathDevice.m43TransformPoint(contactWorldTransform, pairContact.localPointOnB, contactWorldPoint); 321 // var contactNormal = pairContact.worldNormalOnB; 322 // if (numContacts >= contacts.length) 323 // { 324 // contacts[contacts.length] = new Float32Array(6); 325 // } 326 // var contact = contacts[numContacts]; 327 // contact[0] = contactWorldPoint[0]; 328 // contact[1] = contactWorldPoint[1]; 329 // contact[2] = contactWorldPoint[2]; 330 // contact[3] = contactWorldPoint[0] - contactNormal[0]; 331 // contact[4] = contactWorldPoint[1] - contactNormal[1]; 332 // contact[5] = contactWorldPoint[2] - contactNormal[2]; 333 // numContacts += 1; 334 // } 335 //} 336 function addContacts(objectA, objectB, pairContacts) { 337 if (debugMode) { 338 var numPairContacts = pairContacts.length; 339 var n; 340 objectB.calculateTransform(contactWorldTransform); 341 for (n = 0; n < numPairContacts; n += 1) { 342 var pairContact = pairContacts[n]; 343 mathDevice.m43TransformPoint(contactWorldTransform, pairContact.localPointOnB, contactWorldPoint); 344 var contactNormal = pairContact.worldNormalOnB; 345 if (numContacts >= contacts.length) { 346 contacts[contacts.length] = new Float32Array(6); 347 } 348 var contact = contacts[numContacts]; 349 contact[0] = contactWorldPoint[0]; 350 contact[1] = contactWorldPoint[1]; 351 contact[2] = contactWorldPoint[2]; 352 contact[3] = contactWorldPoint[0] - contactNormal[0]; 353 contact[4] = contactWorldPoint[1] - contactNormal[1]; 354 contact[5] = contactWorldPoint[2] - contactNormal[2]; 355 numContacts += 1; 356 } 357 } 358 } 359 360 function drawContacts() { 361 if (numContacts) { 362 graphicsDevice.setTechnique(contactsTechnique); 363 364 contactsTechniqueParameters.worldViewProjection = camera.viewProjectionMatrix; 365 graphicsDevice.setTechniqueParameters(contactsTechniqueParameters); 366 367 var writer = graphicsDevice.beginDraw(graphicsDevice.PRIMITIVE_LINES, numContacts * 2, contactsFormats, contactsSemantics); 368 369 if (writer) { 370 var n; 371 for (n = 0; n < numContacts; n += 1) { 372 var contact = contacts[n]; 373 writer(contact[0], contact[1], contact[2]); 374 writer(contact[3], contact[4], contact[5]); 375 } 376 377 graphicsDevice.endDraw(writer); 378 } 379 } 380 } 381 382 var renderFrame = function renderFrameFn() { 383 var currentTime = TurbulenzEngine.time; 384 385 // Update input and camera 386 inputDevice.update(); 387 388 if (mouseForces.pickedBody) { 389 // If we're dragging a body don't apply the movement to the camera 390 cameraController.pitch = 0; 391 cameraController.turn = 0; 392 cameraController.step = 0; 393 } 394 395 cameraController.update(); 396 397 var deviceWidth = graphicsDevice.width; 398 var deviceHeight = graphicsDevice.height; 399 var aspectRatio = (deviceWidth / deviceHeight); 400 if (aspectRatio !== camera.aspectRatio) { 401 camera.aspectRatio = aspectRatio; 402 camera.updateProjectionMatrix(); 403 } 404 camera.updateViewProjectionMatrix(); 405 406 numContacts = 0; 407 408 // Update the physics 409 mouseForces.update(dynamicsWorld, camera, 0.1); 410 dynamicsWorld.update(); 411 412 physicsManager.update(); 413 scene.update(); 414 415 renderer.update(graphicsDevice, camera, scene, currentTime); 416 417 if (graphicsDevice.beginFrame()) { 418 if (renderer.updateBuffers(graphicsDevice, deviceWidth, deviceHeight)) { 419 renderer.draw(graphicsDevice, clearColor); 420 floor.render(graphicsDevice, camera); 421 if (debugMode) { 422 scene.drawPhysicsNodes(graphicsDevice, shaderManager, camera, physicsManager); 423 scene.drawPhysicsGeometry(graphicsDevice, shaderManager, camera, physicsManager); 424 drawContacts(); 425 } 426 } 427 428 drawCrosshair(); 429 430 graphicsDevice.endFrame(); 431 } 432 }; 433 434 var intervalID; 435 var loadingLoop = function loadingLoopFn() { 436 if (graphicsDevice.beginFrame()) { 437 graphicsDevice.clear(loadingClearColor); 438 graphicsDevice.endFrame(); 439 } 440 441 if (sceneLoader.complete()) { 442 TurbulenzEngine.clearInterval(intervalID); 443 444 camera.lookAt(cameraDefaultLook, worldUp, cameraDefaultPos); 445 camera.updateViewMatrix(); 446 447 renderer.updateShader(shaderManager); 448 449 shader2d = shaderManager.get("shaders/generic2D.cgfx"); 450 technique2d = shader2d.getTechnique("constantColor2D"); 451 techniqueParameters2d = graphicsDevice.createTechniqueParameters({ 452 clipSpace: null, 453 constantColor: mathDevice.v4Build(0, 0, 0, 1) 454 }); 455 456 contactsShader = shaderManager.get("shaders/debug.cgfx"); 457 contactsTechnique = contactsShader.getTechnique("debug_lines_constant"); 458 contactsTechniqueParameters = graphicsDevice.createTechniqueParameters({ 459 worldViewProjection: null, 460 constantColor: mathDevice.v4Build(1, 0, 0, 1) 461 }); 462 463 if (physicsManager.physicsNodes.length >= 0) { 464 // Floor is represented by a plane shape 465 var floorShape = physicsDevice.createPlaneShape({ 466 normal: mathDevice.v3Build(0, 1, 0), 467 distance: 0, 468 margin: 0.001 469 }); 470 471 var floorObject = physicsDevice.createCollisionObject({ 472 shape: floorShape, 473 transform: mathDevice.m43BuildIdentity(), 474 friction: 0.8, 475 restitution: 0.1, 476 group: physicsDevice.FILTER_STATIC, 477 mask: physicsDevice.FILTER_ALL, 478 //onPreSolveContact : addContact, 479 //onAddedContacts : addContacts 480 onProcessedContacts: addContacts 481 }); 482 483 // Adds the floor collision object to the world 484 dynamicsWorld.addCollisionObject(floorObject); 485 } 486 intervalID = TurbulenzEngine.setInterval(renderFrame, 1000 / 60); 487 } 488 }; 489 intervalID = TurbulenzEngine.setInterval(loadingLoop, 1000 / 10); 490 491 // Change the clear color before we start loading assets 492 loadingLoop(); 493 494 var postLoad = function postLoadFn() { 495 var mass = 10.0; 496 var margin = 0.001; 497 duckMesh = scene.findNode("DuckMesh"); 498 var halfExtents = duckMesh.localHalfExtents; 499 var xhalfExtent = halfExtents[0]; 500 var yhalfExtent = halfExtents[1]; 501 var halfPI = Math.PI / 2; 502 var xAxis = mathDevice.v3BuildXAxis(); 503 var zAxis = mathDevice.v3BuildZAxis(); 504 505 function newPhysicsNode(name, shape, offsetTransform, pos) { 506 var duckGeom = duckMesh.clone(name + "Geom"); 507 physicsManager.deletePhysicsNode(duckGeom.physicsNodes[0]); 508 duckGeom.physicsNodes = []; 509 duckGeom.setLocalTransform(offsetTransform); 510 511 var duckPhys = SceneNode.create({ 512 name: name + "Phys", 513 local: pos, 514 dynamic: true, 515 disabled: false 516 }); 517 518 var rigidBody = physicsDevice.createRigidBody({ 519 shape: shape, 520 mass: mass, 521 inertia: mathDevice.v3ScalarMul(shape.inertia, mass), 522 transform: pos, 523 friction: 0.7, 524 restitution: 0.2, 525 angularDamping: 0.4 526 }); 527 528 var physicsNode = { 529 body: rigidBody, 530 target: duckPhys, 531 dynamic: true 532 }; 533 534 scene.addRootNode(duckPhys); 535 duckPhys.addChild(duckGeom); 536 duckPhys.physicsNodes = [physicsNode]; 537 duckPhys.setDynamic(); 538 539 physicsManager.physicsNodes.push(physicsNode); 540 physicsManager.dynamicPhysicsNodes.push(physicsNode); 541 physicsManager.enableHierarchy(duckPhys, true); 542 } 543 544 // Build a box duck 545 var shape = physicsDevice.createBoxShape({ 546 halfExtents: halfExtents, 547 margin: margin 548 }); 549 550 var position = mathDevice.m43BuildTranslation(5, yhalfExtent, 0); 551 newPhysicsNode("DuckBox", shape, mathDevice.m43BuildIdentity(), position); 552 553 // Build a cone duck 554 shape = physicsDevice.createConeShape({ 555 height: yhalfExtent * 2, 556 radius: xhalfExtent, 557 margin: margin 558 }); 559 560 mathDevice.m43BuildTranslation(10, yhalfExtent, 0, position); 561 newPhysicsNode("DuckCone", shape, mathDevice.m43BuildIdentity(), position); 562 563 // Build a cylinder duck 564 shape = physicsDevice.createCylinderShape({ 565 halfExtents: [xhalfExtent, yhalfExtent, xhalfExtent], 566 margin: margin 567 }); 568 569 mathDevice.m43BuildTranslation(15, yhalfExtent, 0, position); 570 newPhysicsNode("DuckCylinder", shape, mathDevice.m43BuildIdentity(), position); 571 572 // Build a sphere duck 573 shape = physicsDevice.createSphereShape({ 574 radius: xhalfExtent, 575 margin: margin 576 }); 577 578 mathDevice.m43BuildTranslation(20, yhalfExtent, 0, position); 579 newPhysicsNode("DuckSphere", shape, mathDevice.m43BuildIdentity(), position); 580 581 // Build a capsule duck 582 shape = physicsDevice.createCapsuleShape({ 583 radius: xhalfExtent, 584 height: yhalfExtent * 2, 585 margin: margin 586 }); 587 588 // Capsules always take their height in the Y-axis 589 // Rotate the capsule so it is flat against the floor 590 // Rotate the duck so it is facing the correct direction 591 mathDevice.m43BuildTranslation(25, yhalfExtent, 0, position); 592 mathDevice.m43SetAxisRotation(position, xAxis, halfPI); 593 mathDevice.m43SetAxisRotation(position, zAxis, halfPI); 594 newPhysicsNode("DuckCapsule", shape, mathDevice.m43FromAxisRotation(zAxis, -halfPI), position); 595 596 // Build a convex hull duck 597 shape = physicsDevice.createConvexHullShape({ 598 points: duckMesh.physicsNodes[0].triangleArray.vertices, 599 margin: margin, 600 minExtent: mathDevice.v3Neg(halfExtents), 601 maxExtent: halfExtents 602 }); 603 604 mathDevice.m43BuildTranslation(30, yhalfExtent, 0, position); 605 newPhysicsNode("DuckConvexHull", shape, mathDevice.m43BuildIdentity(), position); 606 607 // Set DuckMesh to disabled when debug rendering is enabled 608 // This is to prevent Z-fighting between the geometry of the triangle mesh and asset 609 duckMesh.setDisabled(true); 610 611 // Create a pool of boxes 612 var identity = mathDevice.m43BuildIdentity(); 613 for (var i = 0; i < numBoxes; i += 1) { 614 var box = physicsDevice.createRigidBody({ 615 shape: boxShape, 616 mass: 1.0, 617 inertia: boxShape.inertia, 618 transform: identity, 619 friction: 0.9, 620 restitution: 0.1 621 }); 622 623 var newBox = SceneNode.create({ 624 name: "box" + i, 625 local: identity, 626 dynamic: true, 627 disabled: false 628 }); 629 var physicsNode = { 630 body: box, 631 target: newBox, 632 dynamic: true 633 }; 634 newBox.physicsNodes = [physicsNode]; 635 scene.addRootNode(newBox); 636 boxes[i] = physicsNode; 637 } 638 }; 639 640 var loadAssets = function loadAssetsFn() { 641 // Renderer for the scene. 642 renderer = DefaultRendering.create(graphicsDevice, mathDevice, shaderManager, effectManager); 643 644 renderer.setGlobalLightPosition(mathDevice.v3Build(0.5, 100.0, 0.5)); 645 renderer.setAmbientColor(mathDevice.v3Build(0.3, 0.3, 0.4)); 646 647 shaderManager.load("shaders/generic2D.cgfx"); 648 649 // Load mesh duck 650 sceneLoader.load({ 651 scene: scene, 652 assetPath: "models/duck_trianglemesh.dae", 653 graphicsDevice: graphicsDevice, 654 textureManager: textureManager, 655 effectManager: effectManager, 656 shaderManager: shaderManager, 657 physicsManager: physicsManager, 658 requestHandler: requestHandler, 659 baseMatrix: mathDevice.m43BuildTranslation(0, 0.77, 0), 660 append: true, 661 postSceneLoadFn: postLoad, 662 dynamic: false 663 }); 664 }; 665 666 var mappingTableReceived = function mappingTableReceivedFn(mappingTable) { 667 textureManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 668 shaderManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 669 sceneLoader.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 670 671 loadAssets(); 672 }; 673 674 var gameSessionCreated = function gameSessionCreatedFn(gameSession) { 675 mappingTable = TurbulenzServices.createMappingTable(requestHandler, gameSession, mappingTableReceived); 676 }; 677 678 var gameSession = TurbulenzServices.createGameSession(requestHandler, gameSessionCreated); 679 680 // Create a scene destroy callback to run when the window is closed 681 function destroyScene() { 682 gameSession.destroy(); 683 684 TurbulenzEngine.clearInterval(intervalID); 685 clearColor = null; 686 687 if (scene) { 688 scene.destroy(); 689 scene = null; 690 } 691 requestHandler = null; 692 693 if (renderer) { 694 renderer.destroy(); 695 renderer = null; 696 } 697 698 camera = null; 699 700 if (textureManager) { 701 textureManager.destroy(); 702 textureManager = null; 703 } 704 705 if (shaderManager) { 706 shaderManager.destroy(); 707 shaderManager = null; 708 } 709 710 effectManager = null; 711 712 TurbulenzEngine.flush(); 713 graphicsDevice = null; 714 mathDevice = null; 715 physicsDevice = null; 716 physicsManager = null; 717 dynamicsWorld = null; 718 mouseCodes = null; 719 keyCodes = null; 720 inputDevice = null; 721 cameraController = null; 722 floor = null; 723 } 724 725 TurbulenzEngine.onunload = destroyScene; 726 };