1 /*{# Copyright (c) 2012 Turbulenz Limited #}*/ 2 /* 3 * @title: Video playback 4 * @description: 5 * This sample shows how to play a video into a texture. 6 */ 7 /*{{ javascript("jslib/observer.js") }}*/ 8 /*{{ javascript("jslib/requesthandler.js") }}*/ 9 /*{{ javascript("jslib/utilities.js") }}*/ 10 /*{{ javascript("jslib/services/turbulenzservices.js") }}*/ 11 /*{{ javascript("jslib/services/turbulenzbridge.js") }}*/ 12 /*{{ javascript("jslib/services/gamesession.js") }}*/ 13 /*{{ javascript("jslib/services/mappingtable.js") }}*/ 14 /*global TurbulenzEngine: true */ 15 /*global TurbulenzServices: false */ 16 /*global RequestHandler: false */ 17 TurbulenzEngine.onload = function onloadFn() { 18 var graphicsDevice = TurbulenzEngine.createGraphicsDevice({}); 19 20 if (graphicsDevice && graphicsDevice.renderer === "Internet Explorer") { 21 window.alert("The video sample is not supported on Internet Explorer"); 22 return; 23 } 24 var soundDevice = TurbulenzEngine.createSoundDevice({}); 25 var mathDevice = TurbulenzEngine.createMathDevice({}); 26 var requestHandler = RequestHandler.create({}); 27 28 var video; 29 var videoPosition = -1; 30 31 var shader, technique; 32 var texture; 33 34 var clearColor = mathDevice.v4Build(0, 0, 0, 1); 35 var clipSpace = mathDevice.v4Build(1, -1, 0, 0); 36 var videoColor = mathDevice.v4Build(1, 1, 1, 1); 37 38 var primitive = graphicsDevice.PRIMITIVE_TRIANGLE_STRIP; 39 var semantics = graphicsDevice.createSemantics(['POSITION', 'TEXCOORD0']); 40 var vertexBuffer = graphicsDevice.createVertexBuffer({ 41 numVertices: 4, 42 attributes: [ 43 graphicsDevice.VERTEXFORMAT_FLOAT2, 44 graphicsDevice.VERTEXFORMAT_FLOAT2 45 ], 46 dynamic: false, 47 data: [ 48 -1.0, 49 1.0, 50 0.0, 51 1.0, 52 1.0, 53 1.0, 54 1.0, 55 1.0, 56 -1.0, 57 -1.0, 58 0.0, 59 0.0, 60 1.0, 61 -1.0, 62 1.0, 63 0.0 64 ] 65 }); 66 67 var source = soundDevice.createSource({ 68 position: [0, 0, 0], 69 relative: true, 70 looping: true 71 }); 72 var sound; 73 74 var assetsToLoad = 3; 75 76 function mappingTableReceived(mappingTable) { 77 var videoURL; 78 if (graphicsDevice.isSupported("FILEFORMAT_WEBM")) { 79 videoURL = mappingTable.getURL("videos/turbulenzanimation.webm"); 80 } else { 81 videoURL = mappingTable.getURL("videos/turbulenzanimation.mp4"); 82 } 83 84 graphicsDevice.createVideo({ 85 src: videoURL, 86 looping: true, 87 onload: function (v) { 88 if (v) { 89 video = v; 90 91 assetsToLoad -= 1; 92 } else { 93 window.alert("Failed to load video!"); 94 } 95 } 96 }); 97 98 var soundURL; 99 if (soundDevice.isSupported("FILEFORMAT_OGG")) { 100 soundURL = mappingTable.getURL("sounds/turbulenzanimation.ogg"); 101 } else { 102 soundURL = mappingTable.getURL("sounds/turbulenzanimation.mp3"); 103 } 104 105 soundDevice.createSound({ 106 src: soundURL, 107 onload: function (s) { 108 if (s) { 109 sound = s; 110 111 assetsToLoad -= 1; 112 } else { 113 window.alert('Failed to load sound!'); 114 } 115 } 116 }); 117 118 function shaderLoaded(shaderText) { 119 if (shaderText) { 120 var shaderParameters = JSON.parse(shaderText); 121 shader = graphicsDevice.createShader(shaderParameters); 122 123 technique = shader.getTechnique("video"); 124 125 assetsToLoad -= 1; 126 } else { 127 window.alert("Failed to load shader!"); 128 } 129 } 130 131 requestHandler.request({ 132 src: mappingTable.getURL("shaders/video.cgfx"), 133 onload: shaderLoaded 134 }); 135 } 136 137 var gameSession; 138 function sessionCreated() { 139 TurbulenzServices.createMappingTable(requestHandler, gameSession, mappingTableReceived); 140 } 141 142 gameSession = TurbulenzServices.createGameSession(requestHandler, sessionCreated); 143 144 //========================================================================== 145 // Main loop. 146 //========================================================================== 147 var fpsElement = document.getElementById("fpscounter"); 148 var lastFPS = ""; 149 var nextUpdate = 0; 150 function displayPerformance() { 151 var currentTime = TurbulenzEngine.time; 152 if (currentTime > nextUpdate) { 153 nextUpdate = (currentTime + 0.1); 154 155 var fpsText = (graphicsDevice.fps).toFixed(2); 156 if (lastFPS !== fpsText) { 157 lastFPS = fpsText; 158 fpsElement.innerHTML = fpsText + " fps"; 159 } 160 } 161 } 162 163 function mainLoop() { 164 soundDevice.update(); 165 166 if (graphicsDevice.beginFrame()) { 167 var deviceWidth = graphicsDevice.width; 168 var deviceHeight = graphicsDevice.height; 169 var aspectRatio = (deviceWidth / deviceHeight); 170 171 var videoWidth = video.width; 172 var videoHeight = video.height; 173 var videoAspectRatio = (videoWidth / videoHeight); 174 175 var x, y; 176 if (aspectRatio < videoAspectRatio) { 177 x = 1; 178 y = aspectRatio / videoAspectRatio; 179 } else { 180 x = videoAspectRatio / aspectRatio; 181 y = 1; 182 } 183 184 var currentVideoPosition = video.tell; 185 if (currentVideoPosition && videoPosition !== currentVideoPosition) { 186 if (currentVideoPosition < videoPosition) { 187 // looped, sync 188 source.seek(videoPosition); 189 } 190 191 videoPosition = currentVideoPosition; 192 texture.setData(video); 193 } 194 195 graphicsDevice.clear(clearColor); 196 197 graphicsDevice.setTechnique(technique); 198 technique.texture = texture; 199 technique.clipSpace = mathDevice.v4Build(x, -y, 0, 0, clipSpace); 200 technique.color = videoColor; 201 202 graphicsDevice.setStream(vertexBuffer, semantics); 203 graphicsDevice.draw(primitive, 4); 204 205 graphicsDevice.endFrame(); 206 207 if (fpsElement) { 208 displayPerformance(); 209 } 210 } 211 } 212 213 var intervalID; 214 function loadingLoop() { 215 if (assetsToLoad === 0) { 216 TurbulenzEngine.clearInterval(intervalID); 217 218 source.play(sound); 219 220 video.play(); 221 222 texture = graphicsDevice.createTexture({ 223 width: video.width, 224 height: video.height, 225 mipmaps: false, 226 format: 'R8G8B8', 227 dynamic: true, 228 data: video 229 }); 230 231 videoPosition = video.tell; 232 233 intervalID = TurbulenzEngine.setInterval(mainLoop, 1000 / 60); 234 } 235 } 236 237 intervalID = TurbulenzEngine.setInterval(loadingLoop, 100); 238 239 // Create a scene destroy callback to run when the window is closed 240 TurbulenzEngine.onunload = function destroyScene() { 241 TurbulenzEngine.clearInterval(intervalID); 242 243 if (texture) { 244 texture.destroy(); 245 texture = null; 246 } 247 248 if (shader) { 249 shader.destroy(); 250 technique = null; 251 shader = null; 252 } 253 254 if (video) { 255 video.destroy(); 256 video = null; 257 } 258 259 if (vertexBuffer) { 260 vertexBuffer.destroy(); 261 vertexBuffer = null; 262 } 263 264 if (source) { 265 source.destroy(); 266 source = null; 267 } 268 269 if (sound) { 270 sound.destroy(); 271 sound = null; 272 } 273 274 fpsElement = null; 275 276 if (gameSession) { 277 gameSession.destroy(); 278 gameSession = null; 279 } 280 }; 281 };