material.js
  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 };