1 /*{# Copyright (c) 2010-2012 Turbulenz Limited #}*/ 2 /* 3 * @title: Camera 4 * @description: 5 * This sample shows how to set up and then animate a Turbulenz Camera object. 6 * You can switch between tracking, orbiting and chasing motions. 7 */ 8 /*{{ javascript("jslib/aabbtree.js") }}*/ 9 /*{{ javascript("jslib/camera.js") }}*/ 10 /*{{ javascript("jslib/floor.js") }}*/ 11 /*{{ javascript("jslib/geometry.js") }}*/ 12 /*{{ javascript("jslib/material.js") }}*/ 13 /*{{ javascript("jslib/light.js") }}*/ 14 /*{{ javascript("jslib/scenenode.js") }}*/ 15 /*{{ javascript("jslib/scene.js") }}*/ 16 /*{{ javascript("jslib/vmath.js") }}*/ 17 /*{{ javascript("jslib/effectmanager.js") }}*/ 18 /*{{ javascript("jslib/shadermanager.js") }}*/ 19 /*{{ javascript("jslib/texturemanager.js") }}*/ 20 /*{{ javascript("jslib/renderingcommon.js") }}*/ 21 /*{{ javascript("jslib/defaultrendering.js") }}*/ 22 /*{{ javascript("jslib/observer.js") }}*/ 23 /*{{ javascript("jslib/resourceloader.js") }}*/ 24 /*{{ javascript("jslib/utilities.js") }}*/ 25 /*{{ javascript("jslib/vertexbuffermanager.js") }}*/ 26 /*{{ javascript("jslib/indexbuffermanager.js") }}*/ 27 /*{{ javascript("jslib/requesthandler.js") }}*/ 28 /*{{ javascript("jslib/services/turbulenzservices.js") }}*/ 29 /*{{ javascript("jslib/services/turbulenzbridge.js") }}*/ 30 /*{{ javascript("jslib/services/gamesession.js") }}*/ 31 /*{{ javascript("jslib/services/mappingtable.js") }}*/ 32 /*{{ javascript("scripts/dynamiccameracontroller.js") }}*/ 33 /*{{ javascript("scripts/htmlcontrols.js") }}*/ 34 /*{{ javascript("scripts/motion.js") }}*/ 35 /*{{ javascript("scripts/sceneloader.js") }}*/ 36 /*global TurbulenzEngine: true */ 37 /*global DefaultRendering: false */ 38 /*global DynamicCameraController: false */ 39 /*global Motion: false */ 40 /*global RequestHandler: false */ 41 /*global SceneLoader: false */ 42 /*global TurbulenzServices: false */ 43 /*global TextureManager: false */ 44 /*global ShaderManager: false */ 45 /*global EffectManager: false */ 46 /*global Camera: false */ 47 /*global Scene: false */ 48 /*global Floor: false */ 49 /*global HTMLControls: false */ 50 TurbulenzEngine.onload = function onloadFn() { 51 var errorCallback = function errorCallback(msg) { 52 window.alert(msg); 53 }; 54 55 // Create the engine devices objects 56 var graphicsDeviceParameters = {}; 57 var graphicsDevice = TurbulenzEngine.createGraphicsDevice(graphicsDeviceParameters); 58 59 if (!graphicsDevice.shadingLanguageVersion) { 60 errorCallback("No shading language support detected.\nPlease check your graphics drivers are up to date."); 61 graphicsDevice = null; 62 return; 63 } 64 65 // Clear the background color of the engine window 66 var clearColor = [0.95, 0.95, 1.0, 1.0]; 67 if (graphicsDevice.beginFrame()) { 68 graphicsDevice.clear(clearColor); 69 graphicsDevice.endFrame(); 70 } 71 72 var mathDeviceParameters = {}; 73 var mathDevice = TurbulenzEngine.createMathDevice(mathDeviceParameters); 74 75 var inputDeviceParameters = {}; 76 var inputDevice = TurbulenzEngine.createInputDevice(inputDeviceParameters); 77 78 var requestHandlerParameters = {}; 79 var requestHandler = RequestHandler.create(requestHandlerParameters); 80 81 var textureManager = TextureManager.create(graphicsDevice, requestHandler, null, errorCallback); 82 var shaderManager = ShaderManager.create(graphicsDevice, requestHandler, null, errorCallback); 83 var effectManager = EffectManager.create(); 84 85 var renderer; 86 87 var scene = Scene.create(mathDevice); 88 var sceneLoader = SceneLoader.create(); 89 90 var loadAssets = function loadAssetsFn() { 91 // Renderer for the scene (requires shader assets). 92 renderer = DefaultRendering.create(graphicsDevice, mathDevice, shaderManager, effectManager); 93 94 renderer.setGlobalLightPosition(mathDevice.v3Build(0.5, 100.0, 0.5)); 95 renderer.setAmbientColor(mathDevice.v3Build(0.3, 0.3, 0.4)); 96 renderer.setDefaultTexture(textureManager.get("default")); 97 98 sceneLoader.load({ 99 scene: scene, 100 append: false, 101 assetPath: "models/duck.dae", 102 keepCameras: true, 103 graphicsDevice: graphicsDevice, 104 mathDevice: mathDevice, 105 textureManager: textureManager, 106 effectManager: effectManager, 107 shaderManager: shaderManager, 108 requestHandler: requestHandler, 109 dynamic: true 110 }); 111 }; 112 113 // Read mapping table 114 var mappingTableReceived = function mappingTableReceivedFn(mappingTable) { 115 textureManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 116 shaderManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 117 sceneLoader.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 118 119 loadAssets(); 120 }; 121 122 var gameSessionCreated = function gameSessionCreatedFn(gameSession) { 123 TurbulenzServices.createMappingTable(requestHandler, gameSession, mappingTableReceived); 124 }; 125 126 var gameSession = TurbulenzServices.createGameSession(requestHandler, gameSessionCreated); 127 128 // Create world 129 var worldUp = mathDevice.v3Build(0.0, 1.0, 0.0); 130 var floor = Floor.create(graphicsDevice, mathDevice); 131 132 // Create duck animation 133 var duck = Motion.create(mathDevice, "duck"); 134 duck.setCircularMovement(5.0, [0, 0, 0]); 135 duck.setDuckMotion(0.1, 0.5, 0.3); 136 duck.baseRotation = mathDevice.m43FromAxisRotation(duck.up, -90, duck.baseRotation); 137 138 // Create fixed positions for tracking camera 139 var cameraFixedPositions = [ 140 mathDevice.v3Build(0.0, 4.0, -10.0), 141 mathDevice.v3Build(9.0, 1.5, 9.0), 142 mathDevice.v3Build(-9.0, 8.0, 9.0) 143 ]; 144 var cameraIndex = 1; 145 146 // Create the orbit motion for the orbit camera position 147 var orbit = Motion.create(mathDevice, "orbitCam"); 148 orbit.setCircularMovement(7.0, [0, 0, 0]); 149 orbit.setConstantMotion(0.3); 150 var updateOrbit = false; 151 152 // Create a basic camera with initial target of the duck position 153 var camera = Camera.create(mathDevice); 154 camera.lookAt(duck.position, worldUp, cameraFixedPositions[cameraIndex]); 155 camera.updateViewMatrix(); 156 157 // Generate the initial matrix of the chase camera 158 var updateChase = false; 159 var chaseCamOffset = mathDevice.v3Build(-8.0, 4.5, 0.0); 160 var chaseCamPosition = chaseCamOffset.slice(); 161 var chaseCamRate = 5.0; 162 163 // Create the dynamic camera used for tracking, orbiting and chasing 164 var dynamicCameraController = DynamicCameraController.create(camera, graphicsDevice); 165 dynamicCameraController.setChaseRate(0.3); 166 dynamicCameraController.setTracking(true); 167 dynamicCameraController.setRate(1.4); 168 169 var htmlControls = HTMLControls.create(); 170 171 // Switch camera 172 var switchToTargetCam = function switchToTargetCamFn(index) { 173 cameraIndex = index; 174 updateOrbit = false; 175 updateChase = false; 176 177 // Rail camera mode is used to move to the target position over time 178 dynamicCameraController.setCameraMode(dynamicCameraController.cameraType.rail); 179 dynamicCameraController.setCameraTargetPos(cameraFixedPositions[index], TurbulenzEngine.time, 100); 180 htmlControls.setSelectedRadio("camPos", cameraIndex); 181 }; 182 183 var switchToOrbitCam = function switchToOrbitCamFn() { 184 cameraIndex = 3; 185 updateChase = false; 186 187 // Fixed camera mode is used for orbit to ensure the orbit movement is constant 188 dynamicCameraController.setCameraMode(dynamicCameraController.cameraType.fixed); 189 updateOrbit = true; 190 htmlControls.setSelectedRadio("camPos", cameraIndex); 191 }; 192 193 var switchToChaseCam = function switchToChaseCamFn() { 194 cameraIndex = 4; 195 updateOrbit = false; 196 197 // Chase camera mode is used, to smooth the varying motion of the 198 // target position 199 dynamicCameraController.setCameraMode(dynamicCameraController.cameraType.chase); 200 updateChase = true; 201 htmlControls.setSelectedRadio("camPos", cameraIndex); 202 }; 203 204 // Controls 205 htmlControls.addRadioControl({ 206 id: "radio01", 207 groupName: "camPos", 208 radioIndex: 0, 209 value: "pos01", 210 fn: function () { 211 switchToTargetCam(0); 212 }, 213 isDefault: true 214 }); 215 htmlControls.addRadioControl({ 216 id: "radio02", 217 groupName: "camPos", 218 radioIndex: 1, 219 value: "pos02", 220 fn: function () { 221 switchToTargetCam(1); 222 }, 223 isDefault: false 224 }); 225 htmlControls.addRadioControl({ 226 id: "radio03", 227 groupName: "camPos", 228 radioIndex: 2, 229 value: "pos03", 230 fn: function () { 231 switchToTargetCam(2); 232 }, 233 isDefault: false 234 }); 235 htmlControls.addRadioControl({ 236 id: "radio04", 237 groupName: "camPos", 238 radioIndex: 3, 239 value: "pos04", 240 fn: switchToOrbitCam, 241 isDefault: false 242 }); 243 htmlControls.addRadioControl({ 244 id: "radio05", 245 groupName: "camPos", 246 radioIndex: 4, 247 value: "pos05", 248 fn: switchToChaseCam, 249 isDefault: false 250 }); 251 htmlControls.register(); 252 253 // Input functions 254 var keyCodes = inputDevice.keyCodes; 255 256 var keyUp = function keyUpFn(key) { 257 if (key === keyCodes.T) { 258 cameraIndex = (cameraIndex + 1) % cameraFixedPositions.length; 259 switchToTargetCam(cameraIndex); 260 } 261 262 if (key === keyCodes.O) { 263 switchToOrbitCam(); 264 } 265 266 if (key === keyCodes.C) { 267 switchToChaseCam(); 268 } 269 270 if (key === keyCodes.RETURN) { 271 graphicsDevice.fullscreen = !graphicsDevice.fullscreen; 272 } 273 }; 274 inputDevice.addEventListener("keyup", keyUp); 275 276 // Initialize the previous frame time 277 var previousFrameTime = TurbulenzEngine.time; 278 var intervalID; 279 280 // Callback to draw extra debug information 281 function drawDebugCB() { 282 floor.render(graphicsDevice, camera); 283 } 284 285 // 286 // Update 287 // 288 var update = function updateFn() { 289 var currentTime = TurbulenzEngine.time; 290 var deltaTime = (currentTime - previousFrameTime); 291 if (deltaTime > 0.1) { 292 deltaTime = 0.1; 293 } 294 295 // Update input 296 inputDevice.update(); 297 298 // Update duck position and rotation 299 duck.update(deltaTime); 300 301 if (updateOrbit) { 302 orbit.circularCenter[0] = duck.position[0]; 303 orbit.circularCenter[2] = duck.position[2]; 304 orbit.position[1] = 4.0; 305 orbit.update(deltaTime); 306 dynamicCameraController.setCameraTargetPos(orbit.position, currentTime, 0); 307 } else if (updateChase) { 308 dynamicCameraController.setCameraTargetPos(chaseCamPosition, currentTime, deltaTime * chaseCamRate); 309 } 310 311 // Update dynamic camera controller 312 dynamicCameraController.setTrackTarget(duck.position); 313 dynamicCameraController.update(deltaTime); 314 315 // Update the aspect ratio of the camera in case of window resizes 316 var deviceWidth = graphicsDevice.width; 317 var deviceHeight = graphicsDevice.height; 318 var aspectRatio = (deviceWidth / deviceHeight); 319 if (aspectRatio !== camera.aspectRatio) { 320 camera.aspectRatio = aspectRatio; 321 camera.updateProjectionMatrix(); 322 } 323 camera.updateViewProjectionMatrix(); 324 325 //Move the duck model. 326 var duckNode = scene.findNode("LOD3sp"); 327 duckNode.setLocalTransform(duck.matrix); 328 329 if (updateChase) { 330 // Only update the chase camera position when we are using it 331 chaseCamPosition = mathDevice.m43TransformPoint(duckNode.getWorldTransform(), chaseCamOffset); 332 } 333 334 // Update scene 335 scene.update(); 336 337 // Update renderer with new camera and updated scene 338 renderer.update(graphicsDevice, camera, scene, currentTime); 339 340 if (graphicsDevice.beginFrame()) { 341 if (renderer.updateBuffers(graphicsDevice, deviceWidth, deviceHeight)) { 342 renderer.draw(graphicsDevice, clearColor, null, null, drawDebugCB); 343 } 344 345 graphicsDevice.endFrame(); 346 } 347 348 previousFrameTime = currentTime; 349 }; 350 351 var loadingLoop = function loadingLoopFn() { 352 if (sceneLoader.complete()) { 353 TurbulenzEngine.clearInterval(intervalID); 354 intervalID = TurbulenzEngine.setInterval(update, 1000 / 60); 355 356 renderer.updateShader(shaderManager); 357 358 switchToTargetCam(0); 359 } 360 }; 361 362 intervalID = TurbulenzEngine.setInterval(loadingLoop, 1000 / 10); 363 364 // Create a scene destroy callback to run when the window is closed 365 TurbulenzEngine.onunload = function destroyScene() { 366 TurbulenzEngine.clearInterval(intervalID); 367 368 if (gameSession) { 369 gameSession.destroy(); 370 gameSession = null; 371 } 372 373 clearColor = null; 374 worldUp = null; 375 floor = null; 376 377 duck = null; 378 cameraFixedPositions = null; 379 380 if (renderer) { 381 renderer.destroy(); 382 renderer = null; 383 } 384 385 orbit = null; 386 chaseCamPosition = null; 387 388 requestHandler = null; 389 sceneLoader = null; 390 391 if (scene) { 392 scene.destroy(); 393 scene = null; 394 } 395 396 camera = null; 397 dynamicCameraController = null; 398 effectManager = null; 399 400 if (textureManager) { 401 textureManager.destroy(); 402 textureManager = null; 403 } 404 405 if (shaderManager) { 406 shaderManager.destroy(); 407 shaderManager = null; 408 } 409 410 TurbulenzEngine.flush(); 411 412 keyCodes = null; 413 inputDevice = null; 414 graphicsDevice = null; 415 mathDevice = null; 416 }; 417 };