immediate_mode_rendering.js
  1 /*{# Copyright (c) 2010-2012 Turbulenz Limited #}*/
  2 ;
  3 
  4 /*
  5 * @title: Immediate rendering
  6 * @description:
  7 * This sample demonstrates how to use the low level API of the Turbulenz graphics device.
  8 * It shows how to load shaders, change techniques, and how to create and dispatch dynamic index and vertex buffers
  9 * to render simple 2D animations.
 10 */
 11 /*{{ javascript("jslib/camera.js") }}*/
 12 /*{{ javascript("jslib/observer.js") }}*/
 13 /*{{ javascript("jslib/utilities.js") }}*/
 14 /*{{ javascript("jslib/requesthandler.js") }}*/
 15 /*{{ javascript("jslib/services/turbulenzservices.js") }}*/
 16 /*{{ javascript("jslib/services/turbulenzbridge.js") }}*/
 17 /*{{ javascript("jslib/services/gamesession.js") }}*/
 18 /*{{ javascript("jslib/services/mappingtable.js") }}*/
 19 /*global RequestHandler: false */
 20 /*global TurbulenzEngine: false */
 21 /*global TurbulenzServices: false */
 22 /*global Camera: false */
 23 TurbulenzEngine.onload = function onloadFn() {
 24     var errorCallback = function errorCallback(msg) {
 25         window.alert(msg);
 26     };
 27 
 28     // Create the engine devices objects
 29     // This sample uses the 'graphicsDevice' to demonstrate different basic rendering techniques
 30     var graphicsDeviceParameters = {};
 31     var graphicsDevice = TurbulenzEngine.createGraphicsDevice(graphicsDeviceParameters);
 32 
 33     if (!graphicsDevice.shadingLanguageVersion) {
 34         errorCallback("No shading language support detected.\nPlease check your graphics drivers are up to date.");
 35         graphicsDevice = null;
 36         return;
 37     }
 38 
 39     // Clear the background color of the engine window
 40     var clearColor = [0.0, 0.0, 0.0, 1.0];
 41     if (graphicsDevice.beginFrame()) {
 42         graphicsDevice.clear(clearColor);
 43         graphicsDevice.endFrame();
 44     }
 45 
 46     var mathDeviceParameters = {};
 47     var mathDevice = TurbulenzEngine.createMathDevice(mathDeviceParameters);
 48 
 49     var requestHandlerParameters = {};
 50     var requestHandler = RequestHandler.create(requestHandlerParameters);
 51 
 52     var camera = Camera.create(mathDevice);
 53     var worldUp = mathDevice.v3BuildYAxis();
 54     camera.lookAt(mathDevice.v3Build(0, 0, -100), worldUp, mathDevice.v3Build(0, 4, 15.0));
 55     camera.updateViewMatrix();
 56     camera.updateProjectionMatrix();
 57 
 58     var aspectRatio = (graphicsDevice.width / graphicsDevice.height);
 59     if (aspectRatio !== camera.aspectRatio) {
 60         camera.aspectRatio = aspectRatio;
 61         camera.updateProjectionMatrix();
 62     }
 63     camera.updateViewProjectionMatrix();
 64 
 65     // Create techniqueParameters for each object
 66     var techniqueParameters = graphicsDevice.createTechniqueParameters({
 67         worldViewProjection: camera.viewProjectionMatrix,
 68         constantColor: [1.0, 0.0, 0.0, 0.5]
 69     });
 70     var techniqueParametersProceduralTexture = graphicsDevice.createTechniqueParameters({
 71         worldViewProjection: camera.viewProjectionMatrix,
 72         diffuse: null
 73     });
 74     var techniqueParametersCrateTexture = graphicsDevice.createTechniqueParameters({
 75         worldViewProjection: camera.viewProjectionMatrix,
 76         diffuse: null
 77     });
 78     var techniqueParametersPoint = graphicsDevice.createTechniqueParameters({
 79         worldViewProjection: camera.viewProjectionMatrix,
 80         constantColor: [1.0, 0.0, 0.0, 0.5],
 81         pointSize: 1
 82     });
 83 
 84     // Create semantics for specifing the vertices/colors/textureCoords
 85     var semanticsTypes = {
 86         position: null,
 87         color: null,
 88         positionAndTexture: null
 89     };
 90     var vertexFormatTypes = {
 91         position: undefined,
 92         color: undefined,
 93         positionAndTexture: undefined
 94     };
 95 
 96     // Only the position
 97     semanticsTypes.position = graphicsDevice.createSemantics([graphicsDevice.SEMANTIC_POSITION]);
 98     vertexFormatTypes.position = [graphicsDevice.VERTEXFORMAT_FLOAT3];
 99 
100     // Only the color (with alpha, rgba)
101     semanticsTypes.color = graphicsDevice.createSemantics([graphicsDevice.SEMANTIC_COLOR]);
102     vertexFormatTypes.color = [graphicsDevice.VERTEXFORMAT_FLOAT4];
103 
104     // Both position and texture coordinate
105     semanticsTypes.positionAndTexture = graphicsDevice.createSemantics([graphicsDevice.SEMANTIC_POSITION, graphicsDevice.SEMANTIC_TEXCOORD]);
106     vertexFormatTypes.positionAndTexture = [graphicsDevice.VERTEXFORMAT_FLOAT3, graphicsDevice.VERTEXFORMAT_SHORT2];
107 
108     var shader = null;
109 
110     // Creation of render objects
111     // The grid, drawn as lines with a constant color
112     var gridRenderObject = {
113         techniqueName: "constantColor3D",
114         semanticName: "position",
115         primitive: graphicsDevice.PRIMITIVE_LINES,
116         numOfRenderItems: 5,
117         technique: null,
118         vertexFormats: null,
119         semantics: null,
120         techniqueParameters: null,
121         startPosition: [1.0, 1.0, 0.0],
122         color: [1.0, 0.0, 0.0, 0.5],
123         isInit: false,
124         accTime: 0,
125         animPeriod: 0.2,
126         animStep: 1,
127         maxNumOfRenderItems: 5,
128         update: function updateFn(delta) {
129             var numOfLevels = this.numOfRenderItems;
130             var maxNumOfRenderItems = this.maxNumOfRenderItems;
131             var animPeriod = this.animPeriod;
132 
133             this.accTime += delta;
134             if (this.accTime > animPeriod) {
135                 this.numOfRenderItems = (numOfLevels + this.animStep) % (maxNumOfRenderItems + 1);
136                 this.accTime = 0;
137             }
138         },
139         init: function initFn() {
140             // Initialise the references to semantics/vertexFormats
141             var semanticName = this.semanticName;
142             this.semantics = semanticsTypes[semanticName];
143             this.vertexFormats = vertexFormatTypes[semanticName];
144             this.techniqueParameters = techniqueParameters;
145             this.isInit = (this.semantics && this.vertexFormats && this.techniqueParameters);
146         },
147         draw: function drawFn(graphicsDevice) {
148             var numOfLines = this.numOfRenderItems + 1;
149             var startX = this.startPosition[0];
150             var startY = this.startPosition[1];
151             var startZ = this.startPosition[2];
152 
153             var primitive = this.primitive;
154             var techniqueParameters = this.techniqueParameters;
155             var vertexFormats = this.vertexFormats;
156             var semantics = this.semantics;
157 
158             if (this.isInit) {
159                 // Shared techniqueParameters, so set the color
160                 // This is the techniqueParameters to be used for this draw
161                 techniqueParameters.constantColor = this.color;
162                 graphicsDevice.setTechniqueParameters(techniqueParameters);
163 
164                 // Draw directly using a writer to populate the vertices
165                 // In this case only positions of x,y,z are being written
166                 var writer = graphicsDevice.beginDraw(primitive, numOfLines * 4, vertexFormats, semantics);
167                 if (writer) {
168                     var ns = numOfLines - 1;
169                     for (var i = 0; i < numOfLines; i += 1) {
170                         var xs = startX + i;
171                         var ys = startY + i;
172                         var xe = startX + ns;
173                         var ye = startY + ns;
174                         writer(xs, startY, startZ);
175                         writer(xs, ye, startZ);
176                         writer(startX, ys, startZ);
177                         writer(xe, ys, startZ);
178                     }
179                     graphicsDevice.endDraw(writer);
180                 }
181             }
182         }
183     };
184 
185     // The circle, drawn as points of a constant color
186     var circleRenderObject = {
187         techniqueName: "pointConstantColor3D",
188         semanticName: "position",
189         primitive: graphicsDevice.PRIMITIVE_POINTS,
190         numOfRenderItems: 1500,
191         technique: null,
192         vertexFormats: null,
193         semantics: null,
194         techniqueParameters: null,
195         startPosition: [10.0, 3.5, 0.0],
196         color: [0.0, 1.0, 0.0, 0.5],
197         radius: 2.5,
198         isInit: false,
199         init: function initFn() {
200             var semanticName = this.semanticName;
201             this.semantics = semanticsTypes[semanticName];
202             this.vertexFormats = vertexFormatTypes[semanticName];
203             this.techniqueParameters = techniqueParametersPoint;
204             this.isInit = (this.semantics && this.vertexFormats && this.techniqueParameters);
205         },
206         draw: function drawFn(graphicsDevice) {
207             var numOfRenderItems = this.numOfRenderItems;
208             var startX = this.startPosition[0];
209             var startY = this.startPosition[1];
210             var startZ = this.startPosition[2];
211 
212             var primitive = this.primitive;
213             var vertexFormats = this.vertexFormats;
214             var semantics = this.semantics;
215 
216             if (this.isInit) {
217                 this.techniqueParameters.constantColor = this.color;
218                 graphicsDevice.setTechniqueParameters(this.techniqueParameters);
219 
220                 // Draw using a writer to add only positions (x,y,z)
221                 var writer = graphicsDevice.beginDraw(primitive, numOfRenderItems, vertexFormats, semantics);
222                 if (writer) {
223                     var sinfn = Math.sin;
224                     var cosfn = Math.cos;
225                     var random = Math.random;
226 
227                     var pi2 = 2 * Math.PI;
228                     var inc = pi2 / 64;
229 
230                     var radius = this.radius;
231                     var sin, cos, r;
232 
233                     for (var i = 0, t = 0; i < numOfRenderItems; i += 1) {
234                         // Random positions are used to make the points clearer to visualise
235                         r = radius * random();
236                         sin = sinfn(t);
237                         cos = cosfn(t);
238                         writer((r * sin) + startX, (r * cos) + startY, startZ);
239                         t += inc;
240                         if (t > pi2) {
241                             t -= pi2;
242                         }
243                     }
244 
245                     graphicsDevice.endDraw(writer);
246                 }
247             }
248         }
249     };
250 
251     // The spiral, drawn using a procedurally generated texture
252     var spiralRenderObject = {
253         techniqueName: "textured3D",
254         semanticName: "positionAndTexture",
255         primitive: graphicsDevice.PRIMITIVE_TRIANGLES,
256         numOfRenderItems: 17,
257         technique: null,
258         vertexFormats: null,
259         semantics: null,
260         techniqueParameters: null,
261         startPosition: [-4.5, 4.5, 0.0],
262         color: [1.0, 0.0, 1.0, 0.5],
263         scale: 0.5,
264         thetaInc: 0,
265         isInit: false,
266         accTime: 0,
267         animPeriod: 0.5,
268         animStep: 1,
269         maxNumOfRenderItems: 17,
270         update: function updateFn(delta) {
271             var maxNumOfRenderItems = this.maxNumOfRenderItems;
272             var animPeriod = this.animPeriod;
273 
274             // Increase/decrease the number of iterations
275             this.accTime += delta;
276             if (this.accTime > animPeriod) {
277                 this.numOfRenderItems += this.animStep;
278                 if (this.numOfRenderItems < 1) {
279                     this.numOfRenderItems = 1;
280                     this.animStep *= -1;
281                 } else if (this.numOfRenderItems > maxNumOfRenderItems) {
282                     this.numOfRenderItems = maxNumOfRenderItems;
283                     this.animStep *= -1;
284                 }
285                 this.accTime = 0;
286             }
287         },
288         init: function initFn() {
289             var semanticName = this.semanticName;
290             this.semantics = semanticsTypes[semanticName];
291             this.vertexFormats = vertexFormatTypes[semanticName];
292             this.techniqueParameters = techniqueParametersProceduralTexture;
293 
294             // Pre-calculate the theta amount to increase per step
295             this.thetaInc = (2 * Math.PI) / 16;
296             this.isInit = (this.semantics && this.vertexFormats && this.techniqueParameters);
297         },
298         draw: function drawFn(graphicsDevice/*, delta */ ) {
299             var numOfRenderLevels = this.numOfRenderItems;
300             var startX = this.startPosition[0];
301             var startY = this.startPosition[1];
302             var startZ = this.startPosition[2];
303 
304             var primitive = this.primitive;
305             var techniqueParameters = this.techniqueParameters;
306             var vertexFormats = this.vertexFormats;
307             var semantics = this.semantics;
308 
309             var scale = this.scale;
310             var thetaInc = this.thetaInc;
311 
312             var sin, cos, at;
313             var theta, absX, absY;
314             var x0, y0, x1, y1, x2, y2, x3, y3;
315 
316             techniqueParameters.constantColor = this.color;
317             graphicsDevice.setTechniqueParameters(techniqueParameters);
318 
319             if (this.isInit) {
320                 // Direct draw, specifying a position (x,y,z) and texture coordinate (u,v)
321                 var writer = graphicsDevice.beginDraw(primitive, (numOfRenderLevels * 6), vertexFormats, semantics);
322                 if (writer) {
323                     var sinfn = Math.sin;
324                     var cosfn = Math.cos;
325                     var absfn = Math.abs;
326                     theta = 0;
327                     x0 = startX;
328                     y0 = startY;
329                     x2 = startX;
330                     y2 = startY;
331 
332                     for (var i = 0; i < numOfRenderLevels; i += 1) {
333                         theta += thetaInc;
334                         at = scale * theta;
335                         sin = sinfn(theta);
336                         cos = cosfn(theta);
337 
338                         x1 = (at * cos) + startX;
339                         y1 = (at * sin) + startY;
340                         absX = absfn(x0 - startX);
341                         absY = absfn(y0 - startY);
342                         x3 = x0 + ((x0 > startX) ? scale * absX : -scale * absX);
343                         y3 = y0 + ((y0 > startY) ? scale * absY : -scale * absY);
344 
345                         // Draws two triangles for each iterative step of the algorithm
346                         writer(x3, y3, startZ, 0, 0);
347                         writer(x1, y1, startZ, 1, 1);
348                         writer(x0, y0, startZ, 0, 0);
349 
350                         writer(x2, y2, startZ, 0, 0);
351                         writer(x3, y3, startZ, 1, 1);
352                         writer(x0, y0, startZ, 0, 0);
353 
354                         x0 = x1;
355                         y0 = y1;
356                         x2 = x3;
357                         y2 = y3;
358                     }
359 
360                     graphicsDevice.endDraw(writer);
361                 }
362             }
363         }
364     };
365 
366     // The textured panel, drawn using variable vertex colors
367     var panelRenderObject = {
368         techniqueName: "vertexColorTextured3D",
369         primitive: graphicsDevice.PRIMITIVE_TRIANGLES,
370         numOfRenderItems: 5,
371         colorStream: {
372             semanticName: "color",
373             semantics: null,
374             vertexBuffer: null
375         },
376         positionStream: {
377             semanticName: "positionAndTexture",
378             semantics: null,
379             vertexBuffer: null
380         },
381         indexBuffer: null,
382         technique: null,
383         techniqueParameters: null,
384         startPosition: [-13.0, 1.0, 0.0],
385         color: [0.0, 1.0, 1.0, 0.5],
386         isInit: false,
387         remapColors: function remapColorsFn(colors) {
388             // Code needs to be updated for efficiency
389             // Update the colors used for the vertices
390             var numOfRenderItems = this.numOfRenderItems;
391             var coloredItems = numOfRenderItems * numOfRenderItems * 4;
392             var random = Math.random;
393 
394             if (colors) {
395                 var writer = colors.map();
396                 if (writer) {
397                     var r, g, b;
398                     for (var i = 0; i < coloredItems; i += 1) {
399                         r = random();
400                         g = random();
401                         b = random();
402                         writer(r, g, b, 1);
403                     }
404 
405                     colors.unmap(writer);
406                     writer = null;
407                 }
408             }
409         },
410         update: function updateFn(/* delta */ ) {
411             if (this.isInit) {
412                 this.remapColors(this.colorStream.vertexBuffer);
413             }
414         },
415         init: function initFn() {
416             var numOfLevels = this.numOfRenderItems;
417             var numOfLevelsSqrd = numOfLevels * numOfLevels;
418             var coloredItems = numOfLevelsSqrd * 4;
419             var colorStream = this.colorStream;
420             var positionStream = this.positionStream;
421             var indexBuffer = this.indexBuffer;
422 
423             var writer, i;
424 
425             var positionsParameters = {
426                 numVertices: coloredItems,
427                 attributes: ['FLOAT3', 'SHORT2'],
428                 dynamic: false
429             };
430 
431             var colorsParameters = {
432                 numVertices: coloredItems,
433                 attributes: ['UBYTE4N'],
434                 dynamic: true
435             };
436 
437             var positions = graphicsDevice.createVertexBuffer(positionsParameters);
438             var colors = graphicsDevice.createVertexBuffer(colorsParameters);
439 
440             colorStream.semantics = semanticsTypes[colorStream.semanticName];
441             positionStream.semantics = semanticsTypes[positionStream.semanticName];
442 
443             this.remapColors(colors);
444             colorStream.vertexBuffer = colors;
445 
446             if (!indexBuffer) {
447                 var indexBufferParameters = {
448                     numIndices: numOfLevelsSqrd * 6,
449                     format: 'USHORT'
450                 };
451 
452                 indexBuffer = graphicsDevice.createIndexBuffer(indexBufferParameters);
453 
454                 writer = indexBuffer.map();
455                 if (writer) {
456                     var v0, v1, v2, v3;
457                     for (i = 0; i < numOfLevelsSqrd; i += 1) {
458                         v0 = 4 * i + 0;
459                         v1 = 4 * i + 1;
460                         v2 = 4 * i + 2;
461                         v3 = 4 * i + 3;
462                         writer(v0, v1, v2);
463                         writer(v2, v3, v0);
464                     }
465 
466                     indexBuffer.unmap(writer);
467                 }
468 
469                 this.indexBuffer = indexBuffer;
470             }
471 
472             if (positions) {
473                 writer = positions.map();
474                 if (writer) {
475                     var startX = this.startPosition[0];
476                     var startY = this.startPosition[1];
477                     var startZ = this.startPosition[2];
478 
479                     for (i = 0; i < numOfLevels; i += 1) {
480                         var xs = (startX + i);
481                         var xe = (xs + 1);
482                         for (var j = 0; j < numOfLevels; j += 1) {
483                             var ys = (startY + j);
484                             var ye = (ys + 1);
485                             writer(xs, ys, startZ, 0, 0);
486                             writer(xe, ys, startZ, 1, 0);
487                             writer(xe, ye, startZ, 1, 1);
488                             writer(xs, ye, startZ, 0, 1);
489                         }
490                     }
491 
492                     positions.unmap(writer);
493                     writer = null;
494                     positionStream.vertexBuffer = positions;
495                 }
496             }
497 
498             // Allows panel to be drawn before the texture is loaded
499             this.techniqueParameters = techniqueParametersCrateTexture;
500             this.isInit = (colorStream.vertexBuffer && positionStream.vertexBuffer && this.techniqueParameters);
501         },
502         draw: function drawFn(graphicsDevice) {
503             var primitive = this.primitive;
504             var techniqueParameters = this.techniqueParameters;
505             var colors = this.colorStream.vertexBuffer;
506             var colorSemantics = this.colorStream.semantics;
507             var positions = this.positionStream.vertexBuffer;
508             var positionSemantics = this.positionStream.semantics;
509             var indexBuffer = this.indexBuffer;
510 
511             if (this.isInit) {
512                 // Sets the vertexBuffers to use for the draw call
513                 graphicsDevice.setStream(colors, colorSemantics);
514                 graphicsDevice.setStream(positions, positionSemantics);
515 
516                 // Sets the techniqueParameters, in this case a crate texture with shader with vertexColorTextured3D technique
517                 graphicsDevice.setTechniqueParameters(techniqueParameters);
518 
519                 // Draw quads
520                 graphicsDevice.setIndexBuffer(indexBuffer);
521                 graphicsDevice.drawIndexed(primitive, indexBuffer.numIndices);
522             }
523         }
524     };
525 
526     // Sets objects to render
527     var renderObjects = [
528         circleRenderObject,
529         gridRenderObject,
530         spiralRenderObject,
531         panelRenderObject
532     ];
533 
534     // Generate texture (Simple checkerboard)
535     var proceduralTextureParameters = {
536         name: "checkers",
537         width: 4,
538         height: 4,
539         depth: 1,
540         format: graphicsDevice.PIXELFORMAT_L8,
541         mipmaps: true,
542         cubemap: false,
543         renderable: false,
544         dynamic: false,
545         data: [
546             0,
547             255,
548             0,
549             255,
550             255,
551             0,
552             255,
553             0,
554             0,
555             255,
556             0,
557             255,
558             255,
559             0,
560             255,
561             0
562         ]
563     };
564 
565     var proceduralTexture = graphicsDevice.createTexture(proceduralTextureParameters);
566     techniqueParametersProceduralTexture['diffuse'] = proceduralTexture;
567 
568     // Init objects
569     spiralRenderObject.init();
570     gridRenderObject.init();
571     circleRenderObject.init();
572     panelRenderObject.init();
573 
574     var intervalID;
575     var previousTime = TurbulenzEngine.time;
576     var renderObj = null;
577 
578     var renderFrame = function renderFrameFn() {
579         var currentTime = TurbulenzEngine.time;
580         var deltaTime = currentTime - previousTime;
581         if (deltaTime > 0.1) {
582             deltaTime = 0.1;
583         }
584 
585         // Update objects (in this case animate)
586         var renderObjectsCount = renderObjects.length;
587         for (var n = 0; n < renderObjectsCount; n += 1) {
588             renderObj = renderObjects[n];
589             var updateObj = renderObj.update;
590             if (updateObj) {
591                 renderObj.update(deltaTime);
592             }
593         }
594 
595         // Update the aspect ratio of the camera in case of window resizes
596         var aspectRatio = (graphicsDevice.width / graphicsDevice.height);
597         if (aspectRatio !== camera.aspectRatio) {
598             camera.aspectRatio = aspectRatio;
599             camera.updateProjectionMatrix();
600         }
601         camera.updateViewProjectionMatrix();
602 
603         var vp = camera.viewProjectionMatrix;
604 
605         if (graphicsDevice.beginFrame()) {
606             graphicsDevice.clear(clearColor, 1.0, 0);
607 
608             for (var m = 0; m < renderObjectsCount; m += 1) {
609                 renderObj = renderObjects[m];
610                 var technique = renderObj.technique;
611 
612                 if (!technique) {
613                     technique = shader.getTechnique(renderObj.techniqueName);
614                     if (technique) {
615                         renderObj.technique = technique;
616                     }
617                 }
618 
619                 if (technique) {
620                     graphicsDevice.setTechnique(technique);
621 
622                     var techniqueParameters = renderObj.techniqueParameters;
623                     if (techniqueParameters) {
624                         techniqueParameters.worldViewProjection = vp;
625                     }
626 
627                     renderObj.draw(graphicsDevice);
628                 }
629             }
630 
631             graphicsDevice.endFrame();
632         }
633         previousTime = currentTime;
634     };
635 
636     var crateTextureLoaded = false;
637     var loadingLoop = function loadingLoopFn() {
638         if (shader && crateTextureLoaded) {
639             TurbulenzEngine.clearInterval(intervalID);
640 
641             intervalID = TurbulenzEngine.setInterval(renderFrame, 1000 / 60);
642         }
643     };
644 
645     // Start calling the loading loop at 10Hz
646     intervalID = TurbulenzEngine.setInterval(loadingLoop, 1000 / 10);
647 
648     var mappingTableReceived = function mappingTableReceivedFn(mappingTable) {
649         // Load shader and techniques
650         var shaderLoaded = function shaderLoadedFn(shaderText) {
651             if (shaderText) {
652                 var shaderParameters = JSON.parse(shaderText);
653                 shader = graphicsDevice.createShader(shaderParameters);
654             }
655         };
656 
657         requestHandler.request({
658             src: mappingTable.getURL("shaders/generic3D.cgfx"),
659             onload: shaderLoaded
660         });
661 
662         var crateTextureParameters = {
663             src: mappingTable.getURL("textures/crate.jpg"),
664             mipmaps: true,
665             onload: function (texture) {
666                 techniqueParametersCrateTexture['diffuse'] = texture;
667                 crateTextureLoaded = true;
668             }
669         };
670         graphicsDevice.createTexture(crateTextureParameters);
671     };
672 
673     var gameSessionCreated = function gameSessionCreatedFn(gameSession) {
674         TurbulenzServices.createMappingTable(requestHandler, gameSession, mappingTableReceived);
675     };
676     var gameSession = TurbulenzServices.createGameSession(requestHandler, gameSessionCreated);
677 
678     // Create a scene destroy callback to run when the window is closed
679     TurbulenzEngine.onunload = function destroyScene() {
680         TurbulenzEngine.clearInterval(intervalID);
681 
682         if (gameSession) {
683             gameSession.destroy();
684             gameSession = null;
685         }
686 
687         requestHandler = null;
688         camera = null;
689         techniqueParameters = null;
690         techniqueParametersProceduralTexture = null;
691         techniqueParametersCrateTexture = null;
692         semanticsTypes = null;
693         vertexFormatTypes = null;
694         renderObjects.length = 0;
695         proceduralTexture = null;
696         TurbulenzEngine.flush();
697         graphicsDevice = null;
698         mathDevice = null;
699         requestHandler = null;
700     };
701 };