summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/performance
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html401
-rw-r--r--dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/README35
-rw-r--r--dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/shader-cache.txt2747
-rw-r--r--dom/canvas/test/webgl-conf/checkout/performance/webgl_webcodecs_video_frame/index.html186
4 files changed, 3369 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
new file mode 100644
index 0000000000..1a2a9000d4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/index.html
@@ -0,0 +1,401 @@
+<!--
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+-->
+
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>Parallel Shader Compile test</title>
+
+ <style>
+ body {
+ margin: 0;
+ }
+ #log {
+ margin: 16px;
+ }
+ @keyframes move {
+ 0% { left: 0%; }
+ 50% { left: calc(100% - 64px); }
+ 100% { left: 0%; }
+ }
+ #block {
+ position: relative;
+ bottom: 0%;
+ left: 0%;
+ width: 32px;
+ height: 32px;
+ background-color: #07f;
+
+ animation-name: move;
+ animation-duration: 2000ms;
+ animation-iteration-count: infinite;
+ }
+ .container {
+ display: flex;
+ flex-wrap: wrap;
+ }
+ .button {
+ width: 260px
+ }
+ </style>
+</head>
+<body>
+ <pre id='log'></pre>
+
+ <!-- The smoothness of the block's moving indicates whether the main thread is too busy. -->
+ <div id='block'></div>
+
+ <script>
+ var testGroup;
+
+ window.addEventListener('error', function (err) {
+ var logElement = document.getElementById('log');
+ logElement.textContent += ' \n';
+ logElement.textContent += err.error.stack.replace(
+ new RegExp(window.location.href, 'g'), '/') + '\n';
+ });
+
+ function setupGLContextSerial(testRun) {
+ var infoElement = testRun.logElement;
+
+ testRun.gl = document.createElement('canvas').getContext('webgl2');
+ if (testRun.gl) {
+ infoElement.textContent += 'webgl2 context created.' + '\n\n';
+ return true;
+ } else {
+ infoElement.textContent += 'webgl2 context is not supported.' + '\n\n';
+ return false;
+ }
+ }
+
+ function setupGLContextParallel(testRun) {
+ var infoElement = testRun.logElement;
+ if (setupGLContextSerial(testRun)) {
+ // Enable KHR_parallel_shader_compile extension
+ testRun.ext = testRun.gl.getExtension('KHR_parallel_shader_compile');
+ if (testRun.ext) {
+ return true;
+ } else {
+ infoElement.textContent += 'KHR_parallel_shader_compile is unavailable, you' +
+ ' may need to turn on the webgl draft extensions for your browser.'
+ }
+ }
+ return false;
+ }
+
+ function releasePrograms(testRun) {
+ var gl = testRun.gl;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ if (program.vShader) {
+ gl.deleteShader(program.vShader);
+ program.vShader = null;
+ }
+ if (program.fShader) {
+ gl.deleteShader(program.fShader);
+ program.fShader = null;
+ }
+ if (program.program) {
+ gl.deleteProgram(program.program);
+ program.program = null;
+ }
+ }
+ }
+
+ function showStatistics(testRun) {
+ var infoElement = testRun.logElement;
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += (Math.round(testRun.elapsedTotal * 100) / 100) +
+ 'ms - ' + 'all shaders compiled, and linked.\n';
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += 'done.' + '\n';
+
+ releasePrograms(testRun);
+ }
+
+ function checkShader(gl, shader, infoElement) {
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ var info = gl.getShaderInfoLog(shader);
+ infoElement.textContent += 'couldn\'t compile shader:\n';
+ infoElement.textContent += info.toString() + '\n';
+ return false;
+ }
+ return true;
+ }
+
+ function checkProgram(gl, program, infoElement) {
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ var info = gl.getProgramInfoLog(program);
+ infoElement.textContent += ' ' + '\n';
+ infoElement.textContent += 'couldn\'t link program:\n';
+ infoElement.textContent += info.toString() + '\n';
+ return false;
+ }
+ return true;
+ }
+
+ function makeAllProgramsSerial(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ // vertex shader compilation
+ var vShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vShader, program.vSource);
+ gl.compileShader(vShader);
+ checkShader(gl, vShader, infoElement);
+
+ // fragment shader compilation
+ var fShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fShader, program.fSource);
+ gl.compileShader(fShader);
+ checkShader(gl, fShader, infoElement);
+
+ // program
+ var programHandle = gl.createProgram();
+ gl.attachShader(programHandle, vShader);
+ gl.attachShader(programHandle, fShader);
+ gl.linkProgram(programHandle);
+ checkProgram(gl, programHandle, infoElement);
+ }
+ testRun.elapsedTotal = performance.now() - testRun.start;
+ showStatistics(testRun);
+ };
+
+ function makeAllProgramsParallel(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ var programs = testRun.programs;
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ var vShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vShader, program.vSource);
+ gl.compileShader(vShader);
+
+ var fShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fShader, program.fSource);
+ gl.compileShader(fShader);
+
+ programHandle = gl.createProgram();
+ gl.attachShader(programHandle, vShader);
+ gl.attachShader(programHandle, fShader);
+
+ program.vShader = vShader;
+ program.fShader = fShader;
+ program.program = programHandle;
+ program.status = "Compiling";
+ }
+
+ function checkCompletion() {
+ var ext = testRun.ext;
+
+ var allProgramsLinked = true;
+
+ for (var i = 0; i < programs.length; i++) {
+ var program = programs[i];
+ switch (program.status) {
+ case "Compiling":
+ if (gl.getShaderParameter(program.vShader, ext.COMPLETION_STATUS_KHR) &&
+ gl.getShaderParameter(program.fShader, ext.COMPLETION_STATUS_KHR))
+ {
+ checkShader(gl, program.vShader, infoElement);
+ checkShader(gl, program.fShader, infoElement);
+ gl.linkProgram(program.program);
+ program.status = "Linking";
+ }
+ allProgramsLinked = false;
+ break;
+
+ case "Linking":
+ if (gl.getProgramParameter(program.program, ext.COMPLETION_STATUS_KHR))
+ {
+ checkProgram(gl, program.program, infoElement);
+ program.status = "Done";
+ }
+ else {
+ allProgramsLinked = false;
+ }
+ break;
+
+ case "Done":
+ break;
+ }
+ }
+
+ if (allProgramsLinked) {
+ testRun.elapsedTotal = performance.now() - testRun.start;
+ showStatistics(testRun);
+ }
+ else {
+ requestAnimationFrame(checkCompletion);
+ }
+ }
+ requestAnimationFrame(checkCompletion);
+ }
+
+ function parsePrograms(testRun) {
+ var gl = testRun.gl;
+ var infoElement = testRun.logElement;
+
+ // Parse programs from the cached text, formatted as:
+ // __BEGINPROGRAM__
+ // __VERTEXSHADER__
+ // shader source line
+ // ...
+ // __FRAGMENTSHADER__
+ // shader source line
+ // ...
+ // __ENDPROGRAM__
+ //
+ // __BEGINPROGRAM__
+ // ...
+ var arrayOfLines = testRun.test.shaderCache.match(/[^\r\n]+/g);
+ var programs = [];
+ var currentProgram = {};
+ var currentShader;
+ var shaderSourceLine = false;
+ for (var ii = 0; ii < arrayOfLines.length; ii++) {
+ var cur = arrayOfLines[ii];
+ // Use random numbers to fool the program cache mechanism.
+ if (cur.indexOf('PROGRAM_CACHE_BREAKER_RANDOM') != -1) {
+ cur = cur.replace('PROGRAM_CACHE_BREAKER_RANDOM', Math.random())
+ }
+
+ if (cur == '__VERTEXSHADER__') {
+ currentShader = [];
+ shaderSourceLine = true;
+ } else if (cur == '__FRAGMENTSHADER__') {
+ currentProgram.vSource = currentShader.join('\n');
+
+ currentShader = [];
+ shaderSourceLine = true;
+ } else if (cur == '__ENDPROGRAM__') {
+ currentProgram.fSource = currentShader.join('\n');
+ programs.push(currentProgram);
+
+ currentProgram = {};
+ currentShader = [];
+ shaderSourceLine = false;
+ } else if (shaderSourceLine) {
+ currentShader.push(cur);
+ }
+ }
+
+ infoElement.textContent += programs.length + ' programs found.' + '\n';
+ infoElement.textContent += 'starting compilations ...' + '\n';
+
+ testRun.start = performance.now();
+
+ testRun.programs = programs;
+
+ testRun.makeAllPrograms(testRun);
+ };
+
+
+ function runTest(index, isParallel) {
+ var testRun = {};
+ var test = testGroup[index];
+ testRun.test = test;
+ testRun.name = test.name + (isParallel ? "_parallel" : "_serial");
+ testRun.logElement = document.getElementById(testRun.name);
+ testRun.logElement.textContent = '';
+
+ testRun.setupGLContext =
+ (isParallel ? setupGLContextParallel : setupGLContextSerial);
+
+ testRun.makeAllPrograms =
+ (isParallel ? makeAllProgramsParallel : makeAllProgramsSerial);
+
+ if (!testRun.setupGLContext(testRun)) {
+ return;
+ }
+
+ if (test.shaderCache === undefined) {
+ // load shader cache
+ var xhr = new XMLHttpRequest();
+ xhr.addEventListener('load', function() {
+ test.shaderCache = xhr.responseText;
+
+ requestAnimationFrame(function() {
+ parsePrograms(testRun);
+ });
+ });
+ xhr.open('GET', test.location);
+ xhr.send();
+ } else {
+ parsePrograms(testRun);
+ }
+ }
+
+ function createElement(element, attribute, inner) {
+ if (element === undefined) {
+ return false;
+ }
+ if (inner === undefined) {
+ inner = [];
+ }
+ var el = document.createElement(element);
+ if (typeof(attribute) === 'object') {
+ for (var key in attribute) {
+ el.setAttribute(key, attribute[key]);
+ }
+ }
+ if (!Array.isArray(inner)) {
+ inner = [inner];
+ }
+ for (var k = 0; k < inner.length; k++) {
+ if (inner[k].tagName) {
+ el.appendChild(inner[k]);
+ } else {
+ el.appendChild(document.createTextNode(inner[k]));
+ }
+ }
+ return el;
+ }
+
+ var container = createElement("div", {"class": "container"});
+ document.body.appendChild(container);
+
+ testGroup = [{
+ 'location': './shaders/aquarium/shader-cache.txt',
+ 'name': 'aquarium'
+ },
+ ];
+
+ testGroup.forEach((test, index) => {
+
+ function createTestView(test, index, isParallel) {
+
+ testName = test.name + (isParallel ? "_parallel" : "_serial");
+
+ var tButton = createElement(
+ 'button',
+ {'class': 'button', 'onclick': 'runTest(' + index + ', ' + isParallel + ')'},
+ testName
+ );
+
+ var tPrex = createElement("pre");
+ var tPre = createElement("textarea", { "id": testName, "rows": 10, "cols": 30});
+ var tDivContainer = createElement(
+ "div",
+ {"id": " " + testName + "_container"},
+ [tButton, tPrex, tPre]
+ );
+ container.appendChild(tDivContainer);
+ }
+
+ createTestView(test, index, false);
+ createTestView(test, index, true);
+ });
+
+ </script>
+</body>
diff --git a/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/README b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/README
new file mode 100644
index 0000000000..3dff676045
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/README
@@ -0,0 +1,35 @@
+1. Pulled from http://webglsamples.org/aquarium/aquarium.html, the license of which is:
+
+<!--
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<!DOCTYPE html>
+
+2. Inserted a few redundant shader code lines to bypass program cache.
diff --git a/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/shader-cache.txt b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/shader-cache.txt
new file mode 100644
index 0000000000..c3ce8cf6a3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/performance/parallel_shader_compile/shaders/aquarium/shader-cache.txt
@@ -0,0 +1,2747 @@
+<!--
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+
+
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+attribute vec4 position;
+varying vec4 v_position;
+void main() {
+ v_position = position;
+ gl_Position = position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform samplerCube skybox;
+uniform mat4 viewDirectionProjectionInverse;
+varying vec4 v_position;
+void main() {
+ vec4 t = viewDirectionProjectionInverse * v_position;
+ gl_FragColor = textureCube(
+ skybox,
+ normalize(t.xyz));
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+attribute vec4 position;
+attribute vec2 texCoord;
+varying vec2 v_texCoord;
+uniform mat4 worldViewProjection;
+void main() {
+ v_texCoord = texCoord;
+ gl_Position = (worldViewProjection * position);
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+
+varying vec2 v_texCoord;
+uniform vec4 colorMult;
+uniform sampler2D colorMap;
+void main() {
+ gl_FragColor = texture2D(colorMap, v_texCoord) * colorMult;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform vec3 worldVelocity;
+uniform vec3 worldAcceleration;
+uniform float timeRange;
+uniform float time;
+uniform float timeOffset;
+uniform float frameDuration;
+uniform float numFrames;
+
+// Incoming vertex attributes
+attribute vec4 uvLifeTimeFrameStart; // uv, lifeTime, frameStart
+attribute vec4 positionStartTime; // position.xyz, startTime
+attribute vec4 velocityStartSize; // velocity.xyz, startSize
+attribute vec4 accelerationEndSize; // acceleration.xyz, endSize
+attribute vec4 spinStartSpinSpeed; // spinStart.x, spinSpeed.y
+attribute vec4 orientation; // orientation quaternion
+attribute vec4 colorMult; // multiplies color and ramp textures
+
+// Outgoing variables to fragment shader
+varying vec2 outputTexcoord;
+varying float outputPercentLife;
+varying vec4 outputColorMult;
+
+void main() {
+ vec2 uv = uvLifeTimeFrameStart.xy;
+ float lifeTime = uvLifeTimeFrameStart.z;
+ float frameStart = uvLifeTimeFrameStart.w;
+ vec3 position = positionStartTime.xyz;
+ float startTime = positionStartTime.w;
+ vec3 velocity = (world * vec4(velocityStartSize.xyz,
+ 0.)).xyz + worldVelocity;
+ float startSize = velocityStartSize.w;
+ vec3 acceleration = (world * vec4(accelerationEndSize.xyz,
+ 0)).xyz + worldAcceleration;
+ float endSize = accelerationEndSize.w;
+ float spinStart = spinStartSpinSpeed.x;
+ float spinSpeed = spinStartSpinSpeed.y;
+
+ float localTime = mod((time - timeOffset - startTime), timeRange);
+ float percentLife = localTime / lifeTime;
+
+ float frame = mod(floor(localTime / frameDuration + frameStart),
+ numFrames);
+ float uOffset = frame / numFrames;
+ float u = uOffset + (uv.x + 0.5) * (1. / numFrames);
+
+ outputTexcoord = vec2(u, uv.y + 0.5);
+ outputColorMult = colorMult;
+
+ float size = mix(startSize, endSize, percentLife);
+ size = (percentLife < 0. || percentLife > 1.) ? 0. : size;
+ float s = sin(spinStart + spinSpeed * localTime);
+ float c = cos(spinStart + spinSpeed * localTime);
+
+ vec4 rotatedPoint = vec4((uv.x * c + uv.y * s) * size, 0.,
+ (uv.x * s - uv.y * c) * size, 1.);
+ vec3 center = velocity * localTime +
+ acceleration * localTime * localTime +
+ position;
+
+ vec4 q2 = orientation + orientation;
+ vec4 qx = orientation.xxxw * q2.xyzx;
+ vec4 qy = orientation.xyyw * q2.xyzy;
+ vec4 qz = orientation.xxzw * q2.xxzz;
+
+ mat4 localMatrix = mat4(
+ (1.0 - qy.y) - qz.z,
+ qx.y + qz.w,
+ qx.z - qy.w,
+ 0,
+
+ qx.y - qz.w,
+ (1.0 - qx.x) - qz.z,
+ qy.z + qx.w,
+ 0,
+
+ qx.z + qy.w,
+ qy.z - qx.w,
+ (1.0 - qx.x) - qy.y,
+ 0,
+
+ center.x, center.y, center.z, 1);
+ rotatedPoint = localMatrix * rotatedPoint;
+ outputPercentLife = percentLife;
+ gl_Position = worldViewProjection * rotatedPoint;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__FRAGMENTSHADER__
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D rampSampler;
+uniform sampler2D colorSampler;
+
+// Incoming variables from vertex shader
+varying vec2 outputTexcoord;
+varying float outputPercentLife;
+varying vec4 outputColorMult;
+
+void main() {
+ vec4 colorMult = texture2D(rampSampler,
+ vec2(outputPercentLife, 0.5)) *
+ outputColorMult;
+ gl_FragColor = texture2D(colorSampler, outputTexcoord) * colorMult;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+uniform mat4 viewProjection;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform vec3 worldVelocity;
+uniform vec3 worldAcceleration;
+uniform float timeRange;
+uniform float time;
+uniform float timeOffset;
+uniform float frameDuration;
+uniform float numFrames;
+
+// Incoming vertex attributes
+attribute vec4 uvLifeTimeFrameStart; // uv, lifeTime, frameStart
+attribute vec4 positionStartTime; // position.xyz, startTime
+attribute vec4 velocityStartSize; // velocity.xyz, startSize
+attribute vec4 accelerationEndSize; // acceleration.xyz, endSize
+attribute vec4 spinStartSpinSpeed; // spinStart.x, spinSpeed.y
+attribute vec4 colorMult; // multiplies color and ramp textures
+
+// Outgoing variables to fragment shader
+varying vec2 outputTexcoord;
+varying float outputPercentLife;
+varying vec4 outputColorMult;
+
+void main() {
+ vec2 uv = uvLifeTimeFrameStart.xy;
+ float lifeTime = uvLifeTimeFrameStart.z;
+ float frameStart = uvLifeTimeFrameStart.w;
+ vec3 position = positionStartTime.xyz;
+ float startTime = positionStartTime.w;
+ vec3 velocity = (world * vec4(velocityStartSize.xyz,
+ 0.)).xyz + worldVelocity;
+ float startSize = velocityStartSize.w;
+ vec3 acceleration = (world * vec4(accelerationEndSize.xyz,
+ 0)).xyz + worldAcceleration;
+ float endSize = accelerationEndSize.w;
+ float spinStart = spinStartSpinSpeed.x;
+ float spinSpeed = spinStartSpinSpeed.y;
+
+ float localTime = mod((time - timeOffset - startTime), timeRange);
+ float percentLife = localTime / lifeTime;
+
+ float frame = mod(floor(localTime / frameDuration + frameStart),
+ numFrames);
+ float uOffset = frame / numFrames;
+ float u = uOffset + (uv.x + 0.5) * (1. / numFrames);
+
+ outputTexcoord = vec2(u, uv.y + 0.5);
+ outputColorMult = colorMult;
+
+ vec3 basisX = viewInverse[0].xyz;
+ vec3 basisZ = viewInverse[1].xyz;
+
+ float size = mix(startSize, endSize, percentLife);
+ size = (percentLife < 0. || percentLife > 1.) ? 0. : size;
+ float s = sin(spinStart + spinSpeed * localTime);
+ float c = cos(spinStart + spinSpeed * localTime);
+
+ vec2 rotatedPoint = vec2(uv.x * c + uv.y * s,
+ -uv.x * s + uv.y * c);
+ vec3 localPosition = vec3(basisX * rotatedPoint.x +
+ basisZ * rotatedPoint.y) * size +
+ velocity * localTime +
+ acceleration * localTime * localTime +
+ position;
+
+ outputPercentLife = percentLife;
+ gl_Position = viewProjection * vec4(localPosition + world[3].xyz, 1.);
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__FRAGMENTSHADER__
+#ifdef GL_ES
+precision mediump float;
+#endif
+uniform sampler2D rampSampler;
+uniform sampler2D colorSampler;
+
+// Incoming variables from vertex shader
+varying vec2 outputTexcoord;
+varying float outputPercentLife;
+varying vec4 outputColorMult;
+
+void main() {
+ vec4 colorMult = texture2D(rampSampler,
+ vec2(outputPercentLife, 0.5)) *
+ outputColorMult;
+ gl_FragColor = texture2D(colorSampler, outputTexcoord) * colorMult;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec3 tangentNormal = normalSpec.xyz - // #normalMap
+ vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec3 tangentNormal = normalSpec.xyz - // #normalMap
+ vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform sampler2D reflectionMap; // #reflection
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 reflection = texture2D(reflectionMap, v_texCoord.xy); // #reflection
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = textureCube(skybox, -reflect(surfaceToView, normal)); // #reflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform sampler2D reflectionMap; // #reflection
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 reflection = texture2D(reflectionMap, v_texCoord.xy); // #reflection
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = textureCube(skybox, -reflect(surfaceToView, normal)); // #reflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 reflection = vec4(0,0,0,0); // #noReflection
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = vec4(0.5,0.5,1,1); // #noReflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 reflection = vec4(0,0,0,0); // #noReflection
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = vec4(0.5,0.5,1,1); // #noReflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec4 reflection = vec4(0,0,0,0); // #noReflection
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = vec4(0.5,0.5,1,1); // #noReflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;
+uniform samplerCube skybox; // #reflecton
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec4 reflection = vec4(0,0,0,0); // #noReflection
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec4 skyColor = vec4(0.5,0.5,1,1); // #noReflection
+
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(mix(
+ skyColor,
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a),
+ 1.0 - reflection.r).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ tangentNormal = normalize(tangentNormal + vec3(0, 0, 2)); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ tangentNormal = normalize(tangentNormal + vec3(0, 0, 2)); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 viewProjection;
+uniform vec3 worldPosition;
+uniform vec3 nextPosition;
+uniform float scale;
+uniform float time;
+uniform float fishLength;
+uniform float fishWaveLength;
+uniform float fishBendAmount;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent; // #normalMap
+attribute vec3 binormal; // #normalMap
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 vz = normalize(worldPosition - nextPosition);
+ vec3 vx = normalize(cross(vec3(0,1,0), vz));
+ vec3 vy = cross(vz, vx);
+ mat4 orientMat = mat4(
+ vec4(vx, 0),
+ vec4(vy, 0),
+ vec4(vz, 0),
+ vec4(worldPosition, 1));
+ mat4 scaleMat = mat4(
+ vec4(scale, 0, 0, 0),
+ vec4(0, scale, 0, 0),
+ vec4(0, 0, scale, 0),
+ vec4(0, 0, 0, 1));
+ mat4 world = orientMat * scaleMat;
+ mat4 worldViewProjection = viewProjection * world;
+ mat4 worldInverseTranspose = world;
+
+ v_texCoord = texCoord;
+ // NOTE:If you change this you need to change the laser code to match!
+ float mult = position.z > 0.0 ?
+ (position.z / fishLength) :
+ (-position.z / fishLength * 2.0);
+ float s = sin(time + mult * fishWaveLength);
+ float a = sign(s);
+ float offset = pow(mult, 2.0) * s * fishBendAmount;
+ v_position = (
+ worldViewProjection *
+ (position +
+ vec4(offset, 0, 0, 0)));
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec3 normal = normalize(v_normal); // #noNormalMap
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4(
+ (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor * normalSpec.a)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 reflection = texture2D(reflectionMap, v_texCoord.xy);
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+// tangentNormal = normalize(tangentNormal + vec3(0,0,refractionFudge));
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec4 skyColor = textureCube(skybox, -reflect(surfaceToView, normal));
+ float fudgeAmount = 1.1;
+ vec3 fudge = skyColor.rgb * vec3(fudgeAmount, fudgeAmount, fudgeAmount);
+ float bright = min(1.0, fudge.r * fudge.g * fudge.b);
+ vec4 reflectColor =
+ mix(vec4(skyColor.rgb, bright),
+ diffuseColor,
+ (1.0 - reflection.r));
+ float r = abs(dot(surfaceToView, normal));
+ gl_FragColor = vec4(mix(
+ skyColor,
+ reflectColor,
+ ((r + 0.3) * (reflection.r))).rgb, 1.0 - r);
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec4 reflection = texture2D(reflectionMap, v_texCoord.xy);
+// tangentNormal = normalize(tangentNormal + vec3(0,0,refractionFudge));
+ vec3 normal = normalize(v_normal); // #noNormalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec4 skyColor = textureCube(skybox, -reflect(surfaceToView, normal));
+ float fudgeAmount = 1.1;
+ vec3 fudge = skyColor.rgb * vec3(fudgeAmount, fudgeAmount, fudgeAmount);
+ float bright = min(1.0, fudge.r * fudge.g * fudge.b);
+ vec4 reflectColor =
+ mix(vec4(skyColor.rgb, bright),
+ diffuseColor,
+ (1.0 - reflection.r));
+ float r = abs(dot(surfaceToView, normal));
+ gl_FragColor = vec4(mix(
+ skyColor,
+ reflectColor,
+ ((r + 0.3) * (reflection.r))).rgb, 1.0 - r);
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec3 normal = normalize(v_normal);
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4((
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ vec3 normal = normalize(v_normal);
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4((
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+uniform float refractionFudge;
+uniform float eta;
+uniform float tankColorFudge;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord) +
+ vec4(tankColorFudge, tankColorFudge, tankColorFudge, 1);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 refraction = texture2D(reflectionMap, v_texCoord.xy);
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ tangentNormal = normalize(tangentNormal + vec3(0,0,refractionFudge)); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec3 refractionVec = refract(surfaceToView, normal, eta);
+
+ vec4 skyColor = textureCube(skybox, refractionVec);
+
+// vec4 bumpSkyColor = textureCube(skybox, refractionVec);
+// vec4 nonBumpSkyColor = textureCube(
+// skybox,
+// refract(surfaceToView, normalize(v_normal), eta));
+// vec4 skyColor = mix(nonBumpSkyColor, bumpSkyColor, normalSpec.a);
+ vec4 outColor = vec4(
+ mix(skyColor * diffuseColor, diffuseColor, refraction.r).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap; // #normalMap
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+uniform float refractionFudge;
+uniform float eta;
+uniform float tankColorFudge;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord) +
+ vec4(tankColorFudge, tankColorFudge, tankColorFudge, 1);
+ mat3 tangentToWorld = mat3(v_tangent, // #normalMap
+ v_binormal, // #normalMap
+ v_normal); // #normalMap
+ vec4 normalSpec = texture2D(normalMap, v_texCoord.xy); // #normalMap
+ vec4 refraction = texture2D(reflectionMap, v_texCoord.xy);
+ vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5); // #normalMap
+ tangentNormal = normalize(tangentNormal + vec3(0,0,refractionFudge)); // #normalMap
+ vec3 normal = (tangentToWorld * tangentNormal); // #normalMap
+ normal = normalize(normal); // #normalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec3 refractionVec = refract(surfaceToView, normal, eta);
+
+ vec4 skyColor = textureCube(skybox, refractionVec);
+
+// vec4 bumpSkyColor = textureCube(skybox, refractionVec);
+// vec4 nonBumpSkyColor = textureCube(
+// skybox,
+// refract(surfaceToView, normalize(v_normal), eta));
+// vec4 skyColor = mix(nonBumpSkyColor, bumpSkyColor, normalSpec.a);
+ vec4 outColor = vec4(
+ mix(skyColor * diffuseColor, diffuseColor, refraction.r).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+uniform float refractionFudge;
+uniform float eta;
+uniform float tankColorFudge;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord) +
+ vec4(tankColorFudge, tankColorFudge, tankColorFudge, 1);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec4 refraction = texture2D(reflectionMap, v_texCoord.xy);
+ vec3 normal = normalize(v_normal); // #noNormalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec3 refractionVec = refract(surfaceToView, normal, eta);
+
+ vec4 skyColor = textureCube(skybox, refractionVec);
+
+// vec4 bumpSkyColor = textureCube(skybox, refractionVec);
+// vec4 nonBumpSkyColor = textureCube(
+// skybox,
+// refract(surfaceToView, normalize(v_normal), eta));
+// vec4 skyColor = mix(nonBumpSkyColor, bumpSkyColor, normalSpec.a);
+ vec4 outColor = vec4(
+ mix(skyColor * diffuseColor, diffuseColor, refraction.r).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 worldViewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 world;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+attribute vec3 tangent;
+attribute vec3 binormal;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent; // #normalMap
+varying vec3 v_binormal; // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ v_texCoord = texCoord;
+ v_position = (worldViewProjection * position);
+ v_normal = (worldInverseTranspose * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ v_binormal = (worldInverseTranspose * vec4(binormal, 0)).xyz; // #normalMap
+ v_tangent = (worldInverseTranspose * vec4(tangent, 0)).xyz; // #normalMap
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D reflectionMap;
+uniform samplerCube skybox;
+uniform float shininess;
+uniform float specularFactor;
+uniform float refractionFudge;
+uniform float eta;
+uniform float tankColorFudge;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord) +
+ vec4(tankColorFudge, tankColorFudge, tankColorFudge, 1);
+ vec4 normalSpec = vec4(0,0,0,0); // #noNormalMap
+ vec4 refraction = texture2D(reflectionMap, v_texCoord.xy);
+ vec3 normal = normalize(v_normal); // #noNormalMap
+
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+
+ vec3 refractionVec = refract(surfaceToView, normal, eta);
+
+ vec4 skyColor = textureCube(skybox, refractionVec);
+
+// vec4 bumpSkyColor = textureCube(skybox, refractionVec);
+// vec4 nonBumpSkyColor = textureCube(
+// skybox,
+// refract(surfaceToView, normalize(v_normal), eta));
+// vec4 skyColor = mix(nonBumpSkyColor, bumpSkyColor, normalSpec.a);
+ vec4 outColor = vec4(
+ mix(skyColor * diffuseColor, diffuseColor, refraction.r).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 world;
+uniform mat4 viewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+uniform float time;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 toCamera = normalize(viewInverse[3].xyz - world[3].xyz);
+ vec3 yAxis = vec3(0, 1, 0);
+ vec3 xAxis = cross(yAxis, toCamera);
+ vec3 zAxis = cross(xAxis, yAxis);
+
+ mat4 newWorld = mat4(
+ vec4(xAxis, 0),
+ vec4(yAxis, 0),
+ vec4(xAxis, 0),
+ world[3]);
+
+ v_texCoord = texCoord;
+ v_position = position + vec4(
+ sin(time * 0.5) * pow(position.y * 0.07, 2.0) * 1.0,
+ -4, // TODO(gman): remove this hack
+ 0,
+ 0);
+ v_position = (viewProjection * newWorld) * v_position;
+ v_normal = (newWorld * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+uniform float fogPower;
+uniform float fogMult;
+uniform float fogOffset;
+uniform vec4 fogColor;
+
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ if (diffuseColor.a < 0.3) {
+ discard;
+ }
+ vec3 normal = normalize(v_normal);
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4((
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor)).rgb,
+ diffuseColor.a);
+ outColor = mix(outColor, vec4(fogColor.rgb, diffuseColor.a),
+ clamp(pow((v_position.z / v_position.w), fogPower) * fogMult - fogOffset,0.0,1.0));
+
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
+__BEGINPROGRAM__
+__VERTEXSHADER__
+
+uniform mat4 world;
+uniform mat4 viewProjection;
+uniform vec3 lightWorldPos;
+uniform mat4 viewInverse;
+uniform mat4 worldInverseTranspose;
+uniform float time;
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+void main() {
+ vec3 toCamera = normalize(viewInverse[3].xyz - world[3].xyz);
+ vec3 yAxis = vec3(0, 1, 0);
+ vec3 xAxis = cross(yAxis, toCamera);
+ vec3 zAxis = cross(xAxis, yAxis);
+
+ mat4 newWorld = mat4(
+ vec4(xAxis, 0),
+ vec4(yAxis, 0),
+ vec4(xAxis, 0),
+ world[3]);
+
+ v_texCoord = texCoord;
+ v_position = position + vec4(
+ sin(time * 0.5) * pow(position.y * 0.07, 2.0) * 1.0,
+ -4, // TODO(gman): remove this hack
+ 0,
+ 0);
+ v_position = (viewProjection * newWorld) * v_position;
+ v_normal = (newWorld * vec4(normal, 0)).xyz;
+ v_surfaceToLight = lightWorldPos - (world * position).xyz;
+ v_surfaceToView = (viewInverse[3] - (world * position)).xyz;
+ gl_Position = v_position;
+ gl_Position.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+
+__FRAGMENTSHADER__
+
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+void main() {
+ vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+ if (diffuseColor.a < 0.3) {
+ discard;
+ }
+ vec3 normal = normalize(v_normal);
+ vec3 surfaceToLight = normalize(v_surfaceToLight);
+ vec3 surfaceToView = normalize(v_surfaceToView);
+ vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+ vec4 litR = lit(dot(normal, surfaceToLight),
+ dot(normal, halfVector), shininess);
+ vec4 outColor = vec4((
+ lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+ specular * litR.z * specularFactor)).rgb,
+ diffuseColor.a);
+ // #fogCode
+ gl_FragColor = outColor;
+ gl_FragColor.x += PROGRAM_CACHE_BREAKER_RANDOM;
+}
+
+
+__ENDPROGRAM__
diff --git a/dom/canvas/test/webgl-conf/checkout/performance/webgl_webcodecs_video_frame/index.html b/dom/canvas/test/webgl-conf/checkout/performance/webgl_webcodecs_video_frame/index.html
new file mode 100644
index 0000000000..97eb95a174
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/performance/webgl_webcodecs_video_frame/index.html
@@ -0,0 +1,186 @@
+<!-- This was created from the demo of webcodecs-blogpost-demo.glitch.me, and added the webgl support for test only purpose. -->
+
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="origin-trial"
+ content="AoSY6Q4OOuuZVXTqOwJlfk4n77EL0esumtLRHj+9V97JoFfLq4AKsWlza8A8HmxTx1PU7SSzpjWK6F62bwWLPQYAAAB3eyJvcmlnaW4iOiJodHRwczovL3dlYmNvZGVjcy1ibG9ncG9zdC1kZW1vLmdsaXRjaC5tZTo0NDMiLCJmZWF0dXJlIjoiV2ViQ29kZWNzIiwiZXhwaXJ5IjoxNjA1NDc0OTQ4LCJpc1N1YmRvbWFpbiI6dHJ1ZX0=">
+ <title>WebCodecs API demo: Encoding and Decoding</title>
+ <style>
+ canvas {
+ padding: 10px;
+ background: gold;
+ }
+
+ button {
+ background-color: #555555;
+ border: none;
+ color: white;
+ padding: 15px 32px;
+ width: 150px;
+ text-align: center;
+ display: block;
+ font-size: 16px;
+ }
+ </style>
+ <script src="../../../../extensions/proposals/WEBGL_webcodecs_video_frame/webgl_webcodecs_video_frame.js"></script>
+</head>
+
+<body>
+ <canvas id="src" width="640" height="480"></canvas>
+ <button onclick="playPause()">Pause</button>
+ <canvas id="dst" width="640" height="480"></canvas>
+ <script>
+ let codec_string = "vp8";
+ let keep_going = true;
+
+ function playPause() {
+ keep_going = !keep_going;
+ let btn = document.querySelector("button");
+ if (keep_going) {
+ btn.innerText = "Pause";
+ } else {
+ btn.innerText = "Play";
+ }
+ }
+
+ async function startDrawing() {
+ let cnv = document.getElementById("src");
+ var ctx = cnv.getContext('2d', { alpha: false });
+
+ ctx.fillStyle = "white";
+ let width = cnv.width;
+ let height = cnv.height;
+ let cx = width / 2;
+ let cy = height / 2;
+ let r = Math.min(width, height) / 5;
+ let drawOneFrame = function (time) {
+ let angle = Math.PI * 2 * (time / 5000);
+ let scale = 1 + 0.3 * Math.sin(Math.PI * 2 * (time / 7000));
+ ctx.save();
+ ctx.fillRect(0, 0, width, height);
+
+ ctx.translate(cx, cy);
+ ctx.rotate(angle);
+ ctx.scale(scale, scale);
+
+ ctx.font = '30px Verdana';
+ ctx.fillStyle = 'black';
+ const text = "๐Ÿ˜Š๐Ÿ“น๐Ÿ“ทHello WEBGL_webcodecs_video_frame๐ŸŽฅ๐ŸŽž๏ธ๐Ÿ˜Š";
+ const size = ctx.measureText(text).width;
+ ctx.fillText(text, -size / 2, 0);
+ ctx.restore();
+ window.requestAnimationFrame(drawOneFrame);
+ }
+ window.requestAnimationFrame(drawOneFrame);
+ }
+
+ function captureAndEncode(processChunk) {
+ let cnv = document.getElementById("src");
+ let fps = 30;
+ let pending_outputs = 0;
+ let frame_counter = 0;
+ let stream = cnv.captureStream(fps);
+ let processor = new MediaStreamTrackProcessor(stream.getVideoTracks()[0]);
+
+ const init = {
+ output: (chunk) => {
+ pending_outputs--;
+ processChunk(chunk);
+ },
+ error: (e) => {
+ console.log(e.message);
+ vtr.stop();
+ }
+ };
+
+ const config = {
+ codec: codec_string,
+ width: cnv.width,
+ height: cnv.height,
+ bitrate: 10e6,
+ framerate: fps,
+ };
+
+ let encoder = new VideoEncoder(init);
+ encoder.configure(config);
+
+ const frame_reader = processor.readable.getReader();
+ frame_reader.read().then(function processFrame({done, value}) {
+ if (done)
+ return;
+
+ if (pending_outputs > 30) {
+ // Too many frames in flight, encoder is overwhelmed
+ // let's drop this frame.
+ value.close();
+ frame_reader.read().then(processFrame);
+ return;
+ }
+
+ if(!keep_going) {
+ value.close();
+ frame_reader.read().then(processFrame);
+ return;
+ }
+
+ frame_counter++;
+ pending_outputs++;
+ const insert_keyframe = (frame_counter % 150) == 0;
+ encoder.encode(value, { keyFrame: insert_keyframe });
+
+ frame_reader.read().then(processFrame);
+ });
+ }
+
+
+ function startDecodingAndRendering(cnv, handleFrame) {
+
+ const init = {
+ output: handleFrame,
+ error: (e) => {
+ console.log(e.message);
+ }
+ };
+
+ const config = {
+ codec: codec_string,
+ codedWidth: cnv.width,
+ codedHeight: cnv.height
+ };
+
+ let decoder = new VideoDecoder(init);
+ decoder.configure(config);
+ return decoder;
+ }
+
+
+ function main() {
+ if (!("VideoEncoder" in window)) {
+ document.body.innerHTML = "<h1>WebCodecs API is not supported.</h1>";
+ return;
+ }
+
+ let cnv = document.getElementById("dst");
+ let handleFrame = requestWebGLVideoFrameHandler(cnv);
+ if (handleFrame === null) {
+ document.body.innerHTML =
+ "<h1>Unable to request WebGL to render video frames.</h1>";
+ return;
+ }
+
+ startDrawing();
+ let decoder = startDecodingAndRendering(cnv, handleFrame);
+ captureAndEncode((chunk) => {
+ decoder.decode(chunk);
+ });
+ }
+
+ document.body.onload = main;
+ </script>
+
+</body>
+
+</html> \ No newline at end of file