1 /*{# Copyright (c) 2010-2012 Turbulenz Limited #}*/ 2 /* 3 * @title: Material 4 * @description: 5 * This sample shows how to load materials, how to create them procedurally, and how to apply them to renderables in the scene. 6 * You can select and apply different materials using different rendering effects to the rotation model. 7 */ 8 /*{{ javascript("jslib/aabbtree.js") }}*/ 9 /*{{ javascript("jslib/camera.js") }}*/ 10 /*{{ javascript("jslib/geometry.js") }}*/ 11 /*{{ javascript("jslib/material.js") }}*/ 12 /*{{ javascript("jslib/light.js") }}*/ 13 /*{{ javascript("jslib/scenenode.js") }}*/ 14 /*{{ javascript("jslib/scene.js") }}*/ 15 /*{{ javascript("jslib/vmath.js") }}*/ 16 /*{{ javascript("jslib/effectmanager.js") }}*/ 17 /*{{ javascript("jslib/shadermanager.js") }}*/ 18 /*{{ javascript("jslib/texturemanager.js") }}*/ 19 /*{{ javascript("jslib/renderingcommon.js") }}*/ 20 /*{{ javascript("jslib/defaultrendering.js") }}*/ 21 /*{{ javascript("jslib/observer.js") }}*/ 22 /*{{ javascript("jslib/resourceloader.js") }}*/ 23 /*{{ javascript("jslib/utilities.js") }}*/ 24 /*{{ javascript("jslib/requesthandler.js") }}*/ 25 /*{{ javascript("jslib/vertexbuffermanager.js") }}*/ 26 /*{{ javascript("jslib/indexbuffermanager.js") }}*/ 27 /*{{ javascript("jslib/services/turbulenzservices.js") }}*/ 28 /*{{ javascript("jslib/services/turbulenzbridge.js") }}*/ 29 /*{{ javascript("jslib/services/gamesession.js") }}*/ 30 /*{{ javascript("jslib/services/mappingtable.js") }}*/ 31 /*{{ javascript("scripts/sceneloader.js") }}*/ 32 /*{{ javascript("scripts/motion.js") }}*/ 33 /*{{ javascript("scripts/htmlcontrols.js") }}*/ 34 /*global TurbulenzEngine: true */ 35 /*global TurbulenzServices: false */ 36 /*global Motion: false */ 37 /*global RequestHandler: false */ 38 /*global TextureManager: false */ 39 /*global ShaderManager: false */ 40 /*global EffectManager: false */ 41 /*global Scene: false */ 42 /*global SceneLoader: false */ 43 /*global Camera: false */ 44 /*global HTMLControls: false */ 45 /*global DefaultRendering: false */ 46 /*global VMath: false */ 47 TurbulenzEngine.onload = function onloadFn() { 48 var errorCallback = function errorCallback(msg) { 49 window.alert(msg); 50 }; 51 52 var graphicsDeviceParameters = {}; 53 var graphicsDevice = TurbulenzEngine.createGraphicsDevice(graphicsDeviceParameters); 54 55 if (!graphicsDevice.shadingLanguageVersion) { 56 errorCallback("No shading language support detected.\nPlease check your graphics drivers are up to date."); 57 graphicsDevice = null; 58 return; 59 } 60 61 // Clear the background color of the engine window 62 var clearColor = [0.5, 0.5, 0.5, 1.0]; 63 if (graphicsDevice.beginFrame()) { 64 graphicsDevice.clear(clearColor); 65 graphicsDevice.endFrame(); 66 } 67 68 var mathDeviceParameters = {}; 69 var mathDevice = TurbulenzEngine.createMathDevice(mathDeviceParameters); 70 71 var requestHandlerParameters = {}; 72 var requestHandler = RequestHandler.create(requestHandlerParameters); 73 74 var textureManager = TextureManager.create(graphicsDevice, requestHandler, null, errorCallback); 75 var shaderManager = ShaderManager.create(graphicsDevice, requestHandler, null, errorCallback); 76 var effectManager = EffectManager.create(); 77 78 var scene = Scene.create(mathDevice); 79 var sceneLoader = SceneLoader.create(); 80 var renderer; 81 82 // Setup world space 83 var worldUp = mathDevice.v3BuildYAxis(); 84 85 // Setup a camera to view a close-up object 86 var camera = Camera.create(mathDevice); 87 var cameraDistanceFactor = 1.0; 88 camera.nearPlane = 0.05; 89 90 // Choice of materials to view: 91 // 92 // 'defaultMaterialName' : A material with a texture and technique set on the object by the scene 93 // colouredMaterial : A material with a materialColor and technique that uses material Color to render 94 // newTextureMaterial : A material with a new texture other than the one specified by the scene 95 // The material list 96 var materials = { 97 newTextureMaterial: { 98 effect: "phong", 99 parameters: { 100 diffuse: "textures/brick.png" 101 } 102 }, 103 coloredMaterial: { 104 effect: "constant", 105 meta: { 106 materialcolor: true 107 }, 108 parameters: { 109 materialColor: VMath.v4Build(1.0, 0.1, 0.1, 1.0) 110 } 111 } 112 }; 113 114 // We will find the default material name after the scene is loaded 115 var defaultMaterialName; 116 117 // The name of the node we want to rotate to demonstrate the material 118 var nodeName = "LOD3sp"; 119 var objectNode = null; 120 var objectInstance = null; 121 122 var rotation = Motion.create(mathDevice, "scene"); 123 rotation.setConstantRotation(0.01); 124 125 // Initialize the previous frame time 126 var previousFrameTime = TurbulenzEngine.time; 127 128 var renderFrame = function renderFrameFn() { 129 var currentTime = TurbulenzEngine.time; 130 var deltaTime = (currentTime - previousFrameTime); 131 if (deltaTime > 0.1) { 132 deltaTime = 0.1; 133 } 134 135 var deviceWidth = graphicsDevice.width; 136 var deviceHeight = graphicsDevice.height; 137 var aspectRatio = (deviceWidth / deviceHeight); 138 if (aspectRatio !== camera.aspectRatio) { 139 camera.aspectRatio = aspectRatio; 140 camera.updateProjectionMatrix(); 141 } 142 camera.updateViewProjectionMatrix(); 143 144 if (objectNode) { 145 // Update the scene with rotation 146 rotation.update(deltaTime); 147 objectNode.setLocalTransform(rotation.matrix); 148 } 149 150 scene.update(); 151 152 renderer.update(graphicsDevice, camera, scene, currentTime); 153 154 if (graphicsDevice.beginFrame()) { 155 if (renderer.updateBuffers(graphicsDevice, deviceWidth, deviceHeight)) { 156 renderer.draw(graphicsDevice, clearColor); 157 } 158 159 graphicsDevice.endFrame(); 160 } 161 }; 162 163 // Controls 164 var htmlControls = HTMLControls.create(); 165 166 htmlControls.addRadioControl({ 167 id: "radio01", 168 groupName: "materialType", 169 radioIndex: 0, 170 value: "default", 171 fn: function () { 172 if (objectInstance) { 173 var materialName = defaultMaterialName; 174 var material = materials[materialName]; 175 if (material && material.loaded) { 176 // Set the material to use on the node 177 objectInstance.setMaterial(scene.getMaterial(materialName)); 178 } 179 } 180 }, 181 isDefault: true 182 }); 183 184 htmlControls.addRadioControl({ 185 id: "radio02", 186 groupName: "materialType", 187 radioIndex: 1, 188 value: "coloured", 189 fn: function () { 190 if (objectInstance) { 191 var materialName = "coloredMaterial"; 192 var material = materials[materialName]; 193 if (material && material.loaded) { 194 objectInstance.setMaterial(scene.getMaterial(materialName)); 195 } 196 } 197 }, 198 isDefault: false 199 }); 200 201 htmlControls.addRadioControl({ 202 id: "radio03", 203 groupName: "materialType", 204 radioIndex: 2, 205 value: "newTexture", 206 fn: function () { 207 if (objectInstance) { 208 var materialName = "newTextureMaterial"; 209 var material = materials[materialName]; 210 if (material && material.loaded) { 211 // Set the material to use on the node 212 objectInstance.setMaterial(scene.getMaterial(materialName)); 213 } 214 } 215 }, 216 isDefault: false 217 }); 218 htmlControls.register(); 219 220 var intervalID; 221 var loadingLoop = function loadingLoopFn() { 222 if (sceneLoader.complete()) { 223 TurbulenzEngine.clearInterval(intervalID); 224 225 // For the default texture, take the result loaded by the scene 226 objectNode = scene.findNode(nodeName); 227 if (objectNode) { 228 if (objectNode.hasRenderables()) { 229 objectInstance = objectNode.renderables[0]; 230 defaultMaterialName = objectInstance.getMaterial().getName(); 231 if (defaultMaterialName) { 232 // We don't have the material parameters or effect, but we can refer to it by name 233 materials[defaultMaterialName] = {}; 234 materials[defaultMaterialName].loaded = true; 235 scene.getMaterial(defaultMaterialName).reference.add(); 236 } 237 } 238 } 239 var sceneExtents = scene.getExtents(); 240 var sceneMinExtent = mathDevice.v3Build(sceneExtents[0], sceneExtents[1], sceneExtents[2]); 241 var sceneMaxExtent = mathDevice.v3Build(sceneExtents[3], sceneExtents[4], sceneExtents[5]); 242 var center = mathDevice.v3ScalarMul(mathDevice.v3Add(sceneMaxExtent, sceneMinExtent), 0.5); 243 var extent = mathDevice.v3Sub(center, sceneMinExtent); 244 245 camera.lookAt(center, worldUp, mathDevice.v3Build(center[0] + extent[0] * 2 * cameraDistanceFactor, center[1] + extent[1] * cameraDistanceFactor, center[2] + extent[2] * 2 * cameraDistanceFactor)); 246 camera.updateViewMatrix(); 247 248 renderer.updateShader(shaderManager); 249 250 intervalID = TurbulenzEngine.setInterval(renderFrame, 1000 / 60); 251 } 252 }; 253 intervalID = TurbulenzEngine.setInterval(loadingLoop, 1000 / 10); 254 255 var postLoad = function postLoadFn() { 256 for (var m in materials) { 257 if (materials.hasOwnProperty(m)) { 258 if (scene.loadMaterial(graphicsDevice, textureManager, effectManager, m, materials[m])) { 259 materials[m].loaded = true; 260 scene.getMaterial(m).reference.add(); 261 } else { 262 errorCallback("Failed to load material: " + m); 263 } 264 } 265 } 266 }; 267 268 var loadAssets = function loadAssetsFn() { 269 // Renderer for the scene (requires shader assets). 270 renderer = DefaultRendering.create(graphicsDevice, mathDevice, shaderManager, effectManager); 271 272 renderer.setGlobalLightPosition(mathDevice.v3Build(0.5, 100.0, 0.5)); 273 renderer.setAmbientColor(mathDevice.v3Build(0.3, 0.3, 0.4)); 274 275 // Create object using scene loader 276 sceneLoader.load({ 277 scene: scene, 278 assetPath: "models/duck.dae", 279 graphicsDevice: graphicsDevice, 280 mathDevice: mathDevice, 281 textureManager: textureManager, 282 effectManager: effectManager, 283 shaderManager: shaderManager, 284 requestHandler: requestHandler, 285 append: false, 286 dynamic: true, 287 postSceneLoadFn: postLoad 288 }); 289 }; 290 291 var mappingTableReceived = function mappingTableReceivedFn(mappingTable) { 292 textureManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 293 shaderManager.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 294 sceneLoader.setPathRemapping(mappingTable.urlMapping, mappingTable.assetPrefix); 295 296 loadAssets(); 297 }; 298 299 var gameSessionCreated = function gameSessionCreatedFn(gameSession) { 300 TurbulenzServices.createMappingTable(requestHandler, gameSession, mappingTableReceived); 301 }; 302 var gameSession = TurbulenzServices.createGameSession(requestHandler, gameSessionCreated); 303 304 // Create a scene destroy callback to run when the window is closed 305 TurbulenzEngine.onunload = function destroyScene() { 306 TurbulenzEngine.clearInterval(intervalID); 307 308 if (gameSession) { 309 gameSession.destroy(); 310 gameSession = null; 311 } 312 313 clearColor = null; 314 315 rotation = null; 316 if (scene) { 317 scene.destroy(); 318 scene = null; 319 } 320 requestHandler = null; 321 322 if (renderer) { 323 renderer.destroy(); 324 renderer = null; 325 } 326 327 materials = null; 328 329 camera = null; 330 331 if (textureManager) { 332 textureManager.destroy(); 333 textureManager = null; 334 } 335 336 if (shaderManager) { 337 shaderManager.destroy(); 338 shaderManager = null; 339 } 340 341 effectManager = null; 342 343 TurbulenzEngine.flush(); 344 graphicsDevice = null; 345 mathDevice = null; 346 }; 347 };