From 839e261727a1d9122683d51b9599a960fb1ea1e7 Mon Sep 17 00:00:00 2001 From: Rezmason Date: Fri, 25 Aug 2023 09:11:24 -0700 Subject: [PATCH] Replacing the old project with the new project, using the "unraveled" WebGL calls --- js/bloomPass.js | 128 - js/main.js | 365 +- js/palettePass.js | 64 - js/rainPass.js | 256 -- js/unraveled.js | 809 ++++ js/utils.js | 128 - lib/regl.js | 10527 ------------------------------------------- lib/webgl-debug.js | 1195 ----- 8 files changed, 861 insertions(+), 12611 deletions(-) delete mode 100644 js/bloomPass.js delete mode 100644 js/palettePass.js delete mode 100644 js/rainPass.js create mode 100644 js/unraveled.js delete mode 100644 js/utils.js delete mode 100644 lib/regl.js delete mode 100644 lib/webgl-debug.js diff --git a/js/bloomPass.js b/js/bloomPass.js deleted file mode 100644 index 427a04b..0000000 --- a/js/bloomPass.js +++ /dev/null @@ -1,128 +0,0 @@ -import { loadText, makePassFBO, makePass } from "./utils.js"; - -const pyramidHeight = 5; - -const makePyramid = (regl, height, halfFloat) => - Array(height) - .fill() - .map((_) => makePassFBO(regl, halfFloat)); - -const resizePyramid = (pyramid, vw, vh, scale) => - pyramid.forEach((fbo, index) => fbo.resize(Math.floor((vw * scale) / 2 ** index), Math.floor((vh * scale) / 2 ** index))); - -export default ({ regl }, inputs) => { - const bloomStrength = 0.7; // The intensity of the bloom - const bloomSize = 0.4; // The amount the bloom calculation is scaled - const highPassThreshold = 0.1; // The minimum brightness that is still blurred - - const highPassPyramid = makePyramid(regl, pyramidHeight); - const hBlurPyramid = makePyramid(regl, pyramidHeight); - const vBlurPyramid = makePyramid(regl, pyramidHeight); - const output = makePassFBO(regl); - - const highPass = regl({ - frag: ` - precision mediump float; - - uniform sampler2D tex; - uniform float highPassThreshold; - - varying vec2 vUV; - - void main() { - vec4 color = texture2D(tex, vUV); - if (color.r < highPassThreshold) color.r = 0.0; - if (color.g < highPassThreshold) color.g = 0.0; - if (color.b < highPassThreshold) color.b = 0.0; - gl_FragColor = color; - } - `, - uniforms: { - highPassThreshold, - tex: regl.prop("tex"), - }, - framebuffer: regl.prop("fbo"), - }); - - const blur = regl({ - frag: ` - precision mediump float; - - uniform float width, height; - uniform sampler2D tex; - uniform vec2 direction; - - varying vec2 vUV; - - void main() { - vec2 size = width > height ? vec2(width / height, 1.) : vec2(1., height / width); - gl_FragColor = - texture2D(tex, vUV) * 0.442 + - ( - texture2D(tex, vUV + direction / max(width, height) * size) + - texture2D(tex, vUV - direction / max(width, height) * size) - ) * 0.279; - } - `, - uniforms: { - tex: regl.prop("tex"), - direction: regl.prop("direction"), - height: regl.context("viewportWidth"), - width: regl.context("viewportHeight"), - }, - framebuffer: regl.prop("fbo"), - }); - - // The pyramid of textures gets flattened (summed) into a final blurry "bloom" texture - const combine = regl({ - frag: ` - precision mediump float; - - uniform sampler2D pyr_0, pyr_1, pyr_2, pyr_3, pyr_4; - uniform float bloomStrength; - varying vec2 vUV; - - void main() { - vec4 total = vec4(0.); - total += texture2D(pyr_0, vUV) * 0.96549; - total += texture2D(pyr_1, vUV) * 0.92832; - total += texture2D(pyr_2, vUV) * 0.88790; - total += texture2D(pyr_3, vUV) * 0.84343; - total += texture2D(pyr_4, vUV) * 0.79370; - gl_FragColor = total * bloomStrength; - } - `, - uniforms: { - bloomStrength, - ...Object.fromEntries(vBlurPyramid.map((fbo, index) => [`pyr_${index}`, fbo])), - }, - framebuffer: output, - }); - - return makePass( - { - primary: inputs.primary, - bloom: output, - }, - null, - (w, h) => { - // The blur pyramids can be lower resolution than the screen. - resizePyramid(highPassPyramid, w, h, bloomSize); - resizePyramid(hBlurPyramid, w, h, bloomSize); - resizePyramid(vBlurPyramid, w, h, bloomSize); - output.resize(w, h); - }, - () => { - for (let i = 0; i < pyramidHeight; i++) { - const highPassFBO = highPassPyramid[i]; - const hBlurFBO = hBlurPyramid[i]; - const vBlurFBO = vBlurPyramid[i]; - highPass({ fbo: highPassFBO, tex: i === 0 ? inputs.primary : highPassPyramid[i - 1] }); - blur({ fbo: hBlurFBO, tex: highPassFBO, direction: [1, 0] }); - blur({ fbo: vBlurFBO, tex: hBlurFBO, direction: [0, 1] }); - } - - combine(); - } - ); -}; diff --git a/js/main.js b/js/main.js index 2dd8cd8..dc50d2f 100644 --- a/js/main.js +++ b/js/main.js @@ -1,15 +1,11 @@ +import { init, load, resize, draw } from "./unraveled.js"; + const canvas = document.createElement("canvas"); document.body.appendChild(canvas); document.addEventListener("touchmove", (e) => e.preventDefault(), { passive: false, }); -import { makeFullScreenQuad, makePipeline } from "./utils.js"; - -import makeRain from "./rainPass.js"; -import makeBloomPass from "./bloomPass.js"; -import makePalettePass from "./palettePass.js"; - const dimensions = { width: 1, height: 1 }; const loadJS = (src) => @@ -21,321 +17,64 @@ const loadJS = (src) => document.body.appendChild(tag); }); -const init = async () => { - await loadJS("lib/regl.js"); - await loadJS("lib/webgl-debug.js"); +const start = async () => { - const resize = () => { + const resizeViewport = () => { const devicePixelRatio = window.devicePixelRatio ?? 1; canvas.width = Math.ceil(canvas.clientWidth * devicePixelRatio * 0.75); canvas.height = Math.ceil(canvas.clientHeight * devicePixelRatio * 0.75); }; - window.onresize = resize; - if (document.fullscreenEnabled || document.webkitFullscreenEnabled) { - window.ondblclick = () => { - if (document.fullscreenElement == null) { - if (canvas.webkitRequestFullscreen != null) { - canvas.webkitRequestFullscreen(); - } else { - canvas.requestFullscreen(); - } - } else { - document.exitFullscreen(); - } - }; + window.onresize = resizeViewport; + resizeViewport(); + + const gl = canvas.getContext("webgl"); + + const image = new Image(); + image.crossOrigin = "anonymous"; + image.src = "./assets/matrixcode_msdf.png"; + await image.decode(); + + const palette = [ + [ 0, 0, 0, 255, ], + [ 7, 33, 0, 255, ], + [ 15, 63, 2, 255, ], + [ 22, 96, 5, 255, ], + [ 38, 117, 17, 255, ], + [ 53, 137, 33, 255, ], + [ 71, 160, 48, 255, ], + [ 86, 181, 63, 255, ], + [ 104, 204, 79, 255, ], + [ 119, 224, 94, 255, ], + [ 135, 247, 109, 255, ], + [ 155, 247, 132, 255, ], + [ 175, 249, 158, 255, ], + [ 175, 249, 158, 255, ], + [ 175, 249, 158, 255, ], + [ 175, 249, 158, 255, ], + ].flat(); + + init(gl); + load(gl, image, palette); + + let tick = 0; + const start = Date.now(); + + const update = () => { + tick++; + + if (dimensions.width !== canvas.width || dimensions.height !== canvas.height) { + dimensions.width = canvas.width; + dimensions.height = canvas.height; + resize(gl, dimensions.width, dimensions.height); + } + + draw(gl, tick, (Date.now() - start) / 1000); + requestAnimationFrame(update); } - resize(); + update(); - const extensions = ["OES_texture_half_float", "OES_texture_half_float_linear"]; - // These extensions are also needed, but Safari misreports that they are missing - const optionalExtensions = ["EXT_color_buffer_half_float", "WEBGL_color_buffer_float", "OES_standard_derivatives"]; - - const { makeDebugContext } = WebGLDebugUtils; - - const glConsts = { - DEPTH_TEST: 0x0B71, - BLEND: 0x0BE2, - UNPACK_ALIGNMENT: 0x0CF5, - TEXTURE_2D: 0x0DE1, - RGBA: 0x1908, - LUMINANCE: 0x1909, - NEAREST: 0x2600, - LINEAR: 0x2601, - TEXTURE_MAG_FILTER: 0x2800, - TEXTURE_MIN_FILTER: 0x2801, - TEXTURE_WRAP_S: 0x2802, - TEXTURE_WRAP_T: 0x2803, - CLAMP_TO_EDGE: 0x812F, - DEPTH_STENCIL_ATTACHMENT: 0x821A, - TEXTURE0: 0x84C0, - DEPTH_STENCIL: 0x84F9, - RGBA16F_EXT: 0x881A, - STATIC_DRAW: 0x88E4, - ACTIVE_UNIFORMS: 0x8B86, - ACTIVE_ATTRIBUTES: 0x8B89, - COLOR_ATTACHMENT0: 0x8CE0, - DEPTH_ATTACHMENT: 0x8D00, - STENCIL_ATTACHMENT: 0x8D20, - FRAMEBUFFER: 0x8D40, - RENDERBUFFER: 0x8D41, - HALF_FLOAT_OES: 0x8D61, - UNPACK_FLIP_Y_WEBGL: 0x9240, - UNPACK_PREMULTIPLY_ALPHA_WEBGL: 0x9241, - UNPACK_COLORSPACE_CONVERSION_WEBGL: 0x9243, - BROWSER_DEFAULT_WEBGL: 0x9244, - - ARRAY_BUFFER: 34962, - FRAGMENT_SHADER: 35632, - FRAGMENT_SHADER: 35632, - VERTEX_SHADER: 35633, - COMPILE_STATUS: 35713, - LINK_STATUS: 35714, - TRIANGLES: 4, - UNSIGNED_BYTE: 5121, - FLOAT: 5126, - }; - - for (let i = 1; i < 32; i++) { - glConsts[`TEXTURE${i}`] = 0x84C0 + i; - } - - const betterNames = { - [11]: "defaultFragShader", - [12]: "defaultVertShader", - [13]: "defaultProgram", - [17]: "fullscreen_geometry", - [18]: "rain_compute_doublebuffer_1_texture", [19]: "rain_compute_doublebuffer_1_framebuffer", - [20]: "rain_compute_doublebuffer_2_texture", [21]: "rain_compute_doublebuffer_2_framebuffer", - [22]: "rain_compute_shader", - [23]: "placeholder_texture", - [24]: "rain_output_texture", [25]: "rain_output_framebuffer", [26]: "rain_output_renderbuffer", - [27]: "rain_frag_shader", - [28]: "rain_vert_shader", - [29]: "rain_program", - [47]: "rain_geometry", - - [48]: "bloom_high_pass_pyr_0_texture", [49]: "bloom_high_pass_pyr_0_framebuffer", [50]: "bloom_high_pass_pyr_0_renderbuffer", - [51]: "bloom_high_pass_pyr_1_texture", [52]: "bloom_high_pass_pyr_1_framebuffer", [53]: "bloom_high_pass_pyr_1_renderbuffer", - [54]: "bloom_high_pass_pyr_2_texture", [55]: "bloom_high_pass_pyr_2_framebuffer", [56]: "bloom_high_pass_pyr_2_renderbuffer", - [57]: "bloom_high_pass_pyr_3_texture", [58]: "bloom_high_pass_pyr_3_framebuffer", [59]: "bloom_high_pass_pyr_3_renderbuffer", - [60]: "bloom_high_pass_pyr_4_texture", [61]: "bloom_high_pass_pyr_4_framebuffer", [62]: "bloom_high_pass_pyr_4_renderbuffer", - - [63]: "bloom_h_blur_pyr_0_texture", [64]: "bloom_h_blur_pyr_0_framebuffer", [65]: "bloom_h_blur_pyr_0_renderbuffer", - [66]: "bloom_h_blur_pyr_1_texture", [67]: "bloom_h_blur_pyr_1_framebuffer", [68]: "bloom_h_blur_pyr_1_renderbuffer", - [69]: "bloom_h_blur_pyr_2_texture", [70]: "bloom_h_blur_pyr_2_framebuffer", [71]: "bloom_h_blur_pyr_2_renderbuffer", - [72]: "bloom_h_blur_pyr_3_texture", [73]: "bloom_h_blur_pyr_3_framebuffer", [74]: "bloom_h_blur_pyr_3_renderbuffer", - [75]: "bloom_h_blur_pyr_4_texture", [76]: "bloom_h_blur_pyr_4_framebuffer", [77]: "bloom_h_blur_pyr_4_renderbuffer", - - [78]: "bloom_v_blur_pyr_0_texture", [79]: "bloom_v_blur_pyr_0_framebuffer", [80]: "bloom_v_blur_pyr_0_renderbuffer", - [81]: "bloom_v_blur_pyr_1_texture", [82]: "bloom_v_blur_pyr_1_framebuffer", [83]: "bloom_v_blur_pyr_1_renderbuffer", - [84]: "bloom_v_blur_pyr_2_texture", [85]: "bloom_v_blur_pyr_2_framebuffer", [86]: "bloom_v_blur_pyr_2_renderbuffer", - [87]: "bloom_v_blur_pyr_3_texture", [88]: "bloom_v_blur_pyr_3_framebuffer", [89]: "bloom_v_blur_pyr_3_renderbuffer", - [90]: "bloom_v_blur_pyr_4_texture", [91]: "bloom_v_blur_pyr_4_framebuffer", [92]: "bloom_v_blur_pyr_4_renderbuffer", - - [93]: "bloom_output_texture", [94]: "bloom_output_framebuffer", [95]: "bloom_output_renderbuffer", - [96]: "bloom_high_pass_shader", - [97]: "bloom_blur_shader", - [98]: "bloom_combine_shader", - [99]: "palette_output_texture", [100]: "palette_output_framebuffer", [101]: "palette_output_renderbuffer", - [102]: "palette_texture", - [103]: "palette_shader", - [104]: "msdf_texture", - [105]: "rain_compute_program", - [125]: "bloom_high_pass_program", - [131]: "bloom_blur_program", - [141]: "bloom_combine_program", - [155]: "palette_program", - }; - - const returnedValueNames = []; - - const glConstsByID = {}; - Object.entries(glConsts).forEach(([key, value]) => { - if (glConstsByID[value] == null) { - glConstsByID[value] = []; - } - glConstsByID[value].push(key); - }); - - const returnedValues = []; - const returnedValueUsages = []; - const commands = []; - - const log = []; - - const printCommands = (label) => { - const printedCommands = []; - for (const {name, args, retIndex} of commands) { - const printedArgs = []; - for (const [type, value] of args) { - if (value == null) { - printedArgs.push(`null`); - continue; - } - if (Array.isArray(value) || ArrayBuffer.isView(value)) { - printedArgs.push(`[${value.join(", ")}]`); - continue; - } - switch (type) { - case "string": - printedArgs.push(`\`${value}\``); - break; - case "GLenum": - printedArgs.push(`gl.${value}`); - break; - case "object": - printedArgs.push(`${value}`); - break; - case "returnedValue": - printedArgs.push(`state.${returnedValueNames[value]}`); - break; - default: - printedArgs.push(`${value}`); - break; - } - } - if (retIndex != -1 && returnedValueUsages[retIndex] > 0) { - printedCommands.push(`state.${returnedValueNames[retIndex]} = gl.${name}(${printedArgs.join(", ")});`); - } else { - printedCommands.push(`gl.${name}(${printedArgs.join(", ")});`); - } - } - log.push(`// ${label}`); - log.push(printedCommands.join("\n")); - commands.length = 0; - }; - - const rawGL = canvas.getContext("webgl"); - - const gl = new Proxy(makeDebugContext( - rawGL, - null, - (...a) => { - const name = a[0]; - const args = Array.from(a[1]); - const ret = a[2]; - for (let i = 0; i < args.length; i++) { - let value = args[i]; - let type = typeof value; - if (type === "number" && glConstsByID[value] != null) { - type = "GLenum"; - value = glConstsByID[value][0]; - } - if (returnedValues.includes(value)) { - type = "returnedValue"; - value = returnedValues.indexOf(value); - returnedValueUsages[value]++; - } - args[i] = [type, value]; - } - - let retIndex = -1; - if (typeof ret === "object" && !returnedValues.includes(ret)) { - returnedValues.push(ret); - returnedValueUsages.push(0); - retIndex = returnedValues.length - 1; - let glType = (ret[Symbol.toStringTag] ?? "object").replaceAll("WebGL", "").toLowerCase(); - let retName = glType + "_" + retIndex; - switch (name) { - case "getExtension": - retName = glType; - break; - } - switch (glType) { - case "texture": - break; - case "framebuffer": - break; - case "renderbuffer": - break; - case "program": - break; - case "shader": - if (args[0][1].toLowerCase().includes("fragment")) { - retName = "fragment_shader" + "_" + retIndex; - } else { - retName = "vertex_shader" + "_" + retIndex;; - } - break; - case "activeinfo": - retName = returnedValueNames[args[0][1]] + "_a_" + ret.name; - break; - case "uniformlocation": - retName = returnedValueNames[args[0][1]] + "_u_" + args[1][1]; - break; - } - if (returnedValueNames.includes(retName)) { - retName = retName + "_" + retIndex; - } - - if (betterNames[retIndex] != null) { - retName = betterNames[retIndex]; - } - - returnedValueNames[retIndex] = retName; - } - - commands.push({ name, args, retIndex }); - } - ), { - /* - get(target, prop, receiver) { - const ret = Reflect.get(...arguments); - if (typeof ret !== "function") { - console.log("GET", prop, ret); - } - return ret; - } - */ - }); - - const regl = createREGL({ gl, pixelRatio: 1, extensions, optionalExtensions }); - - printCommands("INIT"); - returnedValueUsages.fill(0); - - // All this takes place in a full screen quad. - const fullScreenQuad = makeFullScreenQuad(regl); - const pipeline = makePipeline({ regl }, [makeRain, makeBloomPass, makePalettePass]); - const screenUniforms = { tex: pipeline[pipeline.length - 1].outputs.primary }; - const drawToScreen = regl({ uniforms: screenUniforms }); - await Promise.all(pipeline.map((step) => step.ready)); - - printCommands("LOAD"); - - const render = ({ viewportWidth, viewportHeight }) => { - const now = regl.now() * 1000; - - if (dimensions.width !== viewportWidth || dimensions.height !== viewportHeight) { - dimensions.width = viewportWidth; - dimensions.height = viewportHeight; - for (const step of pipeline) { - step.setSize(viewportWidth, viewportHeight); - } - printCommands("RESIZE"); - } - fullScreenQuad(() => { - for (const step of pipeline) { - step.execute(); - } - drawToScreen(); - }); - printCommands("DRAW"); - }; - - render({ viewportWidth: 640, viewportHeight: 480 }); - - await new Promise(resolve => { - setTimeout(() => resolve(), 1000) - }); - - render({ viewportWidth: 640, viewportHeight: 480 }); - - console.log(log.join("\n")); - - // const tick = regl.frame(render); }; document.body.onload = () => { - init(); + start(); }; diff --git a/js/palettePass.js b/js/palettePass.js deleted file mode 100644 index 24aa5f1..0000000 --- a/js/palettePass.js +++ /dev/null @@ -1,64 +0,0 @@ -import { make1DTexture, makePassFBO, makePass } from "./utils.js"; - -export default ({ regl }, inputs) => { - const output = makePassFBO(regl); - const render = regl({ - frag: ` - precision mediump float; - #define PI 3.14159265359 - - uniform sampler2D tex, bloomTex, paletteTex; - uniform float time; - varying vec2 vUV; - - highp float rand( const in vec2 uv, const in float t ) { - const highp float a = 12.9898, b = 78.233, c = 43758.5453; - highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); - return fract(sin(sn) * c + t); - } - - void main() { - vec4 primary = texture2D(tex, vUV); - vec4 bloom = texture2D(bloomTex, vUV); - vec4 brightness = primary + bloom - rand( gl_FragCoord.xy, time ) * 0.0167; - gl_FragColor = vec4( - texture2D( paletteTex, vec2(brightness.r, 0.0)).rgb - + min(vec3(0.756, 1.0, 0.46) * brightness.g * 2.0, vec3(1.0)), - 1.0 - ); - } - `, - uniforms: { - tex: inputs.primary, - bloomTex: inputs.bloom, - paletteTex: make1DTexture(regl, [ - [0.0, 0.0, 0.0, 1.0], - [0.03, 0.13, 0.0, 1.0], - [0.06, 0.25, 0.01, 1.0], - [0.09, 0.38, 0.02, 1.0], - [0.15, 0.46, 0.07, 1.0], - [0.21, 0.54, 0.13, 1.0], - [0.28, 0.63, 0.19, 1.0], - [0.34, 0.71, 0.25, 1.0], - [0.41, 0.8, 0.31, 1.0], - [0.47, 0.88, 0.37, 1.0], - [0.53, 0.97, 0.43, 1.0], - [0.61, 0.97, 0.52, 1.0], - [0.69, 0.98, 0.62, 1.0], - [0.69, 0.98, 0.62, 1.0], - [0.69, 0.98, 0.62, 1.0], - [0.69, 0.98, 0.62, 1.0], - ]), - }, - framebuffer: output, - }); - - return makePass( - { - primary: output, - }, - null, - (w, h) => output.resize(w, h), - () => render() - ); -}; diff --git a/js/rainPass.js b/js/rainPass.js deleted file mode 100644 index 64e6c6a..0000000 --- a/js/rainPass.js +++ /dev/null @@ -1,256 +0,0 @@ -import { loadImage, makePassFBO, makeDoubleBuffer, makePass } from "./utils.js"; - -const numVerticesPerQuad = 2 * 3; -const tlVert = [0, 0]; -const trVert = [0, 1]; -const blVert = [1, 0]; -const brVert = [1, 1]; -const quadVertices = [tlVert, trVert, brVert, tlVert, brVert, blVert]; - -export default ({ regl }) => { - const size = 80; // The maximum dimension of the glyph grid - - const commonUniforms = { - glyphSequenceLength: 57, - glyphTextureGridSize: [8, 8], - numColumns: size, - numRows: size, - }; - - const computeDoubleBuffer = makeDoubleBuffer(regl, { - width: size, - height: size, - wrapT: "clamp", - type: "half float", - }); - - const compute = regl({ - frag: ` - precision highp float; - - #define PI 3.14159265359 - #define SQRT_2 1.4142135623730951 - #define SQRT_5 2.23606797749979 - - uniform sampler2D previousComputeState; - - uniform float numColumns, numRows; - uniform float time, tick; - uniform float fallSpeed, cycleSpeed; - uniform float glyphSequenceLength; - uniform float raindropLength; - - // Helper functions for generating randomness, borrowed from elsewhere - - highp float randomFloat( const in vec2 uv ) { - const highp float a = 12.9898, b = 78.233, c = 43758.5453; - highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); - return fract(sin(sn) * c); - } - - float wobble(float x) { - return x + 0.3 * sin(SQRT_2 * x) + 0.2 * sin(SQRT_5 * x); - } - - float getRainBrightness(float simTime, vec2 glyphPos) { - float columnTimeOffset = randomFloat(vec2(glyphPos.x, 0.)) * 1000.; - float columnSpeedOffset = randomFloat(vec2(glyphPos.x + 0.1, 0.)) * 0.5 + 0.5; - float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset; - float rainTime = (glyphPos.y * 0.01 + columnTime) / raindropLength; - rainTime = wobble(rainTime); - return 1.0 - fract(rainTime); - } - - vec2 computeRaindrop(float simTime, vec2 glyphPos) { - float brightness = getRainBrightness(simTime, glyphPos); - float brightnessBelow = getRainBrightness(simTime, glyphPos + vec2(0., -1.)); - bool cursor = brightness > brightnessBelow; - return vec2(brightness, cursor); - } - - vec2 computeSymbol(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous) { - - float previousSymbol = previous.r; - float previousAge = previous.g; - bool resetGlyph = isFirstFrame; - if (resetGlyph) { - previousAge = randomFloat(screenPos + 0.5); - previousSymbol = floor(glyphSequenceLength * randomFloat(screenPos)); - } - float age = previousAge; - float symbol = previousSymbol; - if (mod(tick, 1.0) == 0.) { - age += cycleSpeed; - if (age >= 1.) { - symbol = floor(glyphSequenceLength * randomFloat(screenPos + simTime)); - age = fract(age); - } - } - - return vec2(symbol, age); - } - - void main() { - vec2 glyphPos = gl_FragCoord.xy; - vec2 screenPos = glyphPos / vec2(numColumns, numRows); - - vec2 raindrop = computeRaindrop(time, glyphPos); - - bool isFirstFrame = tick <= 1.; - vec4 previous = texture2D( previousComputeState, screenPos ); - vec4 previousSymbol = vec4(previous.ba, 0.0, 0.0); - vec2 symbol = computeSymbol(time, isFirstFrame, glyphPos, screenPos, previousSymbol); - gl_FragColor = vec4(raindrop, symbol); - } - - `, - uniforms: { - ...commonUniforms, - cycleSpeed: 0.03, // The speed glyphs change - fallSpeed: 0.3, // The speed the raindrops progress downwards - raindropLength: 0.75, // Adjusts the frequency of raindrops (and their length) in a column - previousComputeState: computeDoubleBuffer.back, - }, - - framebuffer: computeDoubleBuffer.front, - }); - - // We render the code into an FBO using MSDFs: https://github.com/Chlumsky/msdfgen - const glyphMSDF = loadImage(regl, "assets/matrixcode_msdf.png"); - const output = makePassFBO(regl); - const render = regl({ - blend: { - enable: true, - func: { - src: "one", - dst: "one", - }, - }, - vert: ` - precision lowp float; - - attribute vec2 aPosition; - uniform vec2 screenSize; - varying vec2 vUV; - - void main() { - vUV = aPosition; - gl_Position = vec4((aPosition - 0.5) * 2.0 * screenSize, 0.0, 1.0); - } - `, - frag: ` - #define PI 3.14159265359 - #ifdef GL_OES_standard_derivatives - #extension GL_OES_standard_derivatives: enable - #endif - precision lowp float; - - uniform sampler2D computeState; - uniform float numColumns, numRows; - uniform sampler2D glyphMSDF; - uniform float msdfPxRange; - uniform vec2 glyphMSDFSize; - uniform float glyphSequenceLength; - uniform vec2 glyphTextureGridSize; - - varying vec2 vUV; - - float median3(vec3 i) { - return max(min(i.r, i.g), min(max(i.r, i.g), i.b)); - } - - float modI(float a, float b) { - float m = a - floor((a + 0.5) / b) * b; - return floor(m + 0.5); - } - - vec3 getBrightness(vec2 raindrop, vec2 uv) { - - float base = raindrop.r; - bool isCursor = bool(raindrop.g); - float glint = base; - - base = base * 1.1 - 0.5; - glint = glint * 2.5 - 1.5; - - return vec3( - (isCursor ? vec2(0.0, 1.0) : vec2(1.0, 0.0)) * base, - glint - ); - } - - vec2 getSymbolUV(float index) { - float symbolX = modI(index, glyphTextureGridSize.x); - float symbolY = (index - symbolX) / glyphTextureGridSize.x; - symbolY = glyphTextureGridSize.y - symbolY - 1.; - return vec2(symbolX, symbolY); - } - - vec2 getSymbol(vec2 uv, float index) { - // resolve UV to cropped position of glyph in MSDF texture - uv = fract(uv * vec2(numColumns, numRows)); - uv = (uv + getSymbolUV(index)) / glyphTextureGridSize; - - // MSDF: calculate brightness of fragment based on distance to shape - vec2 symbol; - { - vec2 unitRange = vec2(msdfPxRange) / glyphMSDFSize; - vec2 screenTexSize = vec2(1.0) / fwidth(uv); - float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0); - - float signedDistance = median3(texture2D(glyphMSDF, uv).rgb); - float screenPxDistance = screenPxRange * (signedDistance - 0.5); - symbol.r = clamp(screenPxDistance + 0.5, 0.0, 1.0); - } - - return symbol; - } - - void main() { - vec4 data = texture2D(computeState, vUV); - vec3 brightness = getBrightness(data.rg, vUV); - vec2 symbol = getSymbol(vUV, data.b); - gl_FragColor = vec4(brightness.rg * symbol.r, brightness.b * symbol.g, 0.); - } - `, - - uniforms: { - ...commonUniforms, - computeState: computeDoubleBuffer.front, - glyphMSDF: glyphMSDF.texture, - msdfPxRange: 4.0, - glyphMSDFSize: () => [glyphMSDF.width(), glyphMSDF.height()], - screenSize: regl.prop("screenSize"), - }, - - attributes: { - aPosition: quadVertices, - }, - count: numVerticesPerQuad, - - framebuffer: output, - }); - - const screenSize = [1, 1]; - - return makePass( - { - primary: output, - }, - Promise.all([glyphMSDF.loaded]), - (w, h) => { - output.resize(w, h); - const aspectRatio = w / h; - [screenSize[0], screenSize[1]] = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1]; - }, - () => { - compute(); - regl.clear({ - depth: 1, - color: [0, 0, 0, 1], - framebuffer: output, - }); - render({ screenSize }); - } - ); -}; diff --git a/js/unraveled.js b/js/unraveled.js new file mode 100644 index 0000000..ececc9a --- /dev/null +++ b/js/unraveled.js @@ -0,0 +1,809 @@ +const extendedContext = {}; +const state = {}; +const textures = {}; +const textureSizes = { fullscreen: {scale: 1}}; + +const extensionNames = [ + "oes_texture_half_float", + "oes_texture_half_float_linear", + "ext_color_buffer_half_float", + "webgl_color_buffer_float", + "oes_standard_derivatives", +]; + +const fullscreen_frag_shader_source = ` + precision mediump float; + varying vec2 vUV; + uniform sampler2D tex; + void main() { + gl_FragColor = texture2D(tex, vUV); + } +`; + +const fullscreen_vert_shader_source = ` + precision mediump float; + attribute vec2 aPosition; + varying vec2 vUV; + void main() { + vUV = 0.5 * (aPosition + 1.0); + gl_Position = vec4(aPosition, 0, 1); + } +`; + +const rain_compute_shader_source = ` + precision highp float; + + #define PI 3.14159265359 + #define SQRT_2 1.4142135623730951 + #define SQRT_5 2.23606797749979 + + uniform sampler2D previousComputeState; + + uniform float numColumns, numRows; + uniform float time, tick; + uniform float fallSpeed, cycleSpeed; + uniform float glyphSequenceLength; + uniform float raindropLength; + + highp float randomFloat( const in vec2 uv ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract(sin(sn) * c); + } + + float wobble(float x) { + return x + 0.3 * sin(SQRT_2 * x) + 0.2 * sin(SQRT_5 * x); + } + + float getRainBrightness(float simTime, vec2 glyphPos) { + float columnTimeOffset = randomFloat(vec2(glyphPos.x, 0.)) * 1000.; + float columnSpeedOffset = randomFloat(vec2(glyphPos.x + 0.1, 0.)) * 0.5 + 0.5; + float columnTime = columnTimeOffset + simTime * fallSpeed * columnSpeedOffset; + float rainTime = (glyphPos.y * 0.01 + columnTime) / raindropLength; + rainTime = wobble(rainTime); + return 1.0 - fract(rainTime); + } + + vec2 computeRaindrop(float simTime, vec2 glyphPos) { + float brightness = getRainBrightness(simTime, glyphPos); + float brightnessBelow = getRainBrightness(simTime, glyphPos + vec2(0., -1.)); + bool cursor = brightness > brightnessBelow; + return vec2(brightness, cursor); + } + + vec2 computeSymbol(float simTime, bool isFirstFrame, vec2 glyphPos, vec2 screenPos, vec4 previous) { + + float previousSymbol = previous.r; + float previousAge = previous.g; + bool resetGlyph = isFirstFrame; + if (resetGlyph) { + previousAge = randomFloat(screenPos + 0.5); + previousSymbol = floor(glyphSequenceLength * randomFloat(screenPos)); + } + float age = previousAge; + float symbol = previousSymbol; + if (mod(tick, 1.0) == 0.) { + age += cycleSpeed; + if (age >= 1.) { + symbol = floor(glyphSequenceLength * randomFloat(screenPos + simTime)); + age = fract(age); + } + } + + return vec2(symbol, age); + } + + void main() { + vec2 glyphPos = gl_FragCoord.xy; + vec2 screenPos = glyphPos / vec2(numColumns, numRows); + + vec2 raindrop = computeRaindrop(time, glyphPos); + + bool isFirstFrame = tick <= 1.; + vec4 previous = texture2D( previousComputeState, screenPos ); + vec4 previousSymbol = vec4(previous.ba, 0.0, 0.0); + vec2 symbol = computeSymbol(time, isFirstFrame, glyphPos, screenPos, previousSymbol); + gl_FragColor = vec4(raindrop, symbol); + } + +`; + +const rain_vert_shader_source = ` + precision lowp float; + + attribute vec2 aPosition; + uniform vec2 screenSize; + varying vec2 vUV; + + void main() { + vUV = aPosition; + gl_Position = vec4((aPosition - 0.5) * 2.0 * screenSize, 0.0, 1.0); + } +`; + +const rain_frag_shader_source = ` + #define PI 3.14159265359 + #ifdef GL_OES_standard_derivatives + #extension GL_OES_standard_derivatives: enable + #endif + precision lowp float; + + uniform sampler2D computeState; + uniform float numColumns, numRows; + uniform sampler2D glyphMSDF; + uniform float msdfPxRange; + uniform vec2 glyphMSDFSize; + uniform float glyphSequenceLength; + uniform vec2 glyphTextureGridSize; + + varying vec2 vUV; + + float median3(vec3 i) { + return max(min(i.r, i.g), min(max(i.r, i.g), i.b)); + } + + float modI(float a, float b) { + float m = a - floor((a + 0.5) / b) * b; + return floor(m + 0.5); + } + + vec3 getBrightness(vec2 raindrop, vec2 uv) { + + float base = raindrop.r; + bool isCursor = bool(raindrop.g); + float glint = base; + + base = base * 1.1 - 0.5; + glint = glint * 2.5 - 1.5; + + return vec3( + (isCursor ? vec2(0.0, 1.0) : vec2(1.0, 0.0)) * base, + glint + ); + } + + vec2 getSymbolUV(float index) { + float symbolX = modI(index, glyphTextureGridSize.x); + float symbolY = (index - symbolX) / glyphTextureGridSize.x; + symbolY = glyphTextureGridSize.y - symbolY - 1.; + return vec2(symbolX, symbolY); + } + + vec2 getSymbol(vec2 uv, float index) { + uv = fract(uv * vec2(numColumns, numRows)); + uv = (uv + getSymbolUV(index)) / glyphTextureGridSize; + + vec2 symbol; + { + vec2 unitRange = vec2(msdfPxRange) / glyphMSDFSize; + vec2 screenTexSize = vec2(1.0) / fwidth(uv); + float screenPxRange = max(0.5 * dot(unitRange, screenTexSize), 1.0); + + float signedDistance = median3(texture2D(glyphMSDF, uv).rgb); + float screenPxDistance = screenPxRange * (signedDistance - 0.5); + symbol.r = clamp(screenPxDistance + 0.5, 0.0, 1.0); + } + + return symbol; + } + + void main() { + vec4 data = texture2D(computeState, vUV); + vec3 brightness = getBrightness(data.rg, vUV); + vec2 symbol = getSymbol(vUV, data.b); + gl_FragColor = vec4(brightness.rg * symbol.r, brightness.b * symbol.g, 0.); + } +`; + +const bloom_high_pass_shader_source = ` + precision mediump float; + + uniform sampler2D tex; + uniform float highPassThreshold; + + varying vec2 vUV; + + void main() { + vec4 color = texture2D(tex, vUV); + + if (color.r < highPassThreshold) color.r = 0.0; + if (color.g < highPassThreshold) color.g = 0.0; + if (color.b < highPassThreshold) color.b = 0.0; + gl_FragColor = color; + } +`; + +const bloom_blur_shader_source = ` + precision mediump float; + + uniform float width, height; + uniform sampler2D tex; + uniform vec2 direction; + + varying vec2 vUV; + + void main() { + vec2 size = height > width ? vec2(height / width, 1.) : vec2(1., width / height); + gl_FragColor = + texture2D(tex, vUV) * 0.442 + + ( + texture2D(tex, vUV + direction / max(height, width) * size) + + texture2D(tex, vUV - direction / max(height, width) * size) + ) * 0.279; + } +`; + +const bloom_combine_shader_source = ` + precision mediump float; + + uniform sampler2D pyr_0, pyr_1, pyr_2, pyr_3, pyr_4; + uniform float bloomStrength; + varying vec2 vUV; + + void main() { + vec4 total = vec4(0.); + total += texture2D(pyr_0, vUV) * 0.96549; + total += texture2D(pyr_1, vUV) * 0.92832; + total += texture2D(pyr_2, vUV) * 0.88790; + total += texture2D(pyr_3, vUV) * 0.84343; + total += texture2D(pyr_4, vUV) * 0.79370; + gl_FragColor = total * bloomStrength; + } +`; + +const palette_shader_source = ` + precision mediump float; + #define PI 3.14159265359 + + uniform sampler2D tex, bloomTex, paletteTex; + uniform float time; + varying vec2 vUV; + + highp float rand( const in vec2 uv, const in float t ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract(sin(sn) * c + t); + } + + void main() { + vec4 primary = texture2D(tex, vUV); + vec4 bloom = texture2D(bloomTex, vUV); + vec4 brightness = primary + bloom - rand( gl_FragCoord.xy, time ) * 0.0167; + gl_FragColor = vec4( + texture2D( paletteTex, vec2(brightness.r, 0.0)).rgb + + min(vec3(0.756, 1.0, 0.46) * brightness.g * 2.0, vec3(1.0)), + 1.0 + ); + } +`; + +const init = (gl) => Object.assign(extendedContext, ...extensionNames.map(name => Object.getPrototypeOf(gl.getExtension(name)))); + +const load = (gl, msdfImage, palette) => { + + state.fullscreen_frag_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.fullscreen_frag_shader, fullscreen_frag_shader_source); gl.compileShader(state.fullscreen_frag_shader); + + state.fullscreen_vert_shader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(state.fullscreen_vert_shader, fullscreen_vert_shader_source); gl.compileShader(state.fullscreen_vert_shader); + + state.rain_compute_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.rain_compute_shader, rain_compute_shader_source); gl.compileShader(state.rain_compute_shader); + + state.rain_frag_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.rain_frag_shader, rain_frag_shader_source); gl.compileShader(state.rain_frag_shader); + + state.rain_vert_shader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(state.rain_vert_shader, rain_vert_shader_source); gl.compileShader(state.rain_vert_shader); + + state.bloom_high_pass_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.bloom_high_pass_shader, bloom_high_pass_shader_source); gl.compileShader(state.bloom_high_pass_shader); + + state.bloom_blur_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.bloom_blur_shader, bloom_blur_shader_source); gl.compileShader(state.bloom_blur_shader); + + state.bloom_combine_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.bloom_combine_shader, bloom_combine_shader_source); gl.compileShader(state.bloom_combine_shader); + + state.palette_shader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(state.palette_shader, palette_shader_source); gl.compileShader(state.palette_shader); + + state.fullscreen_program = gl.createProgram(); gl.attachShader(state.fullscreen_program, state.fullscreen_vert_shader); gl.attachShader(state.fullscreen_program, state.fullscreen_frag_shader); gl.linkProgram(state.fullscreen_program); + state.rain_program_u_tex = gl.getUniformLocation(state.fullscreen_program, "tex"); + state.fullscreen_program_a_aPosition = gl.getAttribLocation(state.fullscreen_program, "aPosition"); + + state.rain_compute_program = gl.createProgram(); gl.attachShader(state.rain_compute_program, state.fullscreen_vert_shader); gl.attachShader(state.rain_compute_program, state.rain_compute_shader); gl.linkProgram(state.rain_compute_program); + state.rain_compute_program_a_aPosition = gl.getAttribLocation(state.rain_compute_program, "aPosition"); + state.rain_compute_program_u_numColumns = gl.getUniformLocation(state.rain_compute_program, "numColumns"); + state.rain_compute_program_u_glyphSequenceLength = gl.getUniformLocation(state.rain_compute_program, "glyphSequenceLength"); + state.rain_compute_program_u_numRows = gl.getUniformLocation(state.rain_compute_program, "numRows"); + state.rain_compute_program_u_fallSpeed = gl.getUniformLocation(state.rain_compute_program, "fallSpeed"); + state.rain_compute_program_u_time = gl.getUniformLocation(state.rain_compute_program, "time"); + state.rain_compute_program_u_raindropLength = gl.getUniformLocation(state.rain_compute_program, "raindropLength"); + state.rain_compute_program_u_previousComputeState = gl.getUniformLocation(state.rain_compute_program, "previousComputeState"); + state.rain_compute_program_u_tick = gl.getUniformLocation(state.rain_compute_program, "tick"); + state.rain_compute_program_u_cycleSpeed = gl.getUniformLocation(state.rain_compute_program, "cycleSpeed"); + + gl.useProgram(state.rain_compute_program); + gl.uniform1f(state.rain_compute_program_u_numColumns, 80); + gl.uniform1f(state.rain_compute_program_u_glyphSequenceLength, 57); + gl.uniform1f(state.rain_compute_program_u_numRows, 80); + gl.uniform1f(state.rain_compute_program_u_fallSpeed, 0.3); + gl.uniform1f(state.rain_compute_program_u_raindropLength, 0.75); + gl.uniform1f(state.rain_compute_program_u_cycleSpeed, 0.03); + + state.rain_program = gl.createProgram(); gl.attachShader(state.rain_program, state.rain_vert_shader); gl.attachShader(state.rain_program, state.rain_frag_shader); gl.linkProgram(state.rain_program); + state.rain_program_a_aPosition = gl.getAttribLocation(state.rain_program, "aPosition"); + state.rain_program_u_glyphTextureGridSize = gl.getUniformLocation(state.rain_program, "glyphTextureGridSize"); + state.rain_program_u_numColumns = gl.getUniformLocation(state.rain_program, "numColumns"); + state.rain_program_u_glyphMSDFSize = gl.getUniformLocation(state.rain_program, "glyphMSDFSize"); + state.rain_program_u_numRows = gl.getUniformLocation(state.rain_program, "numRows"); + state.rain_program_u_msdfPxRange = gl.getUniformLocation(state.rain_program, "msdfPxRange"); + state.rain_program_u_screenSize = gl.getUniformLocation(state.rain_program, "screenSize"); + state.rain_program_u_computeState = gl.getUniformLocation(state.rain_program, "computeState"); + state.rain_program_u_glyphMSDF = gl.getUniformLocation(state.rain_program, "glyphMSDF"); + + gl.useProgram(state.rain_program); + gl.uniform2f(state.rain_program_u_glyphTextureGridSize, 8, 8); + gl.uniform1f(state.rain_program_u_numColumns, 80); + gl.uniform2f(state.rain_program_u_glyphMSDFSize, 512, 512); + gl.uniform1f(state.rain_program_u_numRows, 80); + gl.uniform1f(state.rain_program_u_msdfPxRange, 4); + + state.bloom_high_pass_program = gl.createProgram(); gl.attachShader(state.bloom_high_pass_program, state.fullscreen_vert_shader); gl.attachShader(state.bloom_high_pass_program, state.bloom_high_pass_shader); gl.linkProgram(state.bloom_high_pass_program); + state.bloom_high_pass_program_a_aPosition = gl.getAttribLocation(state.bloom_high_pass_program, "aPosition"); + state.bloom_high_pass_program_u_tex = gl.getUniformLocation(state.bloom_high_pass_program, "tex"); + state.bloom_high_pass_program_u_highPassThreshold = gl.getUniformLocation(state.bloom_high_pass_program, "highPassThreshold"); + + gl.useProgram(state.bloom_high_pass_program); + gl.uniform1f(state.bloom_high_pass_program_u_highPassThreshold, 0.1); + + state.bloom_blur_program = gl.createProgram(); gl.attachShader(state.bloom_blur_program, state.fullscreen_vert_shader); gl.attachShader(state.bloom_blur_program, state.bloom_blur_shader); gl.linkProgram(state.bloom_blur_program); + state.bloom_blur_program_a_aPosition = gl.getAttribLocation(state.bloom_blur_program, "aPosition"); + state.bloom_blur_program_u_tex = gl.getUniformLocation(state.bloom_blur_program, "tex"); + state.bloom_blur_program_u_width = gl.getUniformLocation(state.bloom_blur_program, "width"); + state.bloom_blur_program_u_height = gl.getUniformLocation(state.bloom_blur_program, "height"); + state.bloom_blur_program_u_direction = gl.getUniformLocation(state.bloom_blur_program, "direction"); + + state.bloom_combine_program = gl.createProgram(); gl.attachShader(state.bloom_combine_program, state.fullscreen_vert_shader); gl.attachShader(state.bloom_combine_program, state.bloom_combine_shader); gl.linkProgram(state.bloom_combine_program); + state.bloom_combine_program_a_aPosition = gl.getAttribLocation(state.bloom_combine_program, "aPosition"); + state.bloom_combine_program_u_pyr_0 = gl.getUniformLocation(state.bloom_combine_program, "pyr_0"); + state.bloom_combine_program_u_pyr_1 = gl.getUniformLocation(state.bloom_combine_program, "pyr_1"); + state.bloom_combine_program_u_pyr_2 = gl.getUniformLocation(state.bloom_combine_program, "pyr_2"); + state.bloom_combine_program_u_pyr_3 = gl.getUniformLocation(state.bloom_combine_program, "pyr_3"); + state.bloom_combine_program_u_pyr_4 = gl.getUniformLocation(state.bloom_combine_program, "pyr_4"); + state.bloom_combine_program_u_bloomStrength = gl.getUniformLocation(state.bloom_combine_program, "bloomStrength"); + + state.palette_program = gl.createProgram(); gl.attachShader(state.palette_program, state.fullscreen_vert_shader); gl.attachShader(state.palette_program, state.palette_shader); gl.linkProgram(state.palette_program); + state.palette_program_a_aPosition = gl.getAttribLocation(state.palette_program, "aPosition"); + state.palette_program_u_tex = gl.getUniformLocation(state.palette_program, "tex"); + state.palette_program_u_bloomTex = gl.getUniformLocation(state.palette_program, "bloomTex"); + state.palette_program_u_time = gl.getUniformLocation(state.palette_program, "time"); + state.palette_program_u_paletteTex = gl.getUniformLocation(state.palette_program, "paletteTex"); + + state.rain_geometry = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, state.rain_geometry); + gl.bufferData(gl.ARRAY_BUFFER, Float32Array.from([0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0]), gl.STATIC_DRAW); + + state.fullscreen_geometry = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); + gl.bufferData(gl.ARRAY_BUFFER, Float32Array.from([-4, -4, 4, -4, 0, 4]), gl.STATIC_DRAW); + + textures.rain_compute_doublebuffer_1 = gl.createTexture(); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.rain_compute_doublebuffer_1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 80, 80, 0, gl.RGBA, extendedContext.HALF_FLOAT_OES, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + state.rain_compute_doublebuffer_1_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.rain_compute_doublebuffer_1_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.rain_compute_doublebuffer_1, 0); + + textures.rain_compute_doublebuffer_2 = gl.createTexture(); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.rain_compute_doublebuffer_2); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 80, 80, 0, gl.RGBA, extendedContext.HALF_FLOAT_OES, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + state.rain_compute_doublebuffer_2_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.rain_compute_doublebuffer_2_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.rain_compute_doublebuffer_2, 0); + + textures.rain_output = gl.createTexture(); + textureSizes.rain_output = {scale: 1}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.rain_output); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.rain_output_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.rain_output_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.rain_output, 0); + + const bloomSize = 0.4; + + textures.bloom_high_pass_pyr_0 = gl.createTexture(); + textureSizes.bloom_high_pass_pyr_0 = {scale: bloomSize / (2 ** 0)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_high_pass_pyr_0_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_0_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_high_pass_pyr_0, 0); + + textures.bloom_high_pass_pyr_1 = gl.createTexture(); + textureSizes.bloom_high_pass_pyr_1 = {scale: bloomSize / (2 ** 1)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_high_pass_pyr_1_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_1_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_high_pass_pyr_1, 0); + + textures.bloom_high_pass_pyr_2 = gl.createTexture(); + textureSizes.bloom_high_pass_pyr_2 = {scale: bloomSize / (2 ** 2)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_2); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_high_pass_pyr_2_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_2_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_high_pass_pyr_2, 0); + + textures.bloom_high_pass_pyr_3 = gl.createTexture(); + textureSizes.bloom_high_pass_pyr_3 = {scale: bloomSize / (2 ** 3)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_3); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_high_pass_pyr_3_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_3_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_high_pass_pyr_3, 0); + + textures.bloom_high_pass_pyr_4 = gl.createTexture(); + textureSizes.bloom_high_pass_pyr_4 = {scale: bloomSize / (2 ** 4)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_4); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_high_pass_pyr_4_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_4_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_high_pass_pyr_4, 0); + + textures.bloom_h_blur_pyr_0 = gl.createTexture(); + textureSizes.bloom_h_blur_pyr_0 = {scale: bloomSize / (2 ** 0)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_h_blur_pyr_0_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_0_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_h_blur_pyr_0, 0); + + textures.bloom_h_blur_pyr_1 = gl.createTexture(); + textureSizes.bloom_h_blur_pyr_1 = {scale: bloomSize / (2 ** 1)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_h_blur_pyr_1_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_1_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_h_blur_pyr_1, 0); + + textures.bloom_h_blur_pyr_2 = gl.createTexture(); + textureSizes.bloom_h_blur_pyr_2 = {scale: bloomSize / (2 ** 2)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_2); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_h_blur_pyr_2_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_2_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_h_blur_pyr_2, 0); + + textures.bloom_h_blur_pyr_3 = gl.createTexture(); + textureSizes.bloom_h_blur_pyr_3 = {scale: bloomSize / (2 ** 3)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_3); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_h_blur_pyr_3_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_3_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_h_blur_pyr_3, 0); + + textures.bloom_h_blur_pyr_4 = gl.createTexture(); + textureSizes.bloom_h_blur_pyr_4 = {scale: bloomSize / (2 ** 4)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_4); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_h_blur_pyr_4_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_4_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_h_blur_pyr_4, 0); + + textures.bloom_v_blur_pyr_0 = gl.createTexture(); + textureSizes.bloom_v_blur_pyr_0 = {scale: bloomSize / (2 ** 0)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_0); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_v_blur_pyr_0_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_0_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_v_blur_pyr_0, 0); + + textures.bloom_v_blur_pyr_1 = gl.createTexture(); + textureSizes.bloom_v_blur_pyr_1 = {scale: bloomSize / (2 ** 1)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_1); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_v_blur_pyr_1_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_1_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_v_blur_pyr_1, 0); + + textures.bloom_v_blur_pyr_2 = gl.createTexture(); + textureSizes.bloom_v_blur_pyr_2 = {scale: bloomSize / (2 ** 2)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_2); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_v_blur_pyr_2_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_2_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_v_blur_pyr_2, 0); + + textures.bloom_v_blur_pyr_3 = gl.createTexture(); + textureSizes.bloom_v_blur_pyr_3 = {scale: bloomSize / (2 ** 3)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_3); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_v_blur_pyr_3_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_3_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_v_blur_pyr_3, 0); + + textures.bloom_v_blur_pyr_4 = gl.createTexture(); + textureSizes.bloom_v_blur_pyr_4 = {scale: bloomSize / (2 ** 4)}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_4); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_v_blur_pyr_4_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_4_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_v_blur_pyr_4, 0); + + textures.bloom_output = gl.createTexture(); + textureSizes.bloom_output = {scale: 1}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.bloom_output); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.bloom_output_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_output_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.bloom_output, 0); + + textures.palette_output = gl.createTexture(); + textureSizes.palette_output = {scale: 1}; + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.palette_output); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + state.palette_output_framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.palette_output_framebuffer); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textures.palette_output, 0); + + textures.palette = gl.createTexture(); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.palette); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, Uint8ClampedArray.from(palette)); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + + textures.msdf = gl.createTexture(); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures.msdf); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, msdfImage); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +}; + +const resize = (gl, width, height) => { + + textureSizes.fullscreen.width = width; + textureSizes.fullscreen.height = height; + + for (var name in textures) { + const size = textureSizes[name]; + if (size == null) { + continue; + } + size.width = Math.floor(width * size.scale); + size.height = Math.floor(height * size.scale); + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, textures[name]); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size.width, size.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } +}; + +const draw = (gl, tick, time) => { + + const flip = tick % 2 == 0; + const doubleBufferFrontFBO = flip ? state.rain_compute_doublebuffer_2_framebuffer : state.rain_compute_doublebuffer_1_framebuffer; + const doubleBufferFrontTex = flip ? textures.rain_compute_doublebuffer_2 : textures.rain_compute_doublebuffer_1; + const doubleBufferBackTex = flip ? textures.rain_compute_doublebuffer_1 : textures.rain_compute_doublebuffer_2; + let size; + + gl.enableVertexAttribArray(0); + gl.disable(gl.DEPTH_TEST); + gl.blendFuncSeparate(1, 1, 1, 1); + gl.clearColor(0, 0, 0, 1); + + // rain compute + gl.bindFramebuffer(gl.FRAMEBUFFER, doubleBufferFrontFBO); + gl.viewport(0, 0, 80, 80); + gl.useProgram(state.rain_compute_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.rain_compute_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, doubleBufferBackTex); gl.uniform1i(state.rain_compute_program_u_previousComputeState, 0); + gl.uniform1f(state.rain_compute_program_u_time, time); + gl.uniform1f(state.rain_compute_program_u_tick, tick); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + // rain + gl.bindFramebuffer(gl.FRAMEBUFFER, state.rain_output_framebuffer); + size = textureSizes.rain_output; gl.viewport(0, 0, size.width, size.height); + gl.clear(gl.COLOR_BUFFER_BIT); + gl.enable(gl.BLEND); + gl.useProgram(state.rain_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.rain_geometry); gl.vertexAttribPointer(state.rain_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + + size = textureSizes.fullscreen; + const aspectRatio = size.width / size.height; + const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1]; + + gl.uniform2f(state.rain_program_u_screenSize, screenSize[0], screenSize[1]); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, doubleBufferFrontTex); gl.uniform1i(state.rain_program_u_computeState, 0); + gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, textures.msdf); gl.uniform1i(state.rain_program_u_glyphMSDF, 1); + gl.drawArrays(gl.TRIANGLES, 0, 6); + gl.disable(gl.BLEND); + + // high pass pyramid + gl.useProgram(state.bloom_high_pass_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.bloom_high_pass_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_0_framebuffer); + size = textureSizes.bloom_high_pass_pyr_0; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.rain_output); gl.uniform1i(state.bloom_high_pass_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_1_framebuffer); + size = textureSizes.bloom_high_pass_pyr_1; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_0); gl.uniform1i(state.bloom_high_pass_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_2_framebuffer); + size = textureSizes.bloom_high_pass_pyr_2; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_1); gl.uniform1i(state.bloom_high_pass_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_3_framebuffer); + size = textureSizes.bloom_high_pass_pyr_3; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_2); gl.uniform1i(state.bloom_high_pass_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_high_pass_pyr_4_framebuffer); + size = textureSizes.bloom_high_pass_pyr_4; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_3); gl.uniform1i(state.bloom_high_pass_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + // blur pyramids + gl.useProgram(state.bloom_blur_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.bloom_blur_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_0_framebuffer); + size = textureSizes.bloom_h_blur_pyr_0; gl.viewport(0, 0, size.width, size.height); + gl.uniform1f(state.bloom_blur_program_u_width, size.width); gl.uniform1f(state.bloom_blur_program_u_height, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_0); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 1, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_0_framebuffer); + size = textureSizes.bloom_v_blur_pyr_0; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_0); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_1_framebuffer); + size = textureSizes.bloom_h_blur_pyr_1; gl.viewport(0, 0, size.width, size.height); + gl.uniform1f(state.bloom_blur_program_u_width, size.width); gl.uniform1f(state.bloom_blur_program_u_height, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_1); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 1, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_1_framebuffer); + size = textureSizes.bloom_v_blur_pyr_1; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_1); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_2_framebuffer); + size = textureSizes.bloom_h_blur_pyr_2; gl.viewport(0, 0, size.width, size.height); + gl.uniform1f(state.bloom_blur_program_u_width, size.width); gl.uniform1f(state.bloom_blur_program_u_height, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_2); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 1, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_2_framebuffer); + size = textureSizes.bloom_v_blur_pyr_2; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_2); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_3_framebuffer); + size = textureSizes.bloom_h_blur_pyr_3; gl.viewport(0, 0, size.width, size.height); + gl.uniform1f(state.bloom_blur_program_u_width, size.width); gl.uniform1f(state.bloom_blur_program_u_height, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_3); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 1, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_3_framebuffer); + size = textureSizes.bloom_v_blur_pyr_3; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_3); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_h_blur_pyr_4_framebuffer); + size = textureSizes.bloom_h_blur_pyr_4; gl.viewport(0, 0, size.width, size.height); + gl.uniform1f(state.bloom_blur_program_u_width, size.width); gl.uniform1f(state.bloom_blur_program_u_height, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_high_pass_pyr_4); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 1, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_v_blur_pyr_4_framebuffer); + size = textureSizes.bloom_v_blur_pyr_4; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_h_blur_pyr_4); gl.uniform1i(state.bloom_blur_program_u_tex, 0); + gl.uniform2f(state.bloom_blur_program_u_direction, 0, 1); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + // bloom combine + gl.useProgram(state.bloom_combine_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.bloom_combine_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + gl.bindFramebuffer(gl.FRAMEBUFFER, state.bloom_output_framebuffer); + size = textureSizes.bloom_output; gl.viewport(0, 0, size.width, size.height); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_0); gl.uniform1i(state.bloom_combine_program_u_pyr_0, 0); + gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_1); gl.uniform1i(state.bloom_combine_program_u_pyr_1, 1); + gl.activeTexture(gl.TEXTURE2); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_2); gl.uniform1i(state.bloom_combine_program_u_pyr_2, 2); + gl.activeTexture(gl.TEXTURE3); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_3); gl.uniform1i(state.bloom_combine_program_u_pyr_3, 3); + gl.activeTexture(gl.TEXTURE4); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_v_blur_pyr_4); gl.uniform1i(state.bloom_combine_program_u_pyr_4, 4); + gl.uniform1f(state.bloom_combine_program_u_bloomStrength, 0.7); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + // palette + gl.bindFramebuffer(gl.FRAMEBUFFER, state.palette_output_framebuffer); + size = textureSizes.palette_output; gl.viewport(0, 0, size.width, size.height); + gl.useProgram(state.palette_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.palette_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.rain_output); gl.uniform1i(state.palette_program_u_tex, 0); + gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D, textures.bloom_output); gl.uniform1i(state.palette_program_u_bloomTex, 1); + gl.uniform1f(state.palette_program_u_time, 0); + gl.activeTexture(gl.TEXTURE2); gl.bindTexture(gl.TEXTURE_2D, textures.palette); gl.uniform1i(state.palette_program_u_paletteTex, 2); + gl.drawArrays(gl.TRIANGLES, 0, 3); + + // upscale + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + size = textureSizes.fullscreen; gl.viewport(0, 0, size.width, size.height); + gl.useProgram(state.fullscreen_program); + gl.bindBuffer(gl.ARRAY_BUFFER, state.fullscreen_geometry); gl.vertexAttribPointer(state.fullscreen_program_a_aPosition, 2, gl.FLOAT, false, 0, 0); + gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, textures.palette_output); gl.uniform1i(state.fullscreen_program_u_tex, 0); + gl.drawArrays(gl.TRIANGLES, 0, 3); + +}; + +export { + init, load, resize, draw +}; diff --git a/js/utils.js b/js/utils.js deleted file mode 100644 index 7cf2387..0000000 --- a/js/utils.js +++ /dev/null @@ -1,128 +0,0 @@ -const makePassTexture = (regl, halfFloat) => - regl.texture({ - width: 1, - height: 1, - type: halfFloat ? "half float" : "uint8", - wrap: "clamp", - min: "linear", - mag: "linear", - }); - -const makePassFBO = (regl, halfFloat) => regl.framebuffer({ color: makePassTexture(regl, halfFloat) }); - -const makeDoubleBuffer = (regl, props) => { - const state = Array(2) - .fill() - .map(() => - regl.framebuffer({ - color: regl.texture(props), - depthStencil: false, - }) - ); - return { - front: ({ tick }) => state[tick % 2], - back: ({ tick }) => state[(tick + 1) % 2], - }; -}; - -const isPowerOfTwo = (x) => Math.log2(x) % 1 == 0; - -const loadImage = (regl, url) => { - let texture = regl.texture([[0]]); - let loaded = false; - return { - texture: () => texture, - width: () => (loaded ? texture.width : 1), - height: () => (loaded ? texture.height : 1), - loaded: (async () => { - if (url != null) { - const data = new Image(); - data.crossOrigin = "anonymous"; - data.src = url; - await data.decode(); - loaded = true; - texture = regl.texture({ - data, - mag: "linear", - min: "linear", - flipY: true, - }); - } - })(), - }; -}; - -const loadText = (url) => { - let text = ""; - let loaded = false; - return { - text: () => text, - loaded: (async () => { - if (url != null) { - text = await (await fetch(url)).text(); - loaded = true; - } - })(), - }; -}; - -const makeFullScreenQuad = (regl, uniforms = {}, context = {}) => - regl({ - vert: ` - precision mediump float; - attribute vec2 aPosition; - varying vec2 vUV; - void main() { - vUV = 0.5 * (aPosition + 1.0); - gl_Position = vec4(aPosition, 0, 1); - } - `, - - frag: ` - precision mediump float; - varying vec2 vUV; - uniform sampler2D tex; - void main() { - gl_FragColor = texture2D(tex, vUV); - } - `, - - attributes: { - aPosition: [-4, -4, 4, -4, 0, 4], - }, - count: 3, - - uniforms: { - ...uniforms, - time: regl.context("time"), - tick: regl.context("tick"), - }, - - context, - - depth: { enable: false }, - }); - -const make1DTexture = (regl, rgbas) => { - const data = rgbas.map((rgba) => rgba.map((f) => Math.floor(f * 0xff))).flat(); - return regl.texture({ - data, - width: data.length / 4, - height: 1, - format: "rgba", - mag: "linear", - min: "linear", - }); -}; - -const makePass = (outputs, ready, setSize, execute) => ({ - outputs: outputs ?? {}, - ready: ready ?? Promise.resolve(), - setSize: setSize ?? (() => {}), - execute: execute ?? (() => {}), -}); - -const makePipeline = (context, steps) => - steps.filter((f) => f != null).reduce((pipeline, f, i) => [...pipeline, f(context, i == 0 ? null : pipeline[i - 1].outputs)], []); - -export { makePassTexture, makePassFBO, makeDoubleBuffer, loadImage, loadText, makeFullScreenQuad, make1DTexture, makePass, makePipeline }; diff --git a/lib/regl.js b/lib/regl.js deleted file mode 100644 index 105828e..0000000 --- a/lib/regl.js +++ /dev/null @@ -1,10527 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.createREGL = factory()); -}(this, (function () { 'use strict'; - -var isTypedArray = function (x) { - return ( - x instanceof Uint8Array || - x instanceof Uint16Array || - x instanceof Uint32Array || - x instanceof Int8Array || - x instanceof Int16Array || - x instanceof Int32Array || - x instanceof Float32Array || - x instanceof Float64Array || - x instanceof Uint8ClampedArray - ) -} - -var extend = function (base, opts) { - var keys = Object.keys(opts) - for (var i = 0; i < keys.length; ++i) { - base[keys[i]] = opts[keys[i]] - } - return base -} - -// Error checking and parameter validation. -// -// Statements for the form `check.someProcedure(...)` get removed by -// a browserify transform for optimized/minified bundles. -// -/* globals atob */ -var endl = '\n' - -// only used for extracting shader names. if atob not present, then errors -// will be slightly crappier -function decodeB64 (str) { - if (typeof atob !== 'undefined') { - return atob(str) - } - return 'base64:' + str -} - -function raise (message) { - var error = new Error('(regl) ' + message) - console.error(error) - throw error -} - -function check (pred, message) { - if (!pred) { - raise(message) - } -} - -function encolon (message) { - if (message) { - return ': ' + message - } - return '' -} - -function checkParameter (param, possibilities, message) { - if (!(param in possibilities)) { - raise('unknown parameter (' + param + ')' + encolon(message) + - '. possible values: ' + Object.keys(possibilities).join()) - } -} - -function checkIsTypedArray (data, message) { - if (!isTypedArray(data)) { - raise( - 'invalid parameter type' + encolon(message) + - '. must be a typed array') - } -} - -function standardTypeEh (value, type) { - switch (type) { - case 'number': return typeof value === 'number' - case 'object': return typeof value === 'object' - case 'string': return typeof value === 'string' - case 'boolean': return typeof value === 'boolean' - case 'function': return typeof value === 'function' - case 'undefined': return typeof value === 'undefined' - case 'symbol': return typeof value === 'symbol' - } -} - -function checkTypeOf (value, type, message) { - if (!standardTypeEh(value, type)) { - raise( - 'invalid parameter type' + encolon(message) + - '. expected ' + type + ', got ' + (typeof value)) - } -} - -function checkNonNegativeInt (value, message) { - if (!((value >= 0) && - ((value | 0) === value))) { - raise('invalid parameter type, (' + value + ')' + encolon(message) + - '. must be a nonnegative integer') - } -} - -function checkOneOf (value, list, message) { - if (list.indexOf(value) < 0) { - raise('invalid value' + encolon(message) + '. must be one of: ' + list) - } -} - -var constructorKeys = [ - 'gl', - 'canvas', - 'container', - 'attributes', - 'pixelRatio', - 'extensions', - 'optionalExtensions', - 'profile', - 'onDone' -] - -function checkConstructor (obj) { - Object.keys(obj).forEach(function (key) { - if (constructorKeys.indexOf(key) < 0) { - raise('invalid regl constructor argument "' + key + '". must be one of ' + constructorKeys) - } - }) -} - -function leftPad (str, n) { - str = str + '' - while (str.length < n) { - str = ' ' + str - } - return str -} - -function ShaderFile () { - this.name = 'unknown' - this.lines = [] - this.index = {} - this.hasErrors = false -} - -function ShaderLine (number, line) { - this.number = number - this.line = line - this.errors = [] -} - -function ShaderError (fileNumber, lineNumber, message) { - this.file = fileNumber - this.line = lineNumber - this.message = message -} - -function guessCommand () { - var error = new Error() - var stack = (error.stack || error).toString() - var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack) - if (pat) { - return pat[1] - } - var pat2 = /compileProcedure.*\n\s*at\s+(.*)(\n|$)/.exec(stack) - if (pat2) { - return pat2[1] - } - return 'unknown' -} - -function guessCallSite () { - var error = new Error() - var stack = (error.stack || error).toString() - var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack) - if (pat) { - return pat[1] - } - var pat2 = /at REGLCommand.*\n\s+at\s+(.*)\n/.exec(stack) - if (pat2) { - return pat2[1] - } - return 'unknown' -} - -function parseSource (source, command) { - var lines = source.split('\n') - var lineNumber = 1 - var fileNumber = 0 - var files = { - unknown: new ShaderFile(), - 0: new ShaderFile() - } - files.unknown.name = files[0].name = command || guessCommand() - files.unknown.lines.push(new ShaderLine(0, '')) - for (var i = 0; i < lines.length; ++i) { - var line = lines[i] - var parts = /^\s*#\s*(\w+)\s+(.+)\s*$/.exec(line) - if (parts) { - switch (parts[1]) { - case 'line': - var lineNumberInfo = /(\d+)(\s+\d+)?/.exec(parts[2]) - if (lineNumberInfo) { - lineNumber = lineNumberInfo[1] | 0 - if (lineNumberInfo[2]) { - fileNumber = lineNumberInfo[2] | 0 - if (!(fileNumber in files)) { - files[fileNumber] = new ShaderFile() - } - } - } - break - case 'define': - var nameInfo = /SHADER_NAME(_B64)?\s+(.*)$/.exec(parts[2]) - if (nameInfo) { - files[fileNumber].name = (nameInfo[1] - ? decodeB64(nameInfo[2]) - : nameInfo[2]) - } - break - } - } - files[fileNumber].lines.push(new ShaderLine(lineNumber++, line)) - } - Object.keys(files).forEach(function (fileNumber) { - var file = files[fileNumber] - file.lines.forEach(function (line) { - file.index[line.number] = line - }) - }) - return files -} - -function parseErrorLog (errLog) { - var result = [] - errLog.split('\n').forEach(function (errMsg) { - if (errMsg.length < 5) { - return - } - var parts = /^ERROR:\s+(\d+):(\d+):\s*(.*)$/.exec(errMsg) - if (parts) { - result.push(new ShaderError( - parts[1] | 0, - parts[2] | 0, - parts[3].trim())) - } else if (errMsg.length > 0) { - result.push(new ShaderError('unknown', 0, errMsg)) - } - }) - return result -} - -function annotateFiles (files, errors) { - errors.forEach(function (error) { - var file = files[error.file] - if (file) { - var line = file.index[error.line] - if (line) { - line.errors.push(error) - file.hasErrors = true - return - } - } - files.unknown.hasErrors = true - files.unknown.lines[0].errors.push(error) - }) -} - -function checkShaderError (gl, shader, source, type, command) { - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - var errLog = gl.getShaderInfoLog(shader) - var typeName = type === gl.FRAGMENT_SHADER ? 'fragment' : 'vertex' - checkCommandType(source, 'string', typeName + ' shader source must be a string', command) - var files = parseSource(source, command) - var errors = parseErrorLog(errLog) - annotateFiles(files, errors) - - Object.keys(files).forEach(function (fileNumber) { - var file = files[fileNumber] - if (!file.hasErrors) { - return - } - - var strings = [''] - var styles = [''] - - function push (str, style) { - strings.push(str) - styles.push(style || '') - } - - push('file number ' + fileNumber + ': ' + file.name + '\n', 'color:red;text-decoration:underline;font-weight:bold') - - file.lines.forEach(function (line) { - if (line.errors.length > 0) { - push(leftPad(line.number, 4) + '| ', 'background-color:yellow; font-weight:bold') - push(line.line + endl, 'color:red; background-color:yellow; font-weight:bold') - - // try to guess token - var offset = 0 - line.errors.forEach(function (error) { - var message = error.message - var token = /^\s*'(.*)'\s*:\s*(.*)$/.exec(message) - if (token) { - var tokenPat = token[1] - message = token[2] - switch (tokenPat) { - case 'assign': - tokenPat = '=' - break - } - offset = Math.max(line.line.indexOf(tokenPat, offset), 0) - } else { - offset = 0 - } - - push(leftPad('| ', 6)) - push(leftPad('^^^', offset + 3) + endl, 'font-weight:bold') - push(leftPad('| ', 6)) - push(message + endl, 'font-weight:bold') - }) - push(leftPad('| ', 6) + endl) - } else { - push(leftPad(line.number, 4) + '| ') - push(line.line + endl, 'color:red') - } - }) - if (typeof document !== 'undefined' && !window.chrome) { - styles[0] = strings.join('%c') - console.log.apply(console, styles) - } else { - console.log(strings.join('')) - } - }) - - check.raise('Error compiling ' + typeName + ' shader, ' + files[0].name) - } -} - -function checkLinkError (gl, program, fragShader, vertShader, command) { - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - var errLog = gl.getProgramInfoLog(program) - var fragParse = parseSource(fragShader, command) - var vertParse = parseSource(vertShader, command) - - var header = 'Error linking program with vertex shader, "' + - vertParse[0].name + '", and fragment shader "' + fragParse[0].name + '"' - - if (typeof document !== 'undefined') { - console.log('%c' + header + endl + '%c' + errLog, - 'color:red;text-decoration:underline;font-weight:bold', - 'color:red') - } else { - console.log(header + endl + errLog) - } - check.raise(header) - } -} - -function saveCommandRef (object) { - object._commandRef = guessCommand() -} - -function saveDrawCommandInfo (opts, uniforms, attributes, stringStore) { - saveCommandRef(opts) - - function id (str) { - if (str) { - return stringStore.id(str) - } - return 0 - } - opts._fragId = id(opts.static.frag) - opts._vertId = id(opts.static.vert) - - function addProps (dict, set) { - Object.keys(set).forEach(function (u) { - dict[stringStore.id(u)] = true - }) - } - - var uniformSet = opts._uniformSet = {} - addProps(uniformSet, uniforms.static) - addProps(uniformSet, uniforms.dynamic) - - var attributeSet = opts._attributeSet = {} - addProps(attributeSet, attributes.static) - addProps(attributeSet, attributes.dynamic) - - opts._hasCount = ( - 'count' in opts.static || - 'count' in opts.dynamic || - 'elements' in opts.static || - 'elements' in opts.dynamic) -} - -function commandRaise (message, command) { - var callSite = guessCallSite() - raise(message + - ' in command ' + (command || guessCommand()) + - (callSite === 'unknown' ? '' : ' called from ' + callSite)) -} - -function checkCommand (pred, message, command) { - if (!pred) { - commandRaise(message, command || guessCommand()) - } -} - -function checkParameterCommand (param, possibilities, message, command) { - if (!(param in possibilities)) { - commandRaise( - 'unknown parameter (' + param + ')' + encolon(message) + - '. possible values: ' + Object.keys(possibilities).join(), - command || guessCommand()) - } -} - -function checkCommandType (value, type, message, command) { - if (!standardTypeEh(value, type)) { - commandRaise( - 'invalid parameter type' + encolon(message) + - '. expected ' + type + ', got ' + (typeof value), - command || guessCommand()) - } -} - -function checkOptional (block) { - block() -} - -function checkFramebufferFormat (attachment, texFormats, rbFormats) { - if (attachment.texture) { - checkOneOf( - attachment.texture._texture.internalformat, - texFormats, - 'unsupported texture format for attachment') - } else { - checkOneOf( - attachment.renderbuffer._renderbuffer.format, - rbFormats, - 'unsupported renderbuffer format for attachment') - } -} - -var GL_CLAMP_TO_EDGE = 0x812F - -var GL_NEAREST = 0x2600 -var GL_NEAREST_MIPMAP_NEAREST = 0x2700 -var GL_LINEAR_MIPMAP_NEAREST = 0x2701 -var GL_NEAREST_MIPMAP_LINEAR = 0x2702 -var GL_LINEAR_MIPMAP_LINEAR = 0x2703 - -var GL_BYTE = 5120 -var GL_UNSIGNED_BYTE = 5121 -var GL_SHORT = 5122 -var GL_UNSIGNED_SHORT = 5123 -var GL_INT = 5124 -var GL_UNSIGNED_INT = 5125 -var GL_FLOAT = 5126 - -var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033 -var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034 -var GL_UNSIGNED_SHORT_5_6_5 = 0x8363 -var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA - -var GL_HALF_FLOAT_OES = 0x8D61 - -var TYPE_SIZE = {} - -TYPE_SIZE[GL_BYTE] = -TYPE_SIZE[GL_UNSIGNED_BYTE] = 1 - -TYPE_SIZE[GL_SHORT] = -TYPE_SIZE[GL_UNSIGNED_SHORT] = -TYPE_SIZE[GL_HALF_FLOAT_OES] = -TYPE_SIZE[GL_UNSIGNED_SHORT_5_6_5] = -TYPE_SIZE[GL_UNSIGNED_SHORT_4_4_4_4] = -TYPE_SIZE[GL_UNSIGNED_SHORT_5_5_5_1] = 2 - -TYPE_SIZE[GL_INT] = -TYPE_SIZE[GL_UNSIGNED_INT] = -TYPE_SIZE[GL_FLOAT] = -TYPE_SIZE[GL_UNSIGNED_INT_24_8_WEBGL] = 4 - -function pixelSize (type, channels) { - if (type === GL_UNSIGNED_SHORT_5_5_5_1 || - type === GL_UNSIGNED_SHORT_4_4_4_4 || - type === GL_UNSIGNED_SHORT_5_6_5) { - return 2 - } else if (type === GL_UNSIGNED_INT_24_8_WEBGL) { - return 4 - } else { - return TYPE_SIZE[type] * channels - } -} - -function isPow2 (v) { - return !(v & (v - 1)) && (!!v) -} - -function checkTexture2D (info, mipData, limits) { - var i - var w = mipData.width - var h = mipData.height - var c = mipData.channels - - // Check texture shape - check(w > 0 && w <= limits.maxTextureSize && - h > 0 && h <= limits.maxTextureSize, - 'invalid texture shape') - - // check wrap mode - if (info.wrapS !== GL_CLAMP_TO_EDGE || info.wrapT !== GL_CLAMP_TO_EDGE) { - check(isPow2(w) && isPow2(h), - 'incompatible wrap mode for texture, both width and height must be power of 2') - } - - if (mipData.mipmask === 1) { - if (w !== 1 && h !== 1) { - check( - info.minFilter !== GL_NEAREST_MIPMAP_NEAREST && - info.minFilter !== GL_NEAREST_MIPMAP_LINEAR && - info.minFilter !== GL_LINEAR_MIPMAP_NEAREST && - info.minFilter !== GL_LINEAR_MIPMAP_LINEAR, - 'min filter requires mipmap') - } - } else { - // texture must be power of 2 - check(isPow2(w) && isPow2(h), - 'texture must be a square power of 2 to support mipmapping') - check(mipData.mipmask === (w << 1) - 1, - 'missing or incomplete mipmap data') - } - - if (mipData.type === GL_FLOAT) { - if (limits.extensions.indexOf('oes_texture_float_linear') < 0) { - check(info.minFilter === GL_NEAREST && info.magFilter === GL_NEAREST, - 'filter not supported, must enable oes_texture_float_linear') - } - check(!info.genMipmaps, - 'mipmap generation not supported with float textures') - } - - // check image complete - var mipimages = mipData.images - for (i = 0; i < 16; ++i) { - if (mipimages[i]) { - var mw = w >> i - var mh = h >> i - check(mipData.mipmask & (1 << i), 'missing mipmap data') - - var img = mipimages[i] - - check( - img.width === mw && - img.height === mh, - 'invalid shape for mip images') - - check( - img.format === mipData.format && - img.internalformat === mipData.internalformat && - img.type === mipData.type, - 'incompatible type for mip image') - - if (img.compressed) { - // TODO: check size for compressed images - } else if (img.data) { - // check(img.data.byteLength === mw * mh * - // Math.max(pixelSize(img.type, c), img.unpackAlignment), - var rowSize = Math.ceil(pixelSize(img.type, c) * mw / img.unpackAlignment) * img.unpackAlignment - check(img.data.byteLength === rowSize * mh, - 'invalid data for image, buffer size is inconsistent with image format') - } else if (img.element) { - // TODO: check element can be loaded - } else if (img.copy) { - // TODO: check compatible format and type - } - } else if (!info.genMipmaps) { - check((mipData.mipmask & (1 << i)) === 0, 'extra mipmap data') - } - } - - if (mipData.compressed) { - check(!info.genMipmaps, - 'mipmap generation for compressed images not supported') - } -} - -function checkTextureCube (texture, info, faces, limits) { - var w = texture.width - var h = texture.height - var c = texture.channels - - // Check texture shape - check( - w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize, - 'invalid texture shape') - check( - w === h, - 'cube map must be square') - check( - info.wrapS === GL_CLAMP_TO_EDGE && info.wrapT === GL_CLAMP_TO_EDGE, - 'wrap mode not supported by cube map') - - for (var i = 0; i < faces.length; ++i) { - var face = faces[i] - check( - face.width === w && face.height === h, - 'inconsistent cube map face shape') - - if (info.genMipmaps) { - check(!face.compressed, - 'can not generate mipmap for compressed textures') - check(face.mipmask === 1, - 'can not specify mipmaps and generate mipmaps') - } else { - // TODO: check mip and filter mode - } - - var mipmaps = face.images - for (var j = 0; j < 16; ++j) { - var img = mipmaps[j] - if (img) { - var mw = w >> j - var mh = h >> j - check(face.mipmask & (1 << j), 'missing mipmap data') - check( - img.width === mw && - img.height === mh, - 'invalid shape for mip images') - check( - img.format === texture.format && - img.internalformat === texture.internalformat && - img.type === texture.type, - 'incompatible type for mip image') - - if (img.compressed) { - // TODO: check size for compressed images - } else if (img.data) { - check(img.data.byteLength === mw * mh * - Math.max(pixelSize(img.type, c), img.unpackAlignment), - 'invalid data for image, buffer size is inconsistent with image format') - } else if (img.element) { - // TODO: check element can be loaded - } else if (img.copy) { - // TODO: check compatible format and type - } - } - } - } -} - -var check$1 = extend(check, { - optional: checkOptional, - raise: raise, - commandRaise: commandRaise, - command: checkCommand, - parameter: checkParameter, - commandParameter: checkParameterCommand, - constructor: checkConstructor, - type: checkTypeOf, - commandType: checkCommandType, - isTypedArray: checkIsTypedArray, - nni: checkNonNegativeInt, - oneOf: checkOneOf, - shaderError: checkShaderError, - linkError: checkLinkError, - callSite: guessCallSite, - saveCommandRef: saveCommandRef, - saveDrawInfo: saveDrawCommandInfo, - framebufferFormat: checkFramebufferFormat, - guessCommand: guessCommand, - texture2D: checkTexture2D, - textureCube: checkTextureCube -}); - -var VARIABLE_COUNTER = 0 - -var DYN_FUNC = 0 -var DYN_CONSTANT = 5 -var DYN_ARRAY = 6 - -function DynamicVariable (type, data) { - this.id = (VARIABLE_COUNTER++) - this.type = type - this.data = data -} - -function escapeStr (str) { - return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') -} - -function splitParts (str) { - if (str.length === 0) { - return [] - } - - var firstChar = str.charAt(0) - var lastChar = str.charAt(str.length - 1) - - if (str.length > 1 && - firstChar === lastChar && - (firstChar === '"' || firstChar === "'")) { - return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"'] - } - - var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str) - if (parts) { - return ( - splitParts(str.substr(0, parts.index)) - .concat(splitParts(parts[1])) - .concat(splitParts(str.substr(parts.index + parts[0].length))) - ) - } - - var subparts = str.split('.') - if (subparts.length === 1) { - return ['"' + escapeStr(str) + '"'] - } - - var result = [] - for (var i = 0; i < subparts.length; ++i) { - result = result.concat(splitParts(subparts[i])) - } - return result -} - -function toAccessorString (str) { - return '[' + splitParts(str).join('][') + ']' -} - -function defineDynamic (type, data) { - return new DynamicVariable(type, toAccessorString(data + '')) -} - -function isDynamic (x) { - return (typeof x === 'function' && !x._reglType) || (x instanceof DynamicVariable) -} - -function unbox (x, path) { - if (typeof x === 'function') { - return new DynamicVariable(DYN_FUNC, x) - } else if (typeof x === 'number' || typeof x === 'boolean') { - return new DynamicVariable(DYN_CONSTANT, x) - } else if (Array.isArray(x)) { - return new DynamicVariable(DYN_ARRAY, x.map(function (y, i) { return unbox(y, path + '[' + i + ']') })) - } else if (x instanceof DynamicVariable) { - return x - } - check$1(false, 'invalid option type in uniform ' + path) -} - -var dynamic = { - DynamicVariable: DynamicVariable, - define: defineDynamic, - isDynamic: isDynamic, - unbox: unbox, - accessor: toAccessorString -}; - -/* globals requestAnimationFrame, cancelAnimationFrame */ -var raf = { - next: typeof requestAnimationFrame === 'function' - ? function (cb) { return requestAnimationFrame(cb) } - : function (cb) { return setTimeout(cb, 16) }, - cancel: typeof cancelAnimationFrame === 'function' - ? function (raf) { return cancelAnimationFrame(raf) } - : clearTimeout -}; - -/* globals performance */ -var clock = (typeof performance !== 'undefined' && performance.now) - ? function () { return performance.now() } - : function () { return +(new Date()) }; - -function createStringStore () { - var stringIds = { '': 0 } - var stringValues = [''] - return { - id: function (str) { - var result = stringIds[str] - if (result) { - return result - } - result = stringIds[str] = stringValues.length - stringValues.push(str) - return result - }, - - str: function (id) { - return stringValues[id] - } - } -} - -// Context and canvas creation helper functions -function createCanvas (element, onDone, pixelRatio) { - var canvas = document.createElement('canvas') - extend(canvas.style, { - border: 0, - margin: 0, - padding: 0, - top: 0, - left: 0, - width: '100%', - height: '100%' - }) - element.appendChild(canvas) - - if (element === document.body) { - canvas.style.position = 'absolute' - extend(element.style, { - margin: 0, - padding: 0 - }) - } - - function resize () { - var w = window.innerWidth - var h = window.innerHeight - if (element !== document.body) { - var bounds = canvas.getBoundingClientRect() - w = bounds.right - bounds.left - h = bounds.bottom - bounds.top - } - canvas.width = pixelRatio * w - canvas.height = pixelRatio * h - } - - var resizeObserver - if (element !== document.body && typeof ResizeObserver === 'function') { - // ignore 'ResizeObserver' is not defined - // eslint-disable-next-line - resizeObserver = new ResizeObserver(function () { - // setTimeout to avoid flicker - setTimeout(resize) - }) - resizeObserver.observe(element) - } else { - window.addEventListener('resize', resize, false) - } - - function onDestroy () { - if (resizeObserver) { - resizeObserver.disconnect() - } else { - window.removeEventListener('resize', resize) - } - element.removeChild(canvas) - } - - resize() - - return { - canvas: canvas, - onDestroy: onDestroy - } -} - -function createContext (canvas, contextAttributes) { - function get (name) { - try { - return canvas.getContext(name, contextAttributes) - } catch (e) { - return null - } - } - return ( - get('webgl') || - get('experimental-webgl') || - get('webgl-experimental') - ) -} - -function isHTMLElement (obj) { - return ( - typeof obj.nodeName === 'string' && - typeof obj.appendChild === 'function' && - typeof obj.getBoundingClientRect === 'function' - ) -} - -function isWebGLContext (obj) { - return ( - typeof obj.drawArrays === 'function' || - typeof obj.drawElements === 'function' - ) -} - -function parseExtensions (input) { - if (typeof input === 'string') { - return input.split() - } - check$1(Array.isArray(input), 'invalid extension array') - return input -} - -function getElement (desc) { - if (typeof desc === 'string') { - check$1(typeof document !== 'undefined', 'not supported outside of DOM') - return document.querySelector(desc) - } - return desc -} - -function parseArgs (args_) { - var args = args_ || {} - var element, container, canvas, gl - var contextAttributes = {} - var extensions = [] - var optionalExtensions = [] - var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio) - var profile = false - var onDone = function (err) { - if (err) { - check$1.raise(err) - } - } - var onDestroy = function () {} - if (typeof args === 'string') { - check$1( - typeof document !== 'undefined', - 'selector queries only supported in DOM environments') - element = document.querySelector(args) - check$1(element, 'invalid query string for element') - } else if (typeof args === 'object') { - if (isHTMLElement(args)) { - element = args - } else if (isWebGLContext(args)) { - gl = args - canvas = gl.canvas - } else { - check$1.constructor(args) - if ('gl' in args) { - gl = args.gl - } else if ('canvas' in args) { - canvas = getElement(args.canvas) - } else if ('container' in args) { - container = getElement(args.container) - } - if ('attributes' in args) { - contextAttributes = args.attributes - check$1.type(contextAttributes, 'object', 'invalid context attributes') - } - if ('extensions' in args) { - extensions = parseExtensions(args.extensions) - } - if ('optionalExtensions' in args) { - optionalExtensions = parseExtensions(args.optionalExtensions) - } - if ('onDone' in args) { - check$1.type( - args.onDone, 'function', - 'invalid or missing onDone callback') - onDone = args.onDone - } - if ('profile' in args) { - profile = !!args.profile - } - if ('pixelRatio' in args) { - pixelRatio = +args.pixelRatio - check$1(pixelRatio > 0, 'invalid pixel ratio') - } - } - } else { - check$1.raise('invalid arguments to regl') - } - - if (element) { - if (element.nodeName.toLowerCase() === 'canvas') { - canvas = element - } else { - container = element - } - } - - if (!gl) { - if (!canvas) { - check$1( - typeof document !== 'undefined', - 'must manually specify webgl context outside of DOM environments') - var result = createCanvas(container || document.body, onDone, pixelRatio) - if (!result) { - return null - } - canvas = result.canvas - onDestroy = result.onDestroy - } - // workaround for chromium bug, premultiplied alpha value is platform dependent - if (contextAttributes.premultipliedAlpha === undefined) contextAttributes.premultipliedAlpha = true - gl = createContext(canvas, contextAttributes) - } - - if (!gl) { - onDestroy() - onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org') - return null - } - - return { - gl: gl, - canvas: canvas, - container: container, - extensions: extensions, - optionalExtensions: optionalExtensions, - pixelRatio: pixelRatio, - profile: profile, - onDone: onDone, - onDestroy: onDestroy - } -} - -function createExtensionCache (gl, config) { - var extensions = {} - - function tryLoadExtension (name_) { - check$1.type(name_, 'string', 'extension name must be string') - var name = name_.toLowerCase() - var ext - try { - ext = extensions[name] = gl.getExtension(name) - } catch (e) {} - return !!ext - } - - for (var i = 0; i < config.extensions.length; ++i) { - var name = config.extensions[i] - if (!tryLoadExtension(name)) { - config.onDestroy() - config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser') - return null - } - } - - config.optionalExtensions.forEach(tryLoadExtension) - - return { - extensions: extensions, - restore: function () { - Object.keys(extensions).forEach(function (name) { - if (extensions[name] && !tryLoadExtension(name)) { - throw new Error('(regl): error restoring extension ' + name) - } - }) - } - } -} - -function loop (n, f) { - var result = Array(n) - for (var i = 0; i < n; ++i) { - result[i] = f(i) - } - return result -} - -var GL_BYTE$1 = 5120 -var GL_UNSIGNED_BYTE$2 = 5121 -var GL_SHORT$1 = 5122 -var GL_UNSIGNED_SHORT$1 = 5123 -var GL_INT$1 = 5124 -var GL_UNSIGNED_INT$1 = 5125 -var GL_FLOAT$2 = 5126 - -function nextPow16 (v) { - for (var i = 16; i <= (1 << 28); i *= 16) { - if (v <= i) { - return i - } - } - return 0 -} - -function log2 (v) { - var r, shift - r = (v > 0xFFFF) << 4 - v >>>= r - shift = (v > 0xFF) << 3 - v >>>= shift; r |= shift - shift = (v > 0xF) << 2 - v >>>= shift; r |= shift - shift = (v > 0x3) << 1 - v >>>= shift; r |= shift - return r | (v >> 1) -} - -function createPool () { - var bufferPool = loop(8, function () { - return [] - }) - - function alloc (n) { - var sz = nextPow16(n) - var bin = bufferPool[log2(sz) >> 2] - if (bin.length > 0) { - return bin.pop() - } - return new ArrayBuffer(sz) - } - - function free (buf) { - bufferPool[log2(buf.byteLength) >> 2].push(buf) - } - - function allocType (type, n) { - var result = null - switch (type) { - case GL_BYTE$1: - result = new Int8Array(alloc(n), 0, n) - break - case GL_UNSIGNED_BYTE$2: - result = new Uint8Array(alloc(n), 0, n) - break - case GL_SHORT$1: - result = new Int16Array(alloc(2 * n), 0, n) - break - case GL_UNSIGNED_SHORT$1: - result = new Uint16Array(alloc(2 * n), 0, n) - break - case GL_INT$1: - result = new Int32Array(alloc(4 * n), 0, n) - break - case GL_UNSIGNED_INT$1: - result = new Uint32Array(alloc(4 * n), 0, n) - break - case GL_FLOAT$2: - result = new Float32Array(alloc(4 * n), 0, n) - break - default: - return null - } - if (result.length !== n) { - return result.subarray(0, n) - } - return result - } - - function freeType (array) { - free(array.buffer) - } - - return { - alloc: alloc, - free: free, - allocType: allocType, - freeType: freeType - } -} - -var pool = createPool() - -// zero pool for initial zero data -pool.zero = createPool() - -var GL_SUBPIXEL_BITS = 0x0D50 -var GL_RED_BITS = 0x0D52 -var GL_GREEN_BITS = 0x0D53 -var GL_BLUE_BITS = 0x0D54 -var GL_ALPHA_BITS = 0x0D55 -var GL_DEPTH_BITS = 0x0D56 -var GL_STENCIL_BITS = 0x0D57 - -var GL_ALIASED_POINT_SIZE_RANGE = 0x846D -var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E - -var GL_MAX_TEXTURE_SIZE = 0x0D33 -var GL_MAX_VIEWPORT_DIMS = 0x0D3A -var GL_MAX_VERTEX_ATTRIBS = 0x8869 -var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB -var GL_MAX_VARYING_VECTORS = 0x8DFC -var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D -var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C -var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872 -var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD -var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C -var GL_MAX_RENDERBUFFER_SIZE = 0x84E8 - -var GL_VENDOR = 0x1F00 -var GL_RENDERER = 0x1F01 -var GL_VERSION = 0x1F02 -var GL_SHADING_LANGUAGE_VERSION = 0x8B8C - -var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF - -var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF -var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824 - -var GL_TEXTURE_2D = 0x0DE1 -var GL_TEXTURE_CUBE_MAP = 0x8513 -var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515 -var GL_TEXTURE0 = 0x84C0 -var GL_RGBA = 0x1908 -var GL_FLOAT$1 = 0x1406 -var GL_UNSIGNED_BYTE$1 = 0x1401 -var GL_FRAMEBUFFER = 0x8D40 -var GL_FRAMEBUFFER_COMPLETE = 0x8CD5 -var GL_COLOR_ATTACHMENT0 = 0x8CE0 -var GL_COLOR_BUFFER_BIT$1 = 0x4000 - -var wrapLimits = function (gl, extensions) { - var maxAnisotropic = 1 - if (extensions.ext_texture_filter_anisotropic) { - maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) - } - - var maxDrawbuffers = 1 - var maxColorAttachments = 1 - if (extensions.webgl_draw_buffers) { - maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL) - maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL) - } - - // detect if reading float textures is available (Safari doesn't support) - var readFloat = !!extensions.oes_texture_float - if (readFloat) { - var readFloatTexture = gl.createTexture() - gl.bindTexture(GL_TEXTURE_2D, readFloatTexture) - gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_FLOAT$1, null) - - var fbo = gl.createFramebuffer() - gl.bindFramebuffer(GL_FRAMEBUFFER, fbo) - gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, readFloatTexture, 0) - gl.bindTexture(GL_TEXTURE_2D, null) - - if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) !== GL_FRAMEBUFFER_COMPLETE) readFloat = false - - else { - gl.viewport(0, 0, 1, 1) - gl.clearColor(1.0, 0.0, 0.0, 1.0) - gl.clear(GL_COLOR_BUFFER_BIT$1) - var pixels = pool.allocType(GL_FLOAT$1, 4) - gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT$1, pixels) - - if (gl.getError()) readFloat = false - else { - gl.deleteFramebuffer(fbo) - gl.deleteTexture(readFloatTexture) - - readFloat = pixels[0] === 1.0 - } - - pool.freeType(pixels) - } - } - - // detect non power of two cube textures support (IE doesn't support) - var isIE = typeof navigator !== 'undefined' && (/MSIE/.test(navigator.userAgent) || /Trident\//.test(navigator.appVersion) || /Edge/.test(navigator.userAgent)) - - var npotTextureCube = true - - if (!isIE) { - var cubeTexture = gl.createTexture() - var data = pool.allocType(GL_UNSIGNED_BYTE$1, 36) - gl.activeTexture(GL_TEXTURE0) - gl.bindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture) - gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE$1, data) - pool.freeType(data) - gl.bindTexture(GL_TEXTURE_CUBE_MAP, null) - gl.deleteTexture(cubeTexture) - npotTextureCube = !gl.getError() - } - - return { - // drawing buffer bit depth - colorBits: [ - gl.getParameter(GL_RED_BITS), - gl.getParameter(GL_GREEN_BITS), - gl.getParameter(GL_BLUE_BITS), - gl.getParameter(GL_ALPHA_BITS) - ], - depthBits: gl.getParameter(GL_DEPTH_BITS), - stencilBits: gl.getParameter(GL_STENCIL_BITS), - subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS), - - // supported extensions - extensions: Object.keys(extensions).filter(function (ext) { - return !!extensions[ext] - }), - - // max aniso samples - maxAnisotropic: maxAnisotropic, - - // max draw buffers - maxDrawbuffers: maxDrawbuffers, - maxColorAttachments: maxColorAttachments, - - // point and line size ranges - pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE), - lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE), - maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS), - maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS), - maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE), - maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE), - maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS), - maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE), - maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS), - maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS), - maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS), - maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS), - maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS), - - // vendor info - glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION), - renderer: gl.getParameter(GL_RENDERER), - vendor: gl.getParameter(GL_VENDOR), - version: gl.getParameter(GL_VERSION), - - // quirks - readFloat: readFloat, - npotTextureCube: npotTextureCube - } -} - -function isNDArrayLike (obj) { - return ( - !!obj && - typeof obj === 'object' && - Array.isArray(obj.shape) && - Array.isArray(obj.stride) && - typeof obj.offset === 'number' && - obj.shape.length === obj.stride.length && - (Array.isArray(obj.data) || - isTypedArray(obj.data))) -} - -var values = function (obj) { - return Object.keys(obj).map(function (key) { return obj[key] }) -} - -var flattenUtils = { - shape: arrayShape$1, - flatten: flattenArray -}; - -function flatten1D (array, nx, out) { - for (var i = 0; i < nx; ++i) { - out[i] = array[i] - } -} - -function flatten2D (array, nx, ny, out) { - var ptr = 0 - for (var i = 0; i < nx; ++i) { - var row = array[i] - for (var j = 0; j < ny; ++j) { - out[ptr++] = row[j] - } - } -} - -function flatten3D (array, nx, ny, nz, out, ptr_) { - var ptr = ptr_ - for (var i = 0; i < nx; ++i) { - var row = array[i] - for (var j = 0; j < ny; ++j) { - var col = row[j] - for (var k = 0; k < nz; ++k) { - out[ptr++] = col[k] - } - } - } -} - -function flattenRec (array, shape, level, out, ptr) { - var stride = 1 - for (var i = level + 1; i < shape.length; ++i) { - stride *= shape[i] - } - var n = shape[level] - if (shape.length - level === 4) { - var nx = shape[level + 1] - var ny = shape[level + 2] - var nz = shape[level + 3] - for (i = 0; i < n; ++i) { - flatten3D(array[i], nx, ny, nz, out, ptr) - ptr += stride - } - } else { - for (i = 0; i < n; ++i) { - flattenRec(array[i], shape, level + 1, out, ptr) - ptr += stride - } - } -} - -function flattenArray (array, shape, type, out_) { - var sz = 1 - if (shape.length) { - for (var i = 0; i < shape.length; ++i) { - sz *= shape[i] - } - } else { - sz = 0 - } - var out = out_ || pool.allocType(type, sz) - switch (shape.length) { - case 0: - break - case 1: - flatten1D(array, shape[0], out) - break - case 2: - flatten2D(array, shape[0], shape[1], out) - break - case 3: - flatten3D(array, shape[0], shape[1], shape[2], out, 0) - break - default: - flattenRec(array, shape, 0, out, 0) - } - return out -} - -function arrayShape$1 (array_) { - var shape = [] - for (var array = array_; array.length; array = array[0]) { - shape.push(array.length) - } - return shape -} - -var arrayTypes = { - "[object Int8Array]": 5120, - "[object Int16Array]": 5122, - "[object Int32Array]": 5124, - "[object Uint8Array]": 5121, - "[object Uint8ClampedArray]": 5121, - "[object Uint16Array]": 5123, - "[object Uint32Array]": 5125, - "[object Float32Array]": 5126, - "[object Float64Array]": 5121, - "[object ArrayBuffer]": 5121 -}; - -var int8 = 5120; -var int16 = 5122; -var int32 = 5124; -var uint8 = 5121; -var uint16 = 5123; -var uint32 = 5125; -var float = 5126; -var float32 = 5126; -var glTypes = { - int8: int8, - int16: int16, - int32: int32, - uint8: uint8, - uint16: uint16, - uint32: uint32, - float: float, - float32: float32 -}; - -var dynamic$1 = 35048; -var stream = 35040; -var usageTypes = { - dynamic: dynamic$1, - stream: stream, - "static": 35044 -}; - -var arrayFlatten = flattenUtils.flatten -var arrayShape = flattenUtils.shape - -var GL_STATIC_DRAW = 0x88E4 -var GL_STREAM_DRAW = 0x88E0 - -var GL_UNSIGNED_BYTE$3 = 5121 -var GL_FLOAT$3 = 5126 - -var DTYPES_SIZES = [] -DTYPES_SIZES[5120] = 1 // int8 -DTYPES_SIZES[5122] = 2 // int16 -DTYPES_SIZES[5124] = 4 // int32 -DTYPES_SIZES[5121] = 1 // uint8 -DTYPES_SIZES[5123] = 2 // uint16 -DTYPES_SIZES[5125] = 4 // uint32 -DTYPES_SIZES[5126] = 4 // float32 - -function typedArrayCode (data) { - return arrayTypes[Object.prototype.toString.call(data)] | 0 -} - -function copyArray (out, inp) { - for (var i = 0; i < inp.length; ++i) { - out[i] = inp[i] - } -} - -function transpose ( - result, data, shapeX, shapeY, strideX, strideY, offset) { - var ptr = 0 - for (var i = 0; i < shapeX; ++i) { - for (var j = 0; j < shapeY; ++j) { - result[ptr++] = data[strideX * i + strideY * j + offset] - } - } -} - -function wrapBufferState (gl, stats, config, destroyBuffer) { - var bufferCount = 0 - var bufferSet = {} - - function REGLBuffer (type) { - this.id = bufferCount++ - this.buffer = gl.createBuffer() - this.type = type - this.usage = GL_STATIC_DRAW - this.byteLength = 0 - this.dimension = 1 - this.dtype = GL_UNSIGNED_BYTE$3 - - this.persistentData = null - - if (config.profile) { - this.stats = { size: 0 } - } - } - - REGLBuffer.prototype.bind = function () { - gl.bindBuffer(this.type, this.buffer) - } - - REGLBuffer.prototype.destroy = function () { - destroy(this) - } - - var streamPool = [] - - function createStream (type, data) { - var buffer = streamPool.pop() - if (!buffer) { - buffer = new REGLBuffer(type) - } - buffer.bind() - initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false) - return buffer - } - - function destroyStream (stream$$1) { - streamPool.push(stream$$1) - } - - function initBufferFromTypedArray (buffer, data, usage) { - buffer.byteLength = data.byteLength - gl.bufferData(buffer.type, data, usage) - } - - function initBufferFromData (buffer, data, usage, dtype, dimension, persist) { - var shape - buffer.usage = usage - if (Array.isArray(data)) { - buffer.dtype = dtype || GL_FLOAT$3 - if (data.length > 0) { - var flatData - if (Array.isArray(data[0])) { - shape = arrayShape(data) - var dim = 1 - for (var i = 1; i < shape.length; ++i) { - dim *= shape[i] - } - buffer.dimension = dim - flatData = arrayFlatten(data, shape, buffer.dtype) - initBufferFromTypedArray(buffer, flatData, usage) - if (persist) { - buffer.persistentData = flatData - } else { - pool.freeType(flatData) - } - } else if (typeof data[0] === 'number') { - buffer.dimension = dimension - var typedData = pool.allocType(buffer.dtype, data.length) - copyArray(typedData, data) - initBufferFromTypedArray(buffer, typedData, usage) - if (persist) { - buffer.persistentData = typedData - } else { - pool.freeType(typedData) - } - } else if (isTypedArray(data[0])) { - buffer.dimension = data[0].length - buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT$3 - flatData = arrayFlatten( - data, - [data.length, data[0].length], - buffer.dtype) - initBufferFromTypedArray(buffer, flatData, usage) - if (persist) { - buffer.persistentData = flatData - } else { - pool.freeType(flatData) - } - } else { - check$1.raise('invalid buffer data') - } - } - } else if (isTypedArray(data)) { - buffer.dtype = dtype || typedArrayCode(data) - buffer.dimension = dimension - initBufferFromTypedArray(buffer, data, usage) - if (persist) { - buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer)) - } - } else if (isNDArrayLike(data)) { - shape = data.shape - var stride = data.stride - var offset = data.offset - - var shapeX = 0 - var shapeY = 0 - var strideX = 0 - var strideY = 0 - if (shape.length === 1) { - shapeX = shape[0] - shapeY = 1 - strideX = stride[0] - strideY = 0 - } else if (shape.length === 2) { - shapeX = shape[0] - shapeY = shape[1] - strideX = stride[0] - strideY = stride[1] - } else { - check$1.raise('invalid shape') - } - - buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$3 - buffer.dimension = shapeY - - var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY) - transpose(transposeData, - data.data, - shapeX, shapeY, - strideX, strideY, - offset) - initBufferFromTypedArray(buffer, transposeData, usage) - if (persist) { - buffer.persistentData = transposeData - } else { - pool.freeType(transposeData) - } - } else if (data instanceof ArrayBuffer) { - buffer.dtype = GL_UNSIGNED_BYTE$3 - buffer.dimension = dimension - initBufferFromTypedArray(buffer, data, usage) - if (persist) { - buffer.persistentData = new Uint8Array(new Uint8Array(data)) - } - } else { - check$1.raise('invalid buffer data') - } - } - - function destroy (buffer) { - stats.bufferCount-- - - // remove attribute link - destroyBuffer(buffer) - - var handle = buffer.buffer - check$1(handle, 'buffer must not be deleted already') - gl.deleteBuffer(handle) - buffer.buffer = null - delete bufferSet[buffer.id] - } - - function createBuffer (options, type, deferInit, persistent) { - stats.bufferCount++ - - var buffer = new REGLBuffer(type) - bufferSet[buffer.id] = buffer - - function reglBuffer (options) { - var usage = GL_STATIC_DRAW - var data = null - var byteLength = 0 - var dtype = 0 - var dimension = 1 - if (Array.isArray(options) || - isTypedArray(options) || - isNDArrayLike(options) || - options instanceof ArrayBuffer) { - data = options - } else if (typeof options === 'number') { - byteLength = options | 0 - } else if (options) { - check$1.type( - options, 'object', - 'buffer arguments must be an object, a number or an array') - - if ('data' in options) { - check$1( - data === null || - Array.isArray(data) || - isTypedArray(data) || - isNDArrayLike(data), - 'invalid data for buffer') - data = options.data - } - - if ('usage' in options) { - check$1.parameter(options.usage, usageTypes, 'invalid buffer usage') - usage = usageTypes[options.usage] - } - - if ('type' in options) { - check$1.parameter(options.type, glTypes, 'invalid buffer type') - dtype = glTypes[options.type] - } - - if ('dimension' in options) { - check$1.type(options.dimension, 'number', 'invalid dimension') - dimension = options.dimension | 0 - } - - if ('length' in options) { - check$1.nni(byteLength, 'buffer length must be a nonnegative integer') - byteLength = options.length | 0 - } - } - - buffer.bind() - if (!data) { - // #475 - if (byteLength) gl.bufferData(buffer.type, byteLength, usage) - buffer.dtype = dtype || GL_UNSIGNED_BYTE$3 - buffer.usage = usage - buffer.dimension = dimension - buffer.byteLength = byteLength - } else { - initBufferFromData(buffer, data, usage, dtype, dimension, persistent) - } - - if (config.profile) { - buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype] - } - - return reglBuffer - } - - function setSubData (data, offset) { - check$1(offset + data.byteLength <= buffer.byteLength, - 'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength) - - gl.bufferSubData(buffer.type, offset, data) - } - - function subdata (data, offset_) { - var offset = (offset_ || 0) | 0 - var shape - buffer.bind() - if (isTypedArray(data) || data instanceof ArrayBuffer) { - setSubData(data, offset) - } else if (Array.isArray(data)) { - if (data.length > 0) { - if (typeof data[0] === 'number') { - var converted = pool.allocType(buffer.dtype, data.length) - copyArray(converted, data) - setSubData(converted, offset) - pool.freeType(converted) - } else if (Array.isArray(data[0]) || isTypedArray(data[0])) { - shape = arrayShape(data) - var flatData = arrayFlatten(data, shape, buffer.dtype) - setSubData(flatData, offset) - pool.freeType(flatData) - } else { - check$1.raise('invalid buffer data') - } - } - } else if (isNDArrayLike(data)) { - shape = data.shape - var stride = data.stride - - var shapeX = 0 - var shapeY = 0 - var strideX = 0 - var strideY = 0 - if (shape.length === 1) { - shapeX = shape[0] - shapeY = 1 - strideX = stride[0] - strideY = 0 - } else if (shape.length === 2) { - shapeX = shape[0] - shapeY = shape[1] - strideX = stride[0] - strideY = stride[1] - } else { - check$1.raise('invalid shape') - } - var dtype = Array.isArray(data.data) - ? buffer.dtype - : typedArrayCode(data.data) - - var transposeData = pool.allocType(dtype, shapeX * shapeY) - transpose(transposeData, - data.data, - shapeX, shapeY, - strideX, strideY, - data.offset) - setSubData(transposeData, offset) - pool.freeType(transposeData) - } else { - check$1.raise('invalid data for buffer subdata') - } - return reglBuffer - } - - if (!deferInit) { - reglBuffer(options) - } - - reglBuffer._reglType = 'buffer' - reglBuffer._buffer = buffer - reglBuffer.subdata = subdata - if (config.profile) { - reglBuffer.stats = buffer.stats - } - reglBuffer.destroy = function () { destroy(buffer) } - - return reglBuffer - } - - function restoreBuffers () { - values(bufferSet).forEach(function (buffer) { - buffer.buffer = gl.createBuffer() - gl.bindBuffer(buffer.type, buffer.buffer) - gl.bufferData( - buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage) - }) - } - - if (config.profile) { - stats.getTotalBufferSize = function () { - var total = 0 - // TODO: Right now, the streams are not part of the total count. - Object.keys(bufferSet).forEach(function (key) { - total += bufferSet[key].stats.size - }) - return total - } - } - - return { - create: createBuffer, - - createStream: createStream, - destroyStream: destroyStream, - - clear: function () { - values(bufferSet).forEach(destroy) - streamPool.forEach(destroy) - }, - - getBuffer: function (wrapper) { - if (wrapper && wrapper._buffer instanceof REGLBuffer) { - return wrapper._buffer - } - return null - }, - - restore: restoreBuffers, - - _initBuffer: initBufferFromData - } -} - -var points = 0; -var point = 0; -var lines = 1; -var line = 1; -var triangles = 4; -var triangle = 4; -var primTypes = { - points: points, - point: point, - lines: lines, - line: line, - triangles: triangles, - triangle: triangle, - "line loop": 2, - "line strip": 3, - "triangle strip": 5, - "triangle fan": 6 -}; - -var GL_POINTS = 0 -var GL_LINES = 1 -var GL_TRIANGLES = 4 - -var GL_BYTE$2 = 5120 -var GL_UNSIGNED_BYTE$4 = 5121 -var GL_SHORT$2 = 5122 -var GL_UNSIGNED_SHORT$2 = 5123 -var GL_INT$2 = 5124 -var GL_UNSIGNED_INT$2 = 5125 - -var GL_ELEMENT_ARRAY_BUFFER = 34963 - -var GL_STREAM_DRAW$1 = 0x88E0 -var GL_STATIC_DRAW$1 = 0x88E4 - -function wrapElementsState (gl, extensions, bufferState, stats) { - var elementSet = {} - var elementCount = 0 - - var elementTypes = { - 'uint8': GL_UNSIGNED_BYTE$4, - 'uint16': GL_UNSIGNED_SHORT$2 - } - - if (extensions.oes_element_index_uint) { - elementTypes.uint32 = GL_UNSIGNED_INT$2 - } - - function REGLElementBuffer (buffer) { - this.id = elementCount++ - elementSet[this.id] = this - this.buffer = buffer - this.primType = GL_TRIANGLES - this.vertCount = 0 - this.type = 0 - } - - REGLElementBuffer.prototype.bind = function () { - this.buffer.bind() - } - - var bufferPool = [] - - function createElementStream (data) { - var result = bufferPool.pop() - if (!result) { - result = new REGLElementBuffer(bufferState.create( - null, - GL_ELEMENT_ARRAY_BUFFER, - true, - false)._buffer) - } - initElements(result, data, GL_STREAM_DRAW$1, -1, -1, 0, 0) - return result - } - - function destroyElementStream (elements) { - bufferPool.push(elements) - } - - function initElements ( - elements, - data, - usage, - prim, - count, - byteLength, - type) { - elements.buffer.bind() - var dtype - if (data) { - var predictedType = type - if (!type && ( - !isTypedArray(data) || - (isNDArrayLike(data) && !isTypedArray(data.data)))) { - predictedType = extensions.oes_element_index_uint - ? GL_UNSIGNED_INT$2 - : GL_UNSIGNED_SHORT$2 - } - bufferState._initBuffer( - elements.buffer, - data, - usage, - predictedType, - 3) - } else { - gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage) - elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$4 - elements.buffer.usage = usage - elements.buffer.dimension = 3 - elements.buffer.byteLength = byteLength - } - - dtype = type - if (!type) { - switch (elements.buffer.dtype) { - case GL_UNSIGNED_BYTE$4: - case GL_BYTE$2: - dtype = GL_UNSIGNED_BYTE$4 - break - - case GL_UNSIGNED_SHORT$2: - case GL_SHORT$2: - dtype = GL_UNSIGNED_SHORT$2 - break - - case GL_UNSIGNED_INT$2: - case GL_INT$2: - dtype = GL_UNSIGNED_INT$2 - break - - default: - check$1.raise('unsupported type for element array') - } - elements.buffer.dtype = dtype - } - elements.type = dtype - - // Check oes_element_index_uint extension - check$1( - dtype !== GL_UNSIGNED_INT$2 || - !!extensions.oes_element_index_uint, - '32 bit element buffers not supported, enable oes_element_index_uint first') - - // try to guess default primitive type and arguments - var vertCount = count - if (vertCount < 0) { - vertCount = elements.buffer.byteLength - if (dtype === GL_UNSIGNED_SHORT$2) { - vertCount >>= 1 - } else if (dtype === GL_UNSIGNED_INT$2) { - vertCount >>= 2 - } - } - elements.vertCount = vertCount - - // try to guess primitive type from cell dimension - var primType = prim - if (prim < 0) { - primType = GL_TRIANGLES - var dimension = elements.buffer.dimension - if (dimension === 1) primType = GL_POINTS - if (dimension === 2) primType = GL_LINES - if (dimension === 3) primType = GL_TRIANGLES - } - elements.primType = primType - } - - function destroyElements (elements) { - stats.elementsCount-- - - check$1(elements.buffer !== null, 'must not double destroy elements') - delete elementSet[elements.id] - elements.buffer.destroy() - elements.buffer = null - } - - function createElements (options, persistent) { - var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true) - var elements = new REGLElementBuffer(buffer._buffer) - stats.elementsCount++ - - function reglElements (options) { - if (!options) { - buffer() - elements.primType = GL_TRIANGLES - elements.vertCount = 0 - elements.type = GL_UNSIGNED_BYTE$4 - } else if (typeof options === 'number') { - buffer(options) - elements.primType = GL_TRIANGLES - elements.vertCount = options | 0 - elements.type = GL_UNSIGNED_BYTE$4 - } else { - var data = null - var usage = GL_STATIC_DRAW$1 - var primType = -1 - var vertCount = -1 - var byteLength = 0 - var dtype = 0 - if (Array.isArray(options) || - isTypedArray(options) || - isNDArrayLike(options)) { - data = options - } else { - check$1.type(options, 'object', 'invalid arguments for elements') - if ('data' in options) { - data = options.data - check$1( - Array.isArray(data) || - isTypedArray(data) || - isNDArrayLike(data), - 'invalid data for element buffer') - } - if ('usage' in options) { - check$1.parameter( - options.usage, - usageTypes, - 'invalid element buffer usage') - usage = usageTypes[options.usage] - } - if ('primitive' in options) { - check$1.parameter( - options.primitive, - primTypes, - 'invalid element buffer primitive') - primType = primTypes[options.primitive] - } - if ('count' in options) { - check$1( - typeof options.count === 'number' && options.count >= 0, - 'invalid vertex count for elements') - vertCount = options.count | 0 - } - if ('type' in options) { - check$1.parameter( - options.type, - elementTypes, - 'invalid buffer type') - dtype = elementTypes[options.type] - } - if ('length' in options) { - byteLength = options.length | 0 - } else { - byteLength = vertCount - if (dtype === GL_UNSIGNED_SHORT$2 || dtype === GL_SHORT$2) { - byteLength *= 2 - } else if (dtype === GL_UNSIGNED_INT$2 || dtype === GL_INT$2) { - byteLength *= 4 - } - } - } - initElements( - elements, - data, - usage, - primType, - vertCount, - byteLength, - dtype) - } - - return reglElements - } - - reglElements(options) - - reglElements._reglType = 'elements' - reglElements._elements = elements - reglElements.subdata = function (data, offset) { - buffer.subdata(data, offset) - return reglElements - } - reglElements.destroy = function () { - destroyElements(elements) - } - - return reglElements - } - - return { - create: createElements, - createStream: createElementStream, - destroyStream: destroyElementStream, - getElements: function (elements) { - if (typeof elements === 'function' && - elements._elements instanceof REGLElementBuffer) { - return elements._elements - } - return null - }, - clear: function () { - values(elementSet).forEach(destroyElements) - } - } -} - -var FLOAT = new Float32Array(1) -var INT = new Uint32Array(FLOAT.buffer) - -var GL_UNSIGNED_SHORT$4 = 5123 - -function convertToHalfFloat (array) { - var ushorts = pool.allocType(GL_UNSIGNED_SHORT$4, array.length) - - for (var i = 0; i < array.length; ++i) { - if (isNaN(array[i])) { - ushorts[i] = 0xffff - } else if (array[i] === Infinity) { - ushorts[i] = 0x7c00 - } else if (array[i] === -Infinity) { - ushorts[i] = 0xfc00 - } else { - FLOAT[0] = array[i] - var x = INT[0] - - var sgn = (x >>> 31) << 15 - var exp = ((x << 1) >>> 24) - 127 - var frac = (x >> 13) & ((1 << 10) - 1) - - if (exp < -24) { - // round non-representable denormals to 0 - ushorts[i] = sgn - } else if (exp < -14) { - // handle denormals - var s = -14 - exp - ushorts[i] = sgn + ((frac + (1 << 10)) >> s) - } else if (exp > 15) { - // round overflow to +/- Infinity - ushorts[i] = sgn + 0x7c00 - } else { - // otherwise convert directly - ushorts[i] = sgn + ((exp + 15) << 10) + frac - } - } - } - - return ushorts -} - -function isArrayLike (s) { - return Array.isArray(s) || isTypedArray(s) -} - -var isPow2$1 = function (v) { - return !(v & (v - 1)) && (!!v) -} - -var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3 - -var GL_TEXTURE_2D$1 = 0x0DE1 -var GL_TEXTURE_CUBE_MAP$1 = 0x8513 -var GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 = 0x8515 - -var GL_RGBA$1 = 0x1908 -var GL_ALPHA = 0x1906 -var GL_RGB = 0x1907 -var GL_LUMINANCE = 0x1909 -var GL_LUMINANCE_ALPHA = 0x190A - -var GL_RGBA4 = 0x8056 -var GL_RGB5_A1 = 0x8057 -var GL_RGB565 = 0x8D62 - -var GL_UNSIGNED_SHORT_4_4_4_4$1 = 0x8033 -var GL_UNSIGNED_SHORT_5_5_5_1$1 = 0x8034 -var GL_UNSIGNED_SHORT_5_6_5$1 = 0x8363 -var GL_UNSIGNED_INT_24_8_WEBGL$1 = 0x84FA - -var GL_DEPTH_COMPONENT = 0x1902 -var GL_DEPTH_STENCIL = 0x84F9 - -var GL_SRGB_EXT = 0x8C40 -var GL_SRGB_ALPHA_EXT = 0x8C42 - -var GL_HALF_FLOAT_OES$1 = 0x8D61 - -var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0 -var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1 -var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2 -var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3 - -var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92 -var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93 -var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE - -var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00 -var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01 -var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02 -var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03 - -var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64 - -var GL_UNSIGNED_BYTE$5 = 0x1401 -var GL_UNSIGNED_SHORT$3 = 0x1403 -var GL_UNSIGNED_INT$3 = 0x1405 -var GL_FLOAT$4 = 0x1406 - -var GL_TEXTURE_WRAP_S = 0x2802 -var GL_TEXTURE_WRAP_T = 0x2803 - -var GL_REPEAT = 0x2901 -var GL_CLAMP_TO_EDGE$1 = 0x812F -var GL_MIRRORED_REPEAT = 0x8370 - -var GL_TEXTURE_MAG_FILTER = 0x2800 -var GL_TEXTURE_MIN_FILTER = 0x2801 - -var GL_NEAREST$1 = 0x2600 -var GL_LINEAR = 0x2601 -var GL_NEAREST_MIPMAP_NEAREST$1 = 0x2700 -var GL_LINEAR_MIPMAP_NEAREST$1 = 0x2701 -var GL_NEAREST_MIPMAP_LINEAR$1 = 0x2702 -var GL_LINEAR_MIPMAP_LINEAR$1 = 0x2703 - -var GL_GENERATE_MIPMAP_HINT = 0x8192 -var GL_DONT_CARE = 0x1100 -var GL_FASTEST = 0x1101 -var GL_NICEST = 0x1102 - -var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE - -var GL_UNPACK_ALIGNMENT = 0x0CF5 -var GL_UNPACK_FLIP_Y_WEBGL = 0x9240 -var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241 -var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243 - -var GL_BROWSER_DEFAULT_WEBGL = 0x9244 - -var GL_TEXTURE0$1 = 0x84C0 - -var MIPMAP_FILTERS = [ - GL_NEAREST_MIPMAP_NEAREST$1, - GL_NEAREST_MIPMAP_LINEAR$1, - GL_LINEAR_MIPMAP_NEAREST$1, - GL_LINEAR_MIPMAP_LINEAR$1 -] - -var CHANNELS_FORMAT = [ - 0, - GL_LUMINANCE, - GL_LUMINANCE_ALPHA, - GL_RGB, - GL_RGBA$1 -] - -var FORMAT_CHANNELS = {} -FORMAT_CHANNELS[GL_LUMINANCE] = -FORMAT_CHANNELS[GL_ALPHA] = -FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1 -FORMAT_CHANNELS[GL_DEPTH_STENCIL] = -FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2 -FORMAT_CHANNELS[GL_RGB] = -FORMAT_CHANNELS[GL_SRGB_EXT] = 3 -FORMAT_CHANNELS[GL_RGBA$1] = -FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4 - -function objectName (str) { - return '[object ' + str + ']' -} - -var CANVAS_CLASS = objectName('HTMLCanvasElement') -var OFFSCREENCANVAS_CLASS = objectName('OffscreenCanvas') -var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D') -var BITMAP_CLASS = objectName('ImageBitmap') -var IMAGE_CLASS = objectName('HTMLImageElement') -var VIDEO_CLASS = objectName('HTMLVideoElement') - -var PIXEL_CLASSES = Object.keys(arrayTypes).concat([ - CANVAS_CLASS, - OFFSCREENCANVAS_CLASS, - CONTEXT2D_CLASS, - BITMAP_CLASS, - IMAGE_CLASS, - VIDEO_CLASS -]) - -// for every texture type, store -// the size in bytes. -var TYPE_SIZES = [] -TYPE_SIZES[GL_UNSIGNED_BYTE$5] = 1 -TYPE_SIZES[GL_FLOAT$4] = 4 -TYPE_SIZES[GL_HALF_FLOAT_OES$1] = 2 - -TYPE_SIZES[GL_UNSIGNED_SHORT$3] = 2 -TYPE_SIZES[GL_UNSIGNED_INT$3] = 4 - -var FORMAT_SIZES_SPECIAL = [] -FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2 -FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2 -FORMAT_SIZES_SPECIAL[GL_RGB565] = 2 -FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4 - -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1 - -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1 - -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5 -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25 - -FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5 - -function isNumericArray (arr) { - return ( - Array.isArray(arr) && - (arr.length === 0 || - typeof arr[0] === 'number')) -} - -function isRectArray (arr) { - if (!Array.isArray(arr)) { - return false - } - var width = arr.length - if (width === 0 || !isArrayLike(arr[0])) { - return false - } - return true -} - -function classString (x) { - return Object.prototype.toString.call(x) -} - -function isCanvasElement (object) { - return classString(object) === CANVAS_CLASS -} - -function isOffscreenCanvas (object) { - return classString(object) === OFFSCREENCANVAS_CLASS -} - -function isContext2D (object) { - return classString(object) === CONTEXT2D_CLASS -} - -function isBitmap (object) { - return classString(object) === BITMAP_CLASS -} - -function isImageElement (object) { - return classString(object) === IMAGE_CLASS -} - -function isVideoElement (object) { - return classString(object) === VIDEO_CLASS -} - -function isPixelData (object) { - if (!object) { - return false - } - var className = classString(object) - if (PIXEL_CLASSES.indexOf(className) >= 0) { - return true - } - return ( - isNumericArray(object) || - isRectArray(object) || - isNDArrayLike(object)) -} - -function typedArrayCode$1 (data) { - return arrayTypes[Object.prototype.toString.call(data)] | 0 -} - -function convertData (result, data) { - var n = data.length - switch (result.type) { - case GL_UNSIGNED_BYTE$5: - case GL_UNSIGNED_SHORT$3: - case GL_UNSIGNED_INT$3: - case GL_FLOAT$4: - var converted = pool.allocType(result.type, n) - converted.set(data) - result.data = converted - break - - case GL_HALF_FLOAT_OES$1: - result.data = convertToHalfFloat(data) - break - - default: - check$1.raise('unsupported texture type, must specify a typed array') - } -} - -function preConvert (image, n) { - return pool.allocType( - image.type === GL_HALF_FLOAT_OES$1 - ? GL_FLOAT$4 - : image.type, n) -} - -function postConvert (image, data) { - if (image.type === GL_HALF_FLOAT_OES$1) { - image.data = convertToHalfFloat(data) - pool.freeType(data) - } else { - image.data = data - } -} - -function transposeData (image, array, strideX, strideY, strideC, offset) { - var w = image.width - var h = image.height - var c = image.channels - var n = w * h * c - var data = preConvert(image, n) - - var p = 0 - for (var i = 0; i < h; ++i) { - for (var j = 0; j < w; ++j) { - for (var k = 0; k < c; ++k) { - data[p++] = array[strideX * j + strideY * i + strideC * k + offset] - } - } - } - - postConvert(image, data) -} - -function getTextureSize (format, type, width, height, isMipmap, isCube) { - var s - if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') { - // we have a special array for dealing with weird color formats such as RGB5A1 - s = FORMAT_SIZES_SPECIAL[format] - } else { - s = FORMAT_CHANNELS[format] * TYPE_SIZES[type] - } - - if (isCube) { - s *= 6 - } - - if (isMipmap) { - // compute the total size of all the mipmaps. - var total = 0 - - var w = width - while (w >= 1) { - // we can only use mipmaps on a square image, - // so we can simply use the width and ignore the height: - total += s * w * w - w /= 2 - } - return total - } else { - return s * width * height - } -} - -function createTextureSet ( - gl, extensions, limits, reglPoll, contextState, stats, config) { - // ------------------------------------------------------- - // Initialize constants and parameter tables here - // ------------------------------------------------------- - var mipmapHint = { - "don't care": GL_DONT_CARE, - 'dont care': GL_DONT_CARE, - 'nice': GL_NICEST, - 'fast': GL_FASTEST - } - - var wrapModes = { - 'repeat': GL_REPEAT, - 'clamp': GL_CLAMP_TO_EDGE$1, - 'mirror': GL_MIRRORED_REPEAT - } - - var magFilters = { - 'nearest': GL_NEAREST$1, - 'linear': GL_LINEAR - } - - var minFilters = extend({ - 'mipmap': GL_LINEAR_MIPMAP_LINEAR$1, - 'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST$1, - 'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST$1, - 'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR$1, - 'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR$1 - }, magFilters) - - var colorSpace = { - 'none': 0, - 'browser': GL_BROWSER_DEFAULT_WEBGL - } - - var textureTypes = { - 'uint8': GL_UNSIGNED_BYTE$5, - 'rgba4': GL_UNSIGNED_SHORT_4_4_4_4$1, - 'rgb565': GL_UNSIGNED_SHORT_5_6_5$1, - 'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1$1 - } - - var textureFormats = { - 'alpha': GL_ALPHA, - 'luminance': GL_LUMINANCE, - 'luminance alpha': GL_LUMINANCE_ALPHA, - 'rgb': GL_RGB, - 'rgba': GL_RGBA$1, - 'rgba4': GL_RGBA4, - 'rgb5 a1': GL_RGB5_A1, - 'rgb565': GL_RGB565 - } - - var compressedTextureFormats = {} - - if (extensions.ext_srgb) { - textureFormats.srgb = GL_SRGB_EXT - textureFormats.srgba = GL_SRGB_ALPHA_EXT - } - - if (extensions.oes_texture_float) { - textureTypes.float32 = textureTypes.float = GL_FLOAT$4 - } - - if (extensions.oes_texture_half_float) { - textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES$1 - } - - if (extensions.webgl_depth_texture) { - extend(textureFormats, { - 'depth': GL_DEPTH_COMPONENT, - 'depth stencil': GL_DEPTH_STENCIL - }) - - extend(textureTypes, { - 'uint16': GL_UNSIGNED_SHORT$3, - 'uint32': GL_UNSIGNED_INT$3, - 'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL$1 - }) - } - - if (extensions.webgl_compressed_texture_s3tc) { - extend(compressedTextureFormats, { - 'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - 'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - 'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - 'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - }) - } - - if (extensions.webgl_compressed_texture_atc) { - extend(compressedTextureFormats, { - 'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL, - 'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL, - 'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL - }) - } - - if (extensions.webgl_compressed_texture_pvrtc) { - extend(compressedTextureFormats, { - 'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG, - 'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG, - 'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, - 'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG - }) - } - - if (extensions.webgl_compressed_texture_etc1) { - compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL - } - - // Copy over all texture formats - var supportedCompressedFormats = Array.prototype.slice.call( - gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS)) - Object.keys(compressedTextureFormats).forEach(function (name) { - var format = compressedTextureFormats[name] - if (supportedCompressedFormats.indexOf(format) >= 0) { - textureFormats[name] = format - } - }) - - var supportedFormats = Object.keys(textureFormats) - limits.textureFormats = supportedFormats - - // associate with every format string its - // corresponding GL-value. - var textureFormatsInvert = [] - Object.keys(textureFormats).forEach(function (key) { - var val = textureFormats[key] - textureFormatsInvert[val] = key - }) - - // associate with every type string its - // corresponding GL-value. - var textureTypesInvert = [] - Object.keys(textureTypes).forEach(function (key) { - var val = textureTypes[key] - textureTypesInvert[val] = key - }) - - var magFiltersInvert = [] - Object.keys(magFilters).forEach(function (key) { - var val = magFilters[key] - magFiltersInvert[val] = key - }) - - var minFiltersInvert = [] - Object.keys(minFilters).forEach(function (key) { - var val = minFilters[key] - minFiltersInvert[val] = key - }) - - var wrapModesInvert = [] - Object.keys(wrapModes).forEach(function (key) { - var val = wrapModes[key] - wrapModesInvert[val] = key - }) - - // colorFormats[] gives the format (channels) associated to an - // internalformat - var colorFormats = supportedFormats.reduce(function (color, key) { - var glenum = textureFormats[key] - if (glenum === GL_LUMINANCE || - glenum === GL_ALPHA || - glenum === GL_LUMINANCE || - glenum === GL_LUMINANCE_ALPHA || - glenum === GL_DEPTH_COMPONENT || - glenum === GL_DEPTH_STENCIL || - (extensions.ext_srgb && - (glenum === GL_SRGB_EXT || - glenum === GL_SRGB_ALPHA_EXT))) { - color[glenum] = glenum - } else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) { - color[glenum] = GL_RGBA$1 - } else { - color[glenum] = GL_RGB - } - return color - }, {}) - - function TexFlags () { - // format info - this.internalformat = GL_RGBA$1 - this.format = GL_RGBA$1 - this.type = GL_UNSIGNED_BYTE$5 - this.compressed = false - - // pixel storage - this.premultiplyAlpha = false - this.flipY = false - this.unpackAlignment = 1 - this.colorSpace = GL_BROWSER_DEFAULT_WEBGL - - // shape info - this.width = 0 - this.height = 0 - this.channels = 0 - } - - function copyFlags (result, other) { - result.internalformat = other.internalformat - result.format = other.format - result.type = other.type - result.compressed = other.compressed - - result.premultiplyAlpha = other.premultiplyAlpha - result.flipY = other.flipY - result.unpackAlignment = other.unpackAlignment - result.colorSpace = other.colorSpace - - result.width = other.width - result.height = other.height - result.channels = other.channels - } - - function parseFlags (flags, options) { - if (typeof options !== 'object' || !options) { - return - } - - if ('premultiplyAlpha' in options) { - check$1.type(options.premultiplyAlpha, 'boolean', - 'invalid premultiplyAlpha') - flags.premultiplyAlpha = options.premultiplyAlpha - } - - if ('flipY' in options) { - check$1.type(options.flipY, 'boolean', - 'invalid texture flip') - flags.flipY = options.flipY - } - - if ('alignment' in options) { - check$1.oneOf(options.alignment, [1, 2, 4, 8], - 'invalid texture unpack alignment') - flags.unpackAlignment = options.alignment - } - - if ('colorSpace' in options) { - check$1.parameter(options.colorSpace, colorSpace, - 'invalid colorSpace') - flags.colorSpace = colorSpace[options.colorSpace] - } - - if ('type' in options) { - var type = options.type - check$1(extensions.oes_texture_float || - !(type === 'float' || type === 'float32'), - 'you must enable the OES_texture_float extension in order to use floating point textures.') - check$1(extensions.oes_texture_half_float || - !(type === 'half float' || type === 'float16'), - 'you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.') - check$1(extensions.webgl_depth_texture || - !(type === 'uint16' || type === 'uint32' || type === 'depth stencil'), - 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.') - check$1.parameter(type, textureTypes, - 'invalid texture type') - flags.type = textureTypes[type] - } - - var w = flags.width - var h = flags.height - var c = flags.channels - var hasChannels = false - if ('shape' in options) { - check$1(Array.isArray(options.shape) && options.shape.length >= 2, - 'shape must be an array') - w = options.shape[0] - h = options.shape[1] - if (options.shape.length === 3) { - c = options.shape[2] - check$1(c > 0 && c <= 4, 'invalid number of channels') - hasChannels = true - } - check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width') - check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height') - } else { - if ('radius' in options) { - w = h = options.radius - check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid radius') - } - if ('width' in options) { - w = options.width - check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width') - } - if ('height' in options) { - h = options.height - check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height') - } - if ('channels' in options) { - c = options.channels - check$1(c > 0 && c <= 4, 'invalid number of channels') - hasChannels = true - } - } - flags.width = w | 0 - flags.height = h | 0 - flags.channels = c | 0 - - var hasFormat = false - if ('format' in options) { - var formatStr = options.format - check$1(extensions.webgl_depth_texture || - !(formatStr === 'depth' || formatStr === 'depth stencil'), - 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.') - check$1.parameter(formatStr, textureFormats, - 'invalid texture format') - var internalformat = flags.internalformat = textureFormats[formatStr] - flags.format = colorFormats[internalformat] - if (formatStr in textureTypes) { - if (!('type' in options)) { - flags.type = textureTypes[formatStr] - } - } - if (formatStr in compressedTextureFormats) { - flags.compressed = true - } - hasFormat = true - } - - // Reconcile channels and format - if (!hasChannels && hasFormat) { - flags.channels = FORMAT_CHANNELS[flags.format] - } else if (hasChannels && !hasFormat) { - if (flags.channels !== CHANNELS_FORMAT[flags.format]) { - flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels] - } - } else if (hasFormat && hasChannels) { - check$1( - flags.channels === FORMAT_CHANNELS[flags.format], - 'number of channels inconsistent with specified format') - } - } - - function setFlags (flags) { - gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY) - gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha) - gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace) - gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment) - } - - // ------------------------------------------------------- - // Tex image data - // ------------------------------------------------------- - function TexImage () { - TexFlags.call(this) - - this.xOffset = 0 - this.yOffset = 0 - - // data - this.data = null - this.needsFree = false - - // html element - this.element = null - - // copyTexImage info - this.needsCopy = false - } - - function parseImage (image, options) { - var data = null - if (isPixelData(options)) { - data = options - } else if (options) { - check$1.type(options, 'object', 'invalid pixel data type') - parseFlags(image, options) - if ('x' in options) { - image.xOffset = options.x | 0 - } - if ('y' in options) { - image.yOffset = options.y | 0 - } - if (isPixelData(options.data)) { - data = options.data - } - } - - check$1( - !image.compressed || - data instanceof Uint8Array, - 'compressed texture data must be stored in a uint8array') - - if (options.copy) { - check$1(!data, 'can not specify copy and data field for the same texture') - var viewW = contextState.viewportWidth - var viewH = contextState.viewportHeight - image.width = image.width || (viewW - image.xOffset) - image.height = image.height || (viewH - image.yOffset) - image.needsCopy = true - check$1(image.xOffset >= 0 && image.xOffset < viewW && - image.yOffset >= 0 && image.yOffset < viewH && - image.width > 0 && image.width <= viewW && - image.height > 0 && image.height <= viewH, - 'copy texture read out of bounds') - } else if (!data) { - image.width = image.width || 1 - image.height = image.height || 1 - image.channels = image.channels || 4 - } else if (isTypedArray(data)) { - image.channels = image.channels || 4 - image.data = data - if (!('type' in options) && image.type === GL_UNSIGNED_BYTE$5) { - image.type = typedArrayCode$1(data) - } - } else if (isNumericArray(data)) { - image.channels = image.channels || 4 - convertData(image, data) - image.alignment = 1 - image.needsFree = true - } else if (isNDArrayLike(data)) { - var array = data.data - if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE$5) { - image.type = typedArrayCode$1(array) - } - var shape = data.shape - var stride = data.stride - var shapeX, shapeY, shapeC, strideX, strideY, strideC - if (shape.length === 3) { - shapeC = shape[2] - strideC = stride[2] - } else { - check$1(shape.length === 2, 'invalid ndarray pixel data, must be 2 or 3D') - shapeC = 1 - strideC = 1 - } - shapeX = shape[0] - shapeY = shape[1] - strideX = stride[0] - strideY = stride[1] - image.alignment = 1 - image.width = shapeX - image.height = shapeY - image.channels = shapeC - image.format = image.internalformat = CHANNELS_FORMAT[shapeC] - image.needsFree = true - transposeData(image, array, strideX, strideY, strideC, data.offset) - } else if (isCanvasElement(data) || isOffscreenCanvas(data) || isContext2D(data)) { - if (isCanvasElement(data) || isOffscreenCanvas(data)) { - image.element = data - } else { - image.element = data.canvas - } - image.width = image.element.width - image.height = image.element.height - image.channels = 4 - } else if (isBitmap(data)) { - image.element = data - image.width = data.width - image.height = data.height - image.channels = 4 - } else if (isImageElement(data)) { - image.element = data - image.width = data.naturalWidth - image.height = data.naturalHeight - image.channels = 4 - } else if (isVideoElement(data)) { - image.element = data - image.width = data.videoWidth - image.height = data.videoHeight - image.channels = 4 - } else if (isRectArray(data)) { - var w = image.width || data[0].length - var h = image.height || data.length - var c = image.channels - if (isArrayLike(data[0][0])) { - c = c || data[0][0].length - } else { - c = c || 1 - } - var arrayShape = flattenUtils.shape(data) - var n = 1 - for (var dd = 0; dd < arrayShape.length; ++dd) { - n *= arrayShape[dd] - } - var allocData = preConvert(image, n) - flattenUtils.flatten(data, arrayShape, '', allocData) - postConvert(image, allocData) - image.alignment = 1 - image.width = w - image.height = h - image.channels = c - image.format = image.internalformat = CHANNELS_FORMAT[c] - image.needsFree = true - } - - if (image.type === GL_FLOAT$4) { - check$1(limits.extensions.indexOf('oes_texture_float') >= 0, - 'oes_texture_float extension not enabled') - } else if (image.type === GL_HALF_FLOAT_OES$1) { - check$1(limits.extensions.indexOf('oes_texture_half_float') >= 0, - 'oes_texture_half_float extension not enabled') - } - - // do compressed texture validation here. - } - - function setImage (info, target, miplevel) { - var element = info.element - var data = info.data - var internalformat = info.internalformat - var format = info.format - var type = info.type - var width = info.width - var height = info.height - - setFlags(info) - - if (element) { - gl.texImage2D(target, miplevel, format, format, type, element) - } else if (info.compressed) { - gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data) - } else if (info.needsCopy) { - reglPoll() - gl.copyTexImage2D( - target, miplevel, format, info.xOffset, info.yOffset, width, height, 0) - } else { - gl.texImage2D(target, miplevel, format, width, height, 0, format, type, data || null) - } - } - - function setSubImage (info, target, x, y, miplevel) { - var element = info.element - var data = info.data - var internalformat = info.internalformat - var format = info.format - var type = info.type - var width = info.width - var height = info.height - - setFlags(info) - - if (element) { - gl.texSubImage2D( - target, miplevel, x, y, format, type, element) - } else if (info.compressed) { - gl.compressedTexSubImage2D( - target, miplevel, x, y, internalformat, width, height, data) - } else if (info.needsCopy) { - reglPoll() - gl.copyTexSubImage2D( - target, miplevel, x, y, info.xOffset, info.yOffset, width, height) - } else { - gl.texSubImage2D( - target, miplevel, x, y, width, height, format, type, data) - } - } - - // texImage pool - var imagePool = [] - - function allocImage () { - return imagePool.pop() || new TexImage() - } - - function freeImage (image) { - if (image.needsFree) { - pool.freeType(image.data) - } - TexImage.call(image) - imagePool.push(image) - } - - // ------------------------------------------------------- - // Mip map - // ------------------------------------------------------- - function MipMap () { - TexFlags.call(this) - - this.genMipmaps = false - this.mipmapHint = GL_DONT_CARE - this.mipmask = 0 - this.images = Array(16) - } - - function parseMipMapFromShape (mipmap, width, height) { - var img = mipmap.images[0] = allocImage() - mipmap.mipmask = 1 - img.width = mipmap.width = width - img.height = mipmap.height = height - img.channels = mipmap.channels = 4 - } - - function parseMipMapFromObject (mipmap, options) { - var imgData = null - if (isPixelData(options)) { - imgData = mipmap.images[0] = allocImage() - copyFlags(imgData, mipmap) - parseImage(imgData, options) - mipmap.mipmask = 1 - } else { - parseFlags(mipmap, options) - if (Array.isArray(options.mipmap)) { - var mipData = options.mipmap - for (var i = 0; i < mipData.length; ++i) { - imgData = mipmap.images[i] = allocImage() - copyFlags(imgData, mipmap) - imgData.width >>= i - imgData.height >>= i - parseImage(imgData, mipData[i]) - mipmap.mipmask |= (1 << i) - } - } else { - imgData = mipmap.images[0] = allocImage() - copyFlags(imgData, mipmap) - parseImage(imgData, options) - mipmap.mipmask = 1 - } - } - copyFlags(mipmap, mipmap.images[0]) - - // For textures of the compressed format WEBGL_compressed_texture_s3tc - // we must have that - // - // "When level equals zero width and height must be a multiple of 4. - // When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. " - // - // but we do not yet support having multiple mipmap levels for compressed textures, - // so we only test for level zero. - - if ( - mipmap.compressed && - ( - mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT || - mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || - mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || - mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - ) - ) { - check$1(mipmap.width % 4 === 0 && mipmap.height % 4 === 0, - 'for compressed texture formats, mipmap level 0 must have width and height that are a multiple of 4') - } - } - - function setMipMap (mipmap, target) { - var images = mipmap.images - for (var i = 0; i < images.length; ++i) { - if (!images[i]) { - return - } - setImage(images[i], target, i) - } - } - - var mipPool = [] - - function allocMipMap () { - var result = mipPool.pop() || new MipMap() - TexFlags.call(result) - result.mipmask = 0 - for (var i = 0; i < 16; ++i) { - result.images[i] = null - } - return result - } - - function freeMipMap (mipmap) { - var images = mipmap.images - for (var i = 0; i < images.length; ++i) { - if (images[i]) { - freeImage(images[i]) - } - images[i] = null - } - mipPool.push(mipmap) - } - - // ------------------------------------------------------- - // Tex info - // ------------------------------------------------------- - function TexInfo () { - this.minFilter = GL_NEAREST$1 - this.magFilter = GL_NEAREST$1 - - this.wrapS = GL_CLAMP_TO_EDGE$1 - this.wrapT = GL_CLAMP_TO_EDGE$1 - - this.anisotropic = 1 - - this.genMipmaps = false - this.mipmapHint = GL_DONT_CARE - } - - function parseTexInfo (info, options) { - if ('min' in options) { - var minFilter = options.min - check$1.parameter(minFilter, minFilters) - info.minFilter = minFilters[minFilter] - if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0 && !('faces' in options)) { - info.genMipmaps = true - } - } - - if ('mag' in options) { - var magFilter = options.mag - check$1.parameter(magFilter, magFilters) - info.magFilter = magFilters[magFilter] - } - - var wrapS = info.wrapS - var wrapT = info.wrapT - if ('wrap' in options) { - var wrap = options.wrap - if (typeof wrap === 'string') { - check$1.parameter(wrap, wrapModes) - wrapS = wrapT = wrapModes[wrap] - } else if (Array.isArray(wrap)) { - check$1.parameter(wrap[0], wrapModes) - check$1.parameter(wrap[1], wrapModes) - wrapS = wrapModes[wrap[0]] - wrapT = wrapModes[wrap[1]] - } - } else { - if ('wrapS' in options) { - var optWrapS = options.wrapS - check$1.parameter(optWrapS, wrapModes) - wrapS = wrapModes[optWrapS] - } - if ('wrapT' in options) { - var optWrapT = options.wrapT - check$1.parameter(optWrapT, wrapModes) - wrapT = wrapModes[optWrapT] - } - } - info.wrapS = wrapS - info.wrapT = wrapT - - if ('anisotropic' in options) { - var anisotropic = options.anisotropic - check$1(typeof anisotropic === 'number' && - anisotropic >= 1 && anisotropic <= limits.maxAnisotropic, - 'aniso samples must be between 1 and ') - info.anisotropic = options.anisotropic - } - - if ('mipmap' in options) { - var hasMipMap = false - switch (typeof options.mipmap) { - case 'string': - check$1.parameter(options.mipmap, mipmapHint, - 'invalid mipmap hint') - info.mipmapHint = mipmapHint[options.mipmap] - info.genMipmaps = true - hasMipMap = true - break - - case 'boolean': - hasMipMap = info.genMipmaps = options.mipmap - break - - case 'object': - check$1(Array.isArray(options.mipmap), 'invalid mipmap type') - info.genMipmaps = false - hasMipMap = true - break - - default: - check$1.raise('invalid mipmap type') - } - if (hasMipMap && !('min' in options)) { - info.minFilter = GL_NEAREST_MIPMAP_NEAREST$1 - } - } - } - - function setTexInfo (info, target) { - gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter) - gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter) - gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS) - gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT) - if (extensions.ext_texture_filter_anisotropic) { - gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic) - } - if (info.genMipmaps) { - gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint) - gl.generateMipmap(target) - } - } - - // ------------------------------------------------------- - // Full texture object - // ------------------------------------------------------- - var textureCount = 0 - var textureSet = {} - var numTexUnits = limits.maxTextureUnits - var textureUnits = Array(numTexUnits).map(function () { - return null - }) - - function REGLTexture (target) { - TexFlags.call(this) - this.mipmask = 0 - this.internalformat = GL_RGBA$1 - - this.id = textureCount++ - - this.refCount = 1 - - this.target = target - this.texture = gl.createTexture() - - this.unit = -1 - this.bindCount = 0 - - this.texInfo = new TexInfo() - - if (config.profile) { - this.stats = { size: 0 } - } - } - - function tempBind (texture) { - gl.activeTexture(GL_TEXTURE0$1) - gl.bindTexture(texture.target, texture.texture) - } - - function tempRestore () { - var prev = textureUnits[0] - if (prev) { - gl.bindTexture(prev.target, prev.texture) - } else { - gl.bindTexture(GL_TEXTURE_2D$1, null) - } - } - - function destroy (texture) { - var handle = texture.texture - check$1(handle, 'must not double destroy texture') - var unit = texture.unit - var target = texture.target - if (unit >= 0) { - gl.activeTexture(GL_TEXTURE0$1 + unit) - gl.bindTexture(target, null) - textureUnits[unit] = null - } - gl.deleteTexture(handle) - texture.texture = null - texture.params = null - texture.pixels = null - texture.refCount = 0 - delete textureSet[texture.id] - stats.textureCount-- - } - - extend(REGLTexture.prototype, { - bind: function () { - var texture = this - texture.bindCount += 1 - var unit = texture.unit - if (unit < 0) { - for (var i = 0; i < numTexUnits; ++i) { - var other = textureUnits[i] - if (other) { - if (other.bindCount > 0) { - continue - } - other.unit = -1 - } - textureUnits[i] = texture - unit = i - break - } - if (unit >= numTexUnits) { - check$1.raise('insufficient number of texture units') - } - if (config.profile && stats.maxTextureUnits < (unit + 1)) { - stats.maxTextureUnits = unit + 1 // +1, since the units are zero-based - } - texture.unit = unit - gl.activeTexture(GL_TEXTURE0$1 + unit) - gl.bindTexture(texture.target, texture.texture) - } - return unit - }, - - unbind: function () { - this.bindCount -= 1 - }, - - decRef: function () { - if (--this.refCount <= 0) { - destroy(this) - } - } - }) - - function createTexture2D (a, b) { - var texture = new REGLTexture(GL_TEXTURE_2D$1) - textureSet[texture.id] = texture - stats.textureCount++ - - function reglTexture2D (a, b) { - var texInfo = texture.texInfo - TexInfo.call(texInfo) - var mipData = allocMipMap() - - if (typeof a === 'number') { - if (typeof b === 'number') { - parseMipMapFromShape(mipData, a | 0, b | 0) - } else { - parseMipMapFromShape(mipData, a | 0, a | 0) - } - } else if (a) { - check$1.type(a, 'object', 'invalid arguments to regl.texture') - parseTexInfo(texInfo, a) - parseMipMapFromObject(mipData, a) - } else { - // empty textures get assigned a default shape of 1x1 - parseMipMapFromShape(mipData, 1, 1) - } - - if (texInfo.genMipmaps) { - mipData.mipmask = (mipData.width << 1) - 1 - } - texture.mipmask = mipData.mipmask - - copyFlags(texture, mipData) - - check$1.texture2D(texInfo, mipData, limits) - texture.internalformat = mipData.internalformat - - reglTexture2D.width = mipData.width - reglTexture2D.height = mipData.height - - tempBind(texture) - setMipMap(mipData, GL_TEXTURE_2D$1) - setTexInfo(texInfo, GL_TEXTURE_2D$1) - tempRestore() - - freeMipMap(mipData) - - if (config.profile) { - texture.stats.size = getTextureSize( - texture.internalformat, - texture.type, - mipData.width, - mipData.height, - texInfo.genMipmaps, - false) - } - reglTexture2D.format = textureFormatsInvert[texture.internalformat] - reglTexture2D.type = textureTypesInvert[texture.type] - - reglTexture2D.mag = magFiltersInvert[texInfo.magFilter] - reglTexture2D.min = minFiltersInvert[texInfo.minFilter] - - reglTexture2D.wrapS = wrapModesInvert[texInfo.wrapS] - reglTexture2D.wrapT = wrapModesInvert[texInfo.wrapT] - - return reglTexture2D - } - - function subimage (image, x_, y_, level_) { - check$1(!!image, 'must specify image data') - - var x = x_ | 0 - var y = y_ | 0 - var level = level_ | 0 - - var imageData = allocImage() - copyFlags(imageData, texture) - imageData.width = 0 - imageData.height = 0 - parseImage(imageData, image) - imageData.width = imageData.width || ((texture.width >> level) - x) - imageData.height = imageData.height || ((texture.height >> level) - y) - - check$1( - texture.type === imageData.type && - texture.format === imageData.format && - texture.internalformat === imageData.internalformat, - 'incompatible format for texture.subimage') - check$1( - x >= 0 && y >= 0 && - x + imageData.width <= texture.width && - y + imageData.height <= texture.height, - 'texture.subimage write out of bounds') - check$1( - texture.mipmask & (1 << level), - 'missing mipmap data') - check$1( - imageData.data || imageData.element || imageData.needsCopy, - 'missing image data') - - tempBind(texture) - setSubImage(imageData, GL_TEXTURE_2D$1, x, y, level) - tempRestore() - - freeImage(imageData) - - return reglTexture2D - } - - function resize (w_, h_) { - var w = w_ | 0 - var h = (h_ | 0) || w - if (w === texture.width && h === texture.height) { - return reglTexture2D - } - - reglTexture2D.width = texture.width = w - reglTexture2D.height = texture.height = h - - tempBind(texture) - - for (var i = 0; texture.mipmask >> i; ++i) { - var _w = w >> i - var _h = h >> i - if (!_w || !_h) break - gl.texImage2D( - GL_TEXTURE_2D$1, - i, - texture.format, - _w, - _h, - 0, - texture.format, - texture.type, - null) - } - tempRestore() - - // also, recompute the texture size. - if (config.profile) { - texture.stats.size = getTextureSize( - texture.internalformat, - texture.type, - w, - h, - false, - false) - } - - return reglTexture2D - } - - reglTexture2D(a, b) - - reglTexture2D.subimage = subimage - reglTexture2D.resize = resize - reglTexture2D._reglType = 'texture2d' - reglTexture2D._texture = texture - if (config.profile) { - reglTexture2D.stats = texture.stats - } - reglTexture2D.destroy = function () { - texture.decRef() - } - - return reglTexture2D - } - - function createTextureCube (a0, a1, a2, a3, a4, a5) { - var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP$1) - textureSet[texture.id] = texture - stats.cubeCount++ - - var faces = new Array(6) - - function reglTextureCube (a0, a1, a2, a3, a4, a5) { - var i - var texInfo = texture.texInfo - TexInfo.call(texInfo) - for (i = 0; i < 6; ++i) { - faces[i] = allocMipMap() - } - - if (typeof a0 === 'number' || !a0) { - var s = (a0 | 0) || 1 - for (i = 0; i < 6; ++i) { - parseMipMapFromShape(faces[i], s, s) - } - } else if (typeof a0 === 'object') { - if (a1) { - parseMipMapFromObject(faces[0], a0) - parseMipMapFromObject(faces[1], a1) - parseMipMapFromObject(faces[2], a2) - parseMipMapFromObject(faces[3], a3) - parseMipMapFromObject(faces[4], a4) - parseMipMapFromObject(faces[5], a5) - } else { - parseTexInfo(texInfo, a0) - parseFlags(texture, a0) - if ('faces' in a0) { - var faceInput = a0.faces - check$1(Array.isArray(faceInput) && faceInput.length === 6, - 'cube faces must be a length 6 array') - for (i = 0; i < 6; ++i) { - check$1(typeof faceInput[i] === 'object' && !!faceInput[i], - 'invalid input for cube map face') - copyFlags(faces[i], texture) - parseMipMapFromObject(faces[i], faceInput[i]) - } - } else { - for (i = 0; i < 6; ++i) { - parseMipMapFromObject(faces[i], a0) - } - } - } - } else { - check$1.raise('invalid arguments to cube map') - } - - copyFlags(texture, faces[0]) - check$1.optional(function () { - if (!limits.npotTextureCube) { - check$1(isPow2$1(texture.width) && isPow2$1(texture.height), 'your browser does not support non power or two texture dimensions') - } - }) - - if (texInfo.genMipmaps) { - texture.mipmask = (faces[0].width << 1) - 1 - } else { - texture.mipmask = faces[0].mipmask - } - - check$1.textureCube(texture, texInfo, faces, limits) - texture.internalformat = faces[0].internalformat - - reglTextureCube.width = faces[0].width - reglTextureCube.height = faces[0].height - - tempBind(texture) - for (i = 0; i < 6; ++i) { - setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i) - } - setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP$1) - tempRestore() - - if (config.profile) { - texture.stats.size = getTextureSize( - texture.internalformat, - texture.type, - reglTextureCube.width, - reglTextureCube.height, - texInfo.genMipmaps, - true) - } - - reglTextureCube.format = textureFormatsInvert[texture.internalformat] - reglTextureCube.type = textureTypesInvert[texture.type] - - reglTextureCube.mag = magFiltersInvert[texInfo.magFilter] - reglTextureCube.min = minFiltersInvert[texInfo.minFilter] - - reglTextureCube.wrapS = wrapModesInvert[texInfo.wrapS] - reglTextureCube.wrapT = wrapModesInvert[texInfo.wrapT] - - for (i = 0; i < 6; ++i) { - freeMipMap(faces[i]) - } - - return reglTextureCube - } - - function subimage (face, image, x_, y_, level_) { - check$1(!!image, 'must specify image data') - check$1(typeof face === 'number' && face === (face | 0) && - face >= 0 && face < 6, 'invalid face') - - var x = x_ | 0 - var y = y_ | 0 - var level = level_ | 0 - - var imageData = allocImage() - copyFlags(imageData, texture) - imageData.width = 0 - imageData.height = 0 - parseImage(imageData, image) - imageData.width = imageData.width || ((texture.width >> level) - x) - imageData.height = imageData.height || ((texture.height >> level) - y) - - check$1( - texture.type === imageData.type && - texture.format === imageData.format && - texture.internalformat === imageData.internalformat, - 'incompatible format for texture.subimage') - check$1( - x >= 0 && y >= 0 && - x + imageData.width <= texture.width && - y + imageData.height <= texture.height, - 'texture.subimage write out of bounds') - check$1( - texture.mipmask & (1 << level), - 'missing mipmap data') - check$1( - imageData.data || imageData.element || imageData.needsCopy, - 'missing image data') - - tempBind(texture) - setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + face, x, y, level) - tempRestore() - - freeImage(imageData) - - return reglTextureCube - } - - function resize (radius_) { - var radius = radius_ | 0 - if (radius === texture.width) { - return - } - - reglTextureCube.width = texture.width = radius - reglTextureCube.height = texture.height = radius - - tempBind(texture) - for (var i = 0; i < 6; ++i) { - for (var j = 0; texture.mipmask >> j; ++j) { - gl.texImage2D( - GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i, - j, - texture.format, - radius >> j, - radius >> j, - 0, - texture.format, - texture.type, - null) - } - } - tempRestore() - - if (config.profile) { - texture.stats.size = getTextureSize( - texture.internalformat, - texture.type, - reglTextureCube.width, - reglTextureCube.height, - false, - true) - } - - return reglTextureCube - } - - reglTextureCube(a0, a1, a2, a3, a4, a5) - - reglTextureCube.subimage = subimage - reglTextureCube.resize = resize - reglTextureCube._reglType = 'textureCube' - reglTextureCube._texture = texture - if (config.profile) { - reglTextureCube.stats = texture.stats - } - reglTextureCube.destroy = function () { - texture.decRef() - } - - return reglTextureCube - } - - // Called when regl is destroyed - function destroyTextures () { - for (var i = 0; i < numTexUnits; ++i) { - gl.activeTexture(GL_TEXTURE0$1 + i) - gl.bindTexture(GL_TEXTURE_2D$1, null) - textureUnits[i] = null - } - values(textureSet).forEach(destroy) - - stats.cubeCount = 0 - stats.textureCount = 0 - } - - if (config.profile) { - stats.getTotalTextureSize = function () { - var total = 0 - Object.keys(textureSet).forEach(function (key) { - total += textureSet[key].stats.size - }) - return total - } - } - - function restoreTextures () { - for (var i = 0; i < numTexUnits; ++i) { - var tex = textureUnits[i] - if (tex) { - tex.bindCount = 0 - tex.unit = -1 - textureUnits[i] = null - } - } - - values(textureSet).forEach(function (texture) { - texture.texture = gl.createTexture() - gl.bindTexture(texture.target, texture.texture) - for (var i = 0; i < 32; ++i) { - if ((texture.mipmask & (1 << i)) === 0) { - continue - } - if (texture.target === GL_TEXTURE_2D$1) { - gl.texImage2D(GL_TEXTURE_2D$1, - i, - texture.internalformat, - texture.width >> i, - texture.height >> i, - 0, - texture.internalformat, - texture.type, - null) - } else { - for (var j = 0; j < 6; ++j) { - gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + j, - i, - texture.internalformat, - texture.width >> i, - texture.height >> i, - 0, - texture.internalformat, - texture.type, - null) - } - } - } - setTexInfo(texture.texInfo, texture.target) - }) - } - - function refreshTextures () { - for (var i = 0; i < numTexUnits; ++i) { - var tex = textureUnits[i] - if (tex) { - tex.bindCount = 0 - tex.unit = -1 - textureUnits[i] = null - } - gl.activeTexture(GL_TEXTURE0$1 + i) - gl.bindTexture(GL_TEXTURE_2D$1, null) - gl.bindTexture(GL_TEXTURE_CUBE_MAP$1, null) - } - } - - return { - create2D: createTexture2D, - createCube: createTextureCube, - clear: destroyTextures, - getTexture: function (wrapper) { - return null - }, - restore: restoreTextures, - refresh: refreshTextures - } -} - -var GL_RENDERBUFFER = 0x8D41 - -var GL_RGBA4$1 = 0x8056 -var GL_RGB5_A1$1 = 0x8057 -var GL_RGB565$1 = 0x8D62 -var GL_DEPTH_COMPONENT16 = 0x81A5 -var GL_STENCIL_INDEX8 = 0x8D48 -var GL_DEPTH_STENCIL$1 = 0x84F9 - -var GL_SRGB8_ALPHA8_EXT = 0x8C43 - -var GL_RGBA32F_EXT = 0x8814 - -var GL_RGBA16F_EXT = 0x881A -var GL_RGB16F_EXT = 0x881B - -var FORMAT_SIZES = [] - -FORMAT_SIZES[GL_RGBA4$1] = 2 -FORMAT_SIZES[GL_RGB5_A1$1] = 2 -FORMAT_SIZES[GL_RGB565$1] = 2 - -FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2 -FORMAT_SIZES[GL_STENCIL_INDEX8] = 1 -FORMAT_SIZES[GL_DEPTH_STENCIL$1] = 4 - -FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4 -FORMAT_SIZES[GL_RGBA32F_EXT] = 16 -FORMAT_SIZES[GL_RGBA16F_EXT] = 8 -FORMAT_SIZES[GL_RGB16F_EXT] = 6 - -function getRenderbufferSize (format, width, height) { - return FORMAT_SIZES[format] * width * height -} - -var wrapRenderbuffers = function (gl, extensions, limits, stats, config) { - var formatTypes = { - 'rgba4': GL_RGBA4$1, - 'rgb565': GL_RGB565$1, - 'rgb5 a1': GL_RGB5_A1$1, - 'depth': GL_DEPTH_COMPONENT16, - 'stencil': GL_STENCIL_INDEX8, - 'depth stencil': GL_DEPTH_STENCIL$1 - } - - if (extensions.ext_srgb) { - formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT - } - - if (extensions.ext_color_buffer_half_float) { - formatTypes['rgba16f'] = GL_RGBA16F_EXT - formatTypes['rgb16f'] = GL_RGB16F_EXT - } - - if (extensions.webgl_color_buffer_float) { - formatTypes['rgba32f'] = GL_RGBA32F_EXT - } - - var formatTypesInvert = [] - Object.keys(formatTypes).forEach(function (key) { - var val = formatTypes[key] - formatTypesInvert[val] = key - }) - - var renderbufferCount = 0 - var renderbufferSet = {} - - function REGLRenderbuffer (renderbuffer) { - this.id = renderbufferCount++ - this.refCount = 1 - - this.renderbuffer = renderbuffer - - this.format = GL_RGBA4$1 - this.width = 0 - this.height = 0 - - if (config.profile) { - this.stats = { size: 0 } - } - } - - REGLRenderbuffer.prototype.decRef = function () { - if (--this.refCount <= 0) { - destroy(this) - } - } - - function destroy (rb) { - var handle = rb.renderbuffer - check$1(handle, 'must not double destroy renderbuffer') - gl.bindRenderbuffer(GL_RENDERBUFFER, null) - gl.deleteRenderbuffer(handle) - rb.renderbuffer = null - rb.refCount = 0 - delete renderbufferSet[rb.id] - stats.renderbufferCount-- - } - - function createRenderbuffer (a, b) { - var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer()) - renderbufferSet[renderbuffer.id] = renderbuffer - stats.renderbufferCount++ - - function reglRenderbuffer (a, b) { - var w = 0 - var h = 0 - var format = GL_RGBA4$1 - - if (typeof a === 'object' && a) { - var options = a - if ('shape' in options) { - var shape = options.shape - check$1(Array.isArray(shape) && shape.length >= 2, - 'invalid renderbuffer shape') - w = shape[0] | 0 - h = shape[1] | 0 - } else { - if ('radius' in options) { - w = h = options.radius | 0 - } - if ('width' in options) { - w = options.width | 0 - } - if ('height' in options) { - h = options.height | 0 - } - } - if ('format' in options) { - check$1.parameter(options.format, formatTypes, - 'invalid renderbuffer format') - format = formatTypes[options.format] - } - } else if (typeof a === 'number') { - w = a | 0 - if (typeof b === 'number') { - h = b | 0 - } else { - h = w - } - } else if (!a) { - w = h = 1 - } else { - check$1.raise('invalid arguments to renderbuffer constructor') - } - - // check shape - check$1( - w > 0 && h > 0 && - w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, - 'invalid renderbuffer size') - - if (w === renderbuffer.width && - h === renderbuffer.height && - format === renderbuffer.format) { - return - } - - reglRenderbuffer.width = renderbuffer.width = w - reglRenderbuffer.height = renderbuffer.height = h - renderbuffer.format = format - - gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) - gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h) - - check$1( - gl.getError() === 0, - 'invalid render buffer format') - - if (config.profile) { - renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height) - } - reglRenderbuffer.format = formatTypesInvert[renderbuffer.format] - - return reglRenderbuffer - } - - function resize (w_, h_) { - var w = w_ | 0 - var h = (h_ | 0) || w - - if (w === renderbuffer.width && h === renderbuffer.height) { - return reglRenderbuffer - } - - // check shape - check$1( - w > 0 && h > 0 && - w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize, - 'invalid renderbuffer size') - - reglRenderbuffer.width = renderbuffer.width = w - reglRenderbuffer.height = renderbuffer.height = h - - gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer) - gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h) - - check$1( - gl.getError() === 0, - 'invalid render buffer format') - - // also, recompute size. - if (config.profile) { - renderbuffer.stats.size = getRenderbufferSize( - renderbuffer.format, renderbuffer.width, renderbuffer.height) - } - - return reglRenderbuffer - } - - reglRenderbuffer(a, b) - - reglRenderbuffer.resize = resize - reglRenderbuffer._reglType = 'renderbuffer' - reglRenderbuffer._renderbuffer = renderbuffer - if (config.profile) { - reglRenderbuffer.stats = renderbuffer.stats - } - reglRenderbuffer.destroy = function () { - renderbuffer.decRef() - } - - return reglRenderbuffer - } - - if (config.profile) { - stats.getTotalRenderbufferSize = function () { - var total = 0 - Object.keys(renderbufferSet).forEach(function (key) { - total += renderbufferSet[key].stats.size - }) - return total - } - } - - function restoreRenderbuffers () { - values(renderbufferSet).forEach(function (rb) { - rb.renderbuffer = gl.createRenderbuffer() - gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer) - gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height) - }) - gl.bindRenderbuffer(GL_RENDERBUFFER, null) - } - - return { - create: createRenderbuffer, - clear: function () { - values(renderbufferSet).forEach(destroy) - }, - restore: restoreRenderbuffers - } -} - -// We store these constants so that the minifier can inline them -var GL_FRAMEBUFFER$1 = 0x8D40 -var GL_RENDERBUFFER$1 = 0x8D41 - -var GL_TEXTURE_2D$2 = 0x0DE1 -var GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 = 0x8515 - -var GL_COLOR_ATTACHMENT0$1 = 0x8CE0 -var GL_DEPTH_ATTACHMENT = 0x8D00 -var GL_STENCIL_ATTACHMENT = 0x8D20 -var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A - -var GL_FRAMEBUFFER_COMPLETE$1 = 0x8CD5 -var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6 -var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7 -var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9 -var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD - -var GL_HALF_FLOAT_OES$2 = 0x8D61 -var GL_UNSIGNED_BYTE$6 = 0x1401 -var GL_FLOAT$5 = 0x1406 - -var GL_RGB$1 = 0x1907 -var GL_RGBA$2 = 0x1908 - -var GL_DEPTH_COMPONENT$1 = 0x1902 - -var colorTextureFormatEnums = [ - GL_RGB$1, - GL_RGBA$2 -] - -// for every texture format, store -// the number of channels -var textureFormatChannels = [] -textureFormatChannels[GL_RGBA$2] = 4 -textureFormatChannels[GL_RGB$1] = 3 - -// for every texture type, store -// the size in bytes. -var textureTypeSizes = [] -textureTypeSizes[GL_UNSIGNED_BYTE$6] = 1 -textureTypeSizes[GL_FLOAT$5] = 4 -textureTypeSizes[GL_HALF_FLOAT_OES$2] = 2 - -var GL_RGBA4$2 = 0x8056 -var GL_RGB5_A1$2 = 0x8057 -var GL_RGB565$2 = 0x8D62 -var GL_DEPTH_COMPONENT16$1 = 0x81A5 -var GL_STENCIL_INDEX8$1 = 0x8D48 -var GL_DEPTH_STENCIL$2 = 0x84F9 - -var GL_SRGB8_ALPHA8_EXT$1 = 0x8C43 - -var GL_RGBA32F_EXT$1 = 0x8814 - -var GL_RGBA16F_EXT$1 = 0x881A -var GL_RGB16F_EXT$1 = 0x881B - -var colorRenderbufferFormatEnums = [ - GL_RGBA4$2, - GL_RGB5_A1$2, - GL_RGB565$2, - GL_SRGB8_ALPHA8_EXT$1, - GL_RGBA16F_EXT$1, - GL_RGB16F_EXT$1, - GL_RGBA32F_EXT$1 -] - -var statusCode = {} -statusCode[GL_FRAMEBUFFER_COMPLETE$1] = 'complete' -statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment' -statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions' -statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment' -statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported' - -function wrapFBOState ( - gl, - extensions, - limits, - textureState, - renderbufferState, - stats) { - var framebufferState = { - cur: null, - next: null, - dirty: false, - setFBO: null - } - - var colorTextureFormats = ['rgba'] - var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1'] - - if (extensions.ext_srgb) { - colorRenderbufferFormats.push('srgba') - } - - if (extensions.ext_color_buffer_half_float) { - colorRenderbufferFormats.push('rgba16f', 'rgb16f') - } - - if (extensions.webgl_color_buffer_float) { - colorRenderbufferFormats.push('rgba32f') - } - - var colorTypes = ['uint8'] - if (extensions.oes_texture_half_float) { - colorTypes.push('half float', 'float16') - } - if (extensions.oes_texture_float) { - colorTypes.push('float', 'float32') - } - - function FramebufferAttachment (target, texture, renderbuffer) { - this.target = target - this.texture = texture - this.renderbuffer = renderbuffer - - var w = 0 - var h = 0 - if (texture) { - w = texture.width - h = texture.height - } else if (renderbuffer) { - w = renderbuffer.width - h = renderbuffer.height - } - this.width = w - this.height = h - } - - function decRef (attachment) { - if (attachment) { - if (attachment.texture) { - attachment.texture._texture.decRef() - } - if (attachment.renderbuffer) { - attachment.renderbuffer._renderbuffer.decRef() - } - } - } - - function incRefAndCheckShape (attachment, width, height) { - if (!attachment) { - return - } - if (attachment.texture) { - var texture = attachment.texture._texture - var tw = Math.max(1, texture.width) - var th = Math.max(1, texture.height) - check$1(tw === width && th === height, - 'inconsistent width/height for supplied texture') - texture.refCount += 1 - } else { - var renderbuffer = attachment.renderbuffer._renderbuffer - check$1( - renderbuffer.width === width && renderbuffer.height === height, - 'inconsistent width/height for renderbuffer') - renderbuffer.refCount += 1 - } - } - - function attach (location, attachment) { - if (attachment) { - if (attachment.texture) { - gl.framebufferTexture2D( - GL_FRAMEBUFFER$1, - location, - attachment.target, - attachment.texture._texture.texture, - 0) - } else { - gl.framebufferRenderbuffer( - GL_FRAMEBUFFER$1, - location, - GL_RENDERBUFFER$1, - attachment.renderbuffer._renderbuffer.renderbuffer) - } - } - } - - function parseAttachment (attachment) { - var target = GL_TEXTURE_2D$2 - var texture = null - var renderbuffer = null - - var data = attachment - if (typeof attachment === 'object') { - data = attachment.data - if ('target' in attachment) { - target = attachment.target | 0 - } - } - - check$1.type(data, 'function', 'invalid attachment data') - - var type = data._reglType - if (type === 'texture2d') { - texture = data - check$1(target === GL_TEXTURE_2D$2) - } else if (type === 'textureCube') { - texture = data - check$1( - target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 && - target < GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 + 6, - 'invalid cube map target') - } else if (type === 'renderbuffer') { - renderbuffer = data - target = GL_RENDERBUFFER$1 - } else { - check$1.raise('invalid regl object for attachment') - } - - return new FramebufferAttachment(target, texture, renderbuffer) - } - - function allocAttachment ( - width, - height, - isTexture, - format, - type) { - if (isTexture) { - var texture = textureState.create2D({ - width: width, - height: height, - format: format, - type: type - }) - texture._texture.refCount = 0 - return new FramebufferAttachment(GL_TEXTURE_2D$2, texture, null) - } else { - var rb = renderbufferState.create({ - width: width, - height: height, - format: format - }) - rb._renderbuffer.refCount = 0 - return new FramebufferAttachment(GL_RENDERBUFFER$1, null, rb) - } - } - - function unwrapAttachment (attachment) { - return attachment && (attachment.texture || attachment.renderbuffer) - } - - function resizeAttachment (attachment, w, h) { - if (attachment) { - if (attachment.texture) { - attachment.texture.resize(w, h) - } else if (attachment.renderbuffer) { - attachment.renderbuffer.resize(w, h) - } - attachment.width = w - attachment.height = h - } - } - - var framebufferCount = 0 - var framebufferSet = {} - - function REGLFramebuffer () { - this.id = framebufferCount++ - framebufferSet[this.id] = this - - this.framebuffer = gl.createFramebuffer() - this.width = 0 - this.height = 0 - - this.colorAttachments = [] - this.depthAttachment = null - this.stencilAttachment = null - this.depthStencilAttachment = null - } - - function decFBORefs (framebuffer) { - framebuffer.colorAttachments.forEach(decRef) - decRef(framebuffer.depthAttachment) - decRef(framebuffer.stencilAttachment) - decRef(framebuffer.depthStencilAttachment) - } - - function destroy (framebuffer) { - var handle = framebuffer.framebuffer - check$1(handle, 'must not double destroy framebuffer') - gl.deleteFramebuffer(handle) - framebuffer.framebuffer = null - stats.framebufferCount-- - delete framebufferSet[framebuffer.id] - } - - function updateFramebuffer (framebuffer) { - var i - - gl.bindFramebuffer(GL_FRAMEBUFFER$1, framebuffer.framebuffer) - var colorAttachments = framebuffer.colorAttachments - for (i = 0; i < colorAttachments.length; ++i) { - attach(GL_COLOR_ATTACHMENT0$1 + i, colorAttachments[i]) - } - for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) { - gl.framebufferTexture2D( - GL_FRAMEBUFFER$1, - GL_COLOR_ATTACHMENT0$1 + i, - GL_TEXTURE_2D$2, - null, - 0) - } - - gl.framebufferTexture2D( - GL_FRAMEBUFFER$1, - GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D$2, - null, - 0) - gl.framebufferTexture2D( - GL_FRAMEBUFFER$1, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D$2, - null, - 0) - gl.framebufferTexture2D( - GL_FRAMEBUFFER$1, - GL_STENCIL_ATTACHMENT, - GL_TEXTURE_2D$2, - null, - 0) - - attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment) - attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment) - attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment) - - // Check status code - var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER$1) - if (!gl.isContextLost() && status !== GL_FRAMEBUFFER_COMPLETE$1) { - check$1.raise('framebuffer configuration not supported, status = ' + - statusCode[status]) - } - - gl.bindFramebuffer(GL_FRAMEBUFFER$1, framebufferState.next ? framebufferState.next.framebuffer : null) - framebufferState.cur = framebufferState.next - - // FIXME: Clear error code here. This is a work around for a bug in - // headless-gl - gl.getError() - } - - function createFBO (a0, a1) { - var framebuffer = new REGLFramebuffer() - stats.framebufferCount++ - - function reglFramebuffer (a, b) { - var i - - check$1(framebufferState.next !== framebuffer, - 'can not update framebuffer which is currently in use') - - var width = 0 - var height = 0 - - var needsDepth = true - var needsStencil = true - - var colorBuffer = null - var colorTexture = true - var colorFormat = 'rgba' - var colorType = 'uint8' - var colorCount = 1 - - var depthBuffer = null - var stencilBuffer = null - var depthStencilBuffer = null - var depthStencilTexture = false - - if (typeof a === 'number') { - width = a | 0 - height = (b | 0) || width - } else if (!a) { - width = height = 1 - } else { - check$1.type(a, 'object', 'invalid arguments for framebuffer') - var options = a - - if ('shape' in options) { - var shape = options.shape - check$1(Array.isArray(shape) && shape.length >= 2, - 'invalid shape for framebuffer') - width = shape[0] - height = shape[1] - } else { - if ('radius' in options) { - width = height = options.radius - } - if ('width' in options) { - width = options.width - } - if ('height' in options) { - height = options.height - } - } - - if ('color' in options || - 'colors' in options) { - colorBuffer = - options.color || - options.colors - if (Array.isArray(colorBuffer)) { - check$1( - colorBuffer.length === 1 || extensions.webgl_draw_buffers, - 'multiple render targets not supported') - } - } - - if (!colorBuffer) { - if ('colorCount' in options) { - colorCount = options.colorCount | 0 - check$1(colorCount > 0, 'invalid color buffer count') - } - - if ('colorTexture' in options) { - colorTexture = !!options.colorTexture - colorFormat = 'rgba4' - } - - if ('colorType' in options) { - colorType = options.colorType - if (!colorTexture) { - if (colorType === 'half float' || colorType === 'float16') { - check$1(extensions.ext_color_buffer_half_float, - 'you must enable EXT_color_buffer_half_float to use 16-bit render buffers') - colorFormat = 'rgba16f' - } else if (colorType === 'float' || colorType === 'float32') { - check$1(extensions.webgl_color_buffer_float, - 'you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers') - colorFormat = 'rgba32f' - } - } else { - check$1(extensions.oes_texture_float || - !(colorType === 'float' || colorType === 'float32'), - 'you must enable OES_texture_float in order to use floating point framebuffer objects') - check$1(extensions.oes_texture_half_float || - !(colorType === 'half float' || colorType === 'float16'), - 'you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects') - } - check$1.oneOf(colorType, colorTypes, 'invalid color type') - } - - if ('colorFormat' in options) { - colorFormat = options.colorFormat - if (colorTextureFormats.indexOf(colorFormat) >= 0) { - colorTexture = true - } else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) { - colorTexture = false - } else { - check$1.optional(function () { - if (colorTexture) { - check$1.oneOf( - options.colorFormat, colorTextureFormats, - 'invalid color format for texture') - } else { - check$1.oneOf( - options.colorFormat, colorRenderbufferFormats, - 'invalid color format for renderbuffer') - } - }) - } - } - } - - if ('depthTexture' in options || 'depthStencilTexture' in options) { - depthStencilTexture = !!(options.depthTexture || - options.depthStencilTexture) - check$1(!depthStencilTexture || extensions.webgl_depth_texture, - 'webgl_depth_texture extension not supported') - } - - if ('depth' in options) { - if (typeof options.depth === 'boolean') { - needsDepth = options.depth - } else { - depthBuffer = options.depth - needsStencil = false - } - } - - if ('stencil' in options) { - if (typeof options.stencil === 'boolean') { - needsStencil = options.stencil - } else { - stencilBuffer = options.stencil - needsDepth = false - } - } - - if ('depthStencil' in options) { - if (typeof options.depthStencil === 'boolean') { - needsDepth = needsStencil = options.depthStencil - } else { - depthStencilBuffer = options.depthStencil - needsDepth = false - needsStencil = false - } - } - } - - // parse attachments - var colorAttachments = null - var depthAttachment = null - var stencilAttachment = null - var depthStencilAttachment = null - - // Set up color attachments - if (Array.isArray(colorBuffer)) { - colorAttachments = colorBuffer.map(parseAttachment) - } else if (colorBuffer) { - colorAttachments = [parseAttachment(colorBuffer)] - } else { - colorAttachments = new Array(colorCount) - for (i = 0; i < colorCount; ++i) { - colorAttachments[i] = allocAttachment( - width, - height, - colorTexture, - colorFormat, - colorType) - } - } - - check$1(extensions.webgl_draw_buffers || colorAttachments.length <= 1, - 'you must enable the WEBGL_draw_buffers extension in order to use multiple color buffers.') - check$1(colorAttachments.length <= limits.maxColorAttachments, - 'too many color attachments, not supported') - - width = width || colorAttachments[0].width - height = height || colorAttachments[0].height - - if (depthBuffer) { - depthAttachment = parseAttachment(depthBuffer) - } else if (needsDepth && !needsStencil) { - depthAttachment = allocAttachment( - width, - height, - depthStencilTexture, - 'depth', - 'uint32') - } - - if (stencilBuffer) { - stencilAttachment = parseAttachment(stencilBuffer) - } else if (needsStencil && !needsDepth) { - stencilAttachment = allocAttachment( - width, - height, - false, - 'stencil', - 'uint8') - } - - if (depthStencilBuffer) { - depthStencilAttachment = parseAttachment(depthStencilBuffer) - } else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) { - depthStencilAttachment = allocAttachment( - width, - height, - depthStencilTexture, - 'depth stencil', - 'depth stencil') - } - - check$1( - (!!depthBuffer) + (!!stencilBuffer) + (!!depthStencilBuffer) <= 1, - 'invalid framebuffer configuration, can specify exactly one depth/stencil attachment') - - var commonColorAttachmentSize = null - - for (i = 0; i < colorAttachments.length; ++i) { - incRefAndCheckShape(colorAttachments[i], width, height) - check$1(!colorAttachments[i] || - (colorAttachments[i].texture && - colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0) || - (colorAttachments[i].renderbuffer && - colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0), - 'framebuffer color attachment ' + i + ' is invalid') - - if (colorAttachments[i] && colorAttachments[i].texture) { - var colorAttachmentSize = - textureFormatChannels[colorAttachments[i].texture._texture.format] * - textureTypeSizes[colorAttachments[i].texture._texture.type] - - if (commonColorAttachmentSize === null) { - commonColorAttachmentSize = colorAttachmentSize - } else { - // We need to make sure that all color attachments have the same number of bitplanes - // (that is, the same numer of bits per pixel) - // This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document. - check$1(commonColorAttachmentSize === colorAttachmentSize, - 'all color attachments much have the same number of bits per pixel.') - } - } - } - incRefAndCheckShape(depthAttachment, width, height) - check$1(!depthAttachment || - (depthAttachment.texture && - depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT$1) || - (depthAttachment.renderbuffer && - depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16$1), - 'invalid depth attachment for framebuffer object') - incRefAndCheckShape(stencilAttachment, width, height) - check$1(!stencilAttachment || - (stencilAttachment.renderbuffer && - stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8$1), - 'invalid stencil attachment for framebuffer object') - incRefAndCheckShape(depthStencilAttachment, width, height) - check$1(!depthStencilAttachment || - (depthStencilAttachment.texture && - depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL$2) || - (depthStencilAttachment.renderbuffer && - depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL$2), - 'invalid depth-stencil attachment for framebuffer object') - - // decrement references - decFBORefs(framebuffer) - - framebuffer.width = width - framebuffer.height = height - - framebuffer.colorAttachments = colorAttachments - framebuffer.depthAttachment = depthAttachment - framebuffer.stencilAttachment = stencilAttachment - framebuffer.depthStencilAttachment = depthStencilAttachment - - reglFramebuffer.color = colorAttachments.map(unwrapAttachment) - reglFramebuffer.depth = unwrapAttachment(depthAttachment) - reglFramebuffer.stencil = unwrapAttachment(stencilAttachment) - reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment) - - reglFramebuffer.width = framebuffer.width - reglFramebuffer.height = framebuffer.height - - updateFramebuffer(framebuffer) - - return reglFramebuffer - } - - function resize (w_, h_) { - check$1(framebufferState.next !== framebuffer, - 'can not resize a framebuffer which is currently in use') - - var w = Math.max(w_ | 0, 1) - var h = Math.max((h_ | 0) || w, 1) - if (w === framebuffer.width && h === framebuffer.height) { - return reglFramebuffer - } - - // resize all buffers - var colorAttachments = framebuffer.colorAttachments - for (var i = 0; i < colorAttachments.length; ++i) { - resizeAttachment(colorAttachments[i], w, h) - } - resizeAttachment(framebuffer.depthAttachment, w, h) - resizeAttachment(framebuffer.stencilAttachment, w, h) - resizeAttachment(framebuffer.depthStencilAttachment, w, h) - - framebuffer.width = reglFramebuffer.width = w - framebuffer.height = reglFramebuffer.height = h - - updateFramebuffer(framebuffer) - - return reglFramebuffer - } - - reglFramebuffer(a0, a1) - - return extend(reglFramebuffer, { - resize: resize, - _reglType: 'framebuffer', - _framebuffer: framebuffer, - destroy: function () { - destroy(framebuffer) - decFBORefs(framebuffer) - }, - use: function (block) { - framebufferState.setFBO({ - framebuffer: reglFramebuffer - }, block) - } - }) - } - - function createCubeFBO (options) { - var faces = Array(6) - - function reglFramebufferCube (a) { - var i - - check$1(faces.indexOf(framebufferState.next) < 0, - 'can not update framebuffer which is currently in use') - - var params = { - color: null - } - - var radius = 0 - - var colorBuffer = null - var colorFormat = 'rgba' - var colorType = 'uint8' - var colorCount = 1 - - if (typeof a === 'number') { - radius = a | 0 - } else if (!a) { - radius = 1 - } else { - check$1.type(a, 'object', 'invalid arguments for framebuffer') - var options = a - - if ('shape' in options) { - var shape = options.shape - check$1( - Array.isArray(shape) && shape.length >= 2, - 'invalid shape for framebuffer') - check$1( - shape[0] === shape[1], - 'cube framebuffer must be square') - radius = shape[0] - } else { - if ('radius' in options) { - radius = options.radius | 0 - } - if ('width' in options) { - radius = options.width | 0 - if ('height' in options) { - check$1(options.height === radius, 'must be square') - } - } else if ('height' in options) { - radius = options.height | 0 - } - } - - if ('color' in options || - 'colors' in options) { - colorBuffer = - options.color || - options.colors - if (Array.isArray(colorBuffer)) { - check$1( - colorBuffer.length === 1 || extensions.webgl_draw_buffers, - 'multiple render targets not supported') - } - } - - if (!colorBuffer) { - if ('colorCount' in options) { - colorCount = options.colorCount | 0 - check$1(colorCount > 0, 'invalid color buffer count') - } - - if ('colorType' in options) { - check$1.oneOf( - options.colorType, colorTypes, - 'invalid color type') - colorType = options.colorType - } - - if ('colorFormat' in options) { - colorFormat = options.colorFormat - check$1.oneOf( - options.colorFormat, colorTextureFormats, - 'invalid color format for texture') - } - } - - if ('depth' in options) { - params.depth = options.depth - } - - if ('stencil' in options) { - params.stencil = options.stencil - } - - if ('depthStencil' in options) { - params.depthStencil = options.depthStencil - } - } - - var colorCubes - if (colorBuffer) { - if (Array.isArray(colorBuffer)) { - colorCubes = [] - for (i = 0; i < colorBuffer.length; ++i) { - colorCubes[i] = colorBuffer[i] - } - } else { - colorCubes = [ colorBuffer ] - } - } else { - colorCubes = Array(colorCount) - var cubeMapParams = { - radius: radius, - format: colorFormat, - type: colorType - } - for (i = 0; i < colorCount; ++i) { - colorCubes[i] = textureState.createCube(cubeMapParams) - } - } - - // Check color cubes - params.color = Array(colorCubes.length) - for (i = 0; i < colorCubes.length; ++i) { - var cube = colorCubes[i] - check$1( - typeof cube === 'function' && cube._reglType === 'textureCube', - 'invalid cube map') - radius = radius || cube.width - check$1( - cube.width === radius && cube.height === radius, - 'invalid cube map shape') - params.color[i] = { - target: GL_TEXTURE_CUBE_MAP_POSITIVE_X$2, - data: colorCubes[i] - } - } - - for (i = 0; i < 6; ++i) { - for (var j = 0; j < colorCubes.length; ++j) { - params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 + i - } - // reuse depth-stencil attachments across all cube maps - if (i > 0) { - params.depth = faces[0].depth - params.stencil = faces[0].stencil - params.depthStencil = faces[0].depthStencil - } - if (faces[i]) { - (faces[i])(params) - } else { - faces[i] = createFBO(params) - } - } - - return extend(reglFramebufferCube, { - width: radius, - height: radius, - color: colorCubes - }) - } - - function resize (radius_) { - var i - var radius = radius_ | 0 - check$1(radius > 0 && radius <= limits.maxCubeMapSize, - 'invalid radius for cube fbo') - - if (radius === reglFramebufferCube.width) { - return reglFramebufferCube - } - - var colors = reglFramebufferCube.color - for (i = 0; i < colors.length; ++i) { - colors[i].resize(radius) - } - - for (i = 0; i < 6; ++i) { - faces[i].resize(radius) - } - - reglFramebufferCube.width = reglFramebufferCube.height = radius - - return reglFramebufferCube - } - - reglFramebufferCube(options) - - return extend(reglFramebufferCube, { - faces: faces, - resize: resize, - _reglType: 'framebufferCube', - destroy: function () { - faces.forEach(function (f) { - f.destroy() - }) - } - }) - } - - function restoreFramebuffers () { - framebufferState.cur = null - framebufferState.next = null - framebufferState.dirty = true - values(framebufferSet).forEach(function (fb) { - fb.framebuffer = gl.createFramebuffer() - updateFramebuffer(fb) - }) - } - - return extend(framebufferState, { - getFramebuffer: function (object) { - if (typeof object === 'function' && object._reglType === 'framebuffer') { - var fbo = object._framebuffer - if (fbo instanceof REGLFramebuffer) { - return fbo - } - } - return null - }, - create: createFBO, - createCube: createCubeFBO, - clear: function () { - values(framebufferSet).forEach(destroy) - }, - restore: restoreFramebuffers - }) -} - -var GL_FLOAT$6 = 5126 -var GL_ARRAY_BUFFER$1 = 34962 -var GL_ELEMENT_ARRAY_BUFFER$1 = 34963 - -var VAO_OPTIONS = [ - 'attributes', - 'elements', - 'offset', - 'count', - 'primitive', - 'instances' -] - -function AttributeRecord () { - this.state = 0 - - this.x = 0.0 - this.y = 0.0 - this.z = 0.0 - this.w = 0.0 - - this.buffer = null - this.size = 0 - this.normalized = false - this.type = GL_FLOAT$6 - this.offset = 0 - this.stride = 0 - this.divisor = 0 -} - -function wrapAttributeState ( - gl, - extensions, - limits, - stats, - bufferState, - elementState, - drawState) { - var NUM_ATTRIBUTES = limits.maxAttributes - var attributeBindings = new Array(NUM_ATTRIBUTES) - for (var i = 0; i < NUM_ATTRIBUTES; ++i) { - attributeBindings[i] = new AttributeRecord() - } - var vaoCount = 0 - var vaoSet = {} - - var state = { - Record: AttributeRecord, - scope: {}, - state: attributeBindings, - currentVAO: null, - targetVAO: null, - restore: extVAO() ? restoreVAO : function () {}, - createVAO: createVAO, - getVAO: getVAO, - destroyBuffer: destroyBuffer, - setVAO: extVAO() ? setVAOEXT : setVAOEmulated, - clear: extVAO() ? destroyVAOEXT : function () {} - } - - function destroyBuffer (buffer) { - for (var i = 0; i < attributeBindings.length; ++i) { - var record = attributeBindings[i] - if (record.buffer === buffer) { - gl.disableVertexAttribArray(i) - record.buffer = null - } - } - } - - function extVAO () { - return extensions.oes_vertex_array_object - } - - function extInstanced () { - return extensions.angle_instanced_arrays - } - - function getVAO (vao) { - if (typeof vao === 'function' && vao._vao) { - return vao._vao - } - return null - } - - function setVAOEXT (vao) { - if (vao === state.currentVAO) { - return - } - var ext = extVAO() - if (vao) { - ext.bindVertexArrayOES(vao.vao) - } else { - ext.bindVertexArrayOES(null) - } - state.currentVAO = vao - } - - function setVAOEmulated (vao) { - if (vao === state.currentVAO) { - return - } - if (vao) { - vao.bindAttrs() - } else { - var exti = extInstanced() - for (var i = 0; i < attributeBindings.length; ++i) { - var binding = attributeBindings[i] - if (binding.buffer) { - gl.enableVertexAttribArray(i) - binding.buffer.bind() - gl.vertexAttribPointer(i, binding.size, binding.type, binding.normalized, binding.stride, binding.offfset) - if (exti && binding.divisor) { - exti.vertexAttribDivisorANGLE(i, binding.divisor) - } - } else { - gl.disableVertexAttribArray(i) - gl.vertexAttrib4f(i, binding.x, binding.y, binding.z, binding.w) - } - } - if (drawState.elements) { - gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER$1, drawState.elements.buffer.buffer) - } else { - gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER$1, null) - } - } - state.currentVAO = vao - } - - function destroyVAOEXT () { - values(vaoSet).forEach(function (vao) { - vao.destroy() - }) - } - - function REGLVAO () { - this.id = ++vaoCount - this.attributes = [] - this.elements = null - this.ownsElements = false - this.count = 0 - this.offset = 0 - this.instances = -1 - this.primitive = 4 - var extension = extVAO() - if (extension) { - this.vao = extension.createVertexArrayOES() - } else { - this.vao = null - } - vaoSet[this.id] = this - this.buffers = [] - } - - REGLVAO.prototype.bindAttrs = function () { - var exti = extInstanced() - var attributes = this.attributes - for (var i = 0; i < attributes.length; ++i) { - var attr = attributes[i] - if (attr.buffer) { - gl.enableVertexAttribArray(i) - gl.bindBuffer(GL_ARRAY_BUFFER$1, attr.buffer.buffer) - gl.vertexAttribPointer(i, attr.size, attr.type, attr.normalized, attr.stride, attr.offset) - if (exti && attr.divisor) { - exti.vertexAttribDivisorANGLE(i, attr.divisor) - } - } else { - gl.disableVertexAttribArray(i) - gl.vertexAttrib4f(i, attr.x, attr.y, attr.z, attr.w) - } - } - for (var j = attributes.length; j < NUM_ATTRIBUTES; ++j) { - gl.disableVertexAttribArray(j) - } - var elements = elementState.getElements(this.elements) - if (elements) { - gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER$1, elements.buffer.buffer) - } else { - gl.bindBuffer(GL_ELEMENT_ARRAY_BUFFER$1, null) - } - } - - REGLVAO.prototype.refresh = function () { - var ext = extVAO() - if (ext) { - ext.bindVertexArrayOES(this.vao) - this.bindAttrs() - state.currentVAO = null - ext.bindVertexArrayOES(null) - } - } - - REGLVAO.prototype.destroy = function () { - if (this.vao) { - var extension = extVAO() - if (this === state.currentVAO) { - state.currentVAO = null - extension.bindVertexArrayOES(null) - } - extension.deleteVertexArrayOES(this.vao) - this.vao = null - } - if (this.ownsElements) { - this.elements.destroy() - this.elements = null - this.ownsElements = false - } - if (vaoSet[this.id]) { - delete vaoSet[this.id] - stats.vaoCount -= 1 - } - } - - function restoreVAO () { - var ext = extVAO() - if (ext) { - values(vaoSet).forEach(function (vao) { - vao.refresh() - }) - } - } - - function createVAO (_attr) { - var vao = new REGLVAO() - stats.vaoCount += 1 - - function updateVAO (options) { - var attributes - if (Array.isArray(options)) { - attributes = options - if (vao.elements && vao.ownsElements) { - vao.elements.destroy() - } - vao.elements = null - vao.ownsElements = false - vao.offset = 0 - vao.count = 0 - vao.instances = -1 - vao.primitive = 4 - } else { - check$1(typeof options === 'object', 'invalid arguments for create vao') - check$1('attributes' in options, 'must specify attributes for vao') - if (options.elements) { - var elements = options.elements - if (vao.ownsElements) { - if (typeof elements === 'function' && elements._reglType === 'elements') { - vao.elements.destroy() - vao.ownsElements = false - } else { - vao.elements(elements) - vao.ownsElements = false - } - } else if (elementState.getElements(options.elements)) { - vao.elements = options.elements - vao.ownsElements = false - } else { - vao.elements = elementState.create(options.elements) - vao.ownsElements = true - } - } else { - vao.elements = null - vao.ownsElements = false - } - attributes = options.attributes - - // set default vao - vao.offset = 0 - vao.count = -1 - vao.instances = -1 - vao.primitive = 4 - - // copy element properties - if (vao.elements) { - vao.count = vao.elements._elements.vertCount - vao.primitive = vao.elements._elements.primType - } - - if ('offset' in options) { - vao.offset = options.offset | 0 - } - if ('count' in options) { - vao.count = options.count | 0 - } - if ('instances' in options) { - vao.instances = options.instances | 0 - } - if ('primitive' in options) { - check$1(options.primitive in primTypes, 'bad primitive type: ' + options.primitive) - vao.primitive = primTypes[options.primitive] - } - - check$1.optional(() => { - var keys = Object.keys(options) - for (var i = 0; i < keys.length; ++i) { - check$1(VAO_OPTIONS.indexOf(keys[i]) >= 0, 'invalid option for vao: "' + keys[i] + '" valid options are ' + VAO_OPTIONS) - } - }) - check$1(Array.isArray(attributes), 'attributes must be an array') - } - - check$1(attributes.length < NUM_ATTRIBUTES, 'too many attributes') - check$1(attributes.length > 0, 'must specify at least one attribute') - - var bufUpdated = {} - var nattributes = vao.attributes - nattributes.length = attributes.length - for (var i = 0; i < attributes.length; ++i) { - var spec = attributes[i] - var rec = nattributes[i] = new AttributeRecord() - var data = spec.data || spec - if (Array.isArray(data) || isTypedArray(data) || isNDArrayLike(data)) { - var buf - if (vao.buffers[i]) { - buf = vao.buffers[i] - if (isTypedArray(data) && buf._buffer.byteLength >= data.byteLength) { - buf.subdata(data) - } else { - buf.destroy() - vao.buffers[i] = null - } - } - if (!vao.buffers[i]) { - buf = vao.buffers[i] = bufferState.create(spec, GL_ARRAY_BUFFER$1, false, true) - } - rec.buffer = bufferState.getBuffer(buf) - rec.size = rec.buffer.dimension | 0 - rec.normalized = false - rec.type = rec.buffer.dtype - rec.offset = 0 - rec.stride = 0 - rec.divisor = 0 - rec.state = 1 - bufUpdated[i] = 1 - } else if (bufferState.getBuffer(spec)) { - rec.buffer = bufferState.getBuffer(spec) - rec.size = rec.buffer.dimension | 0 - rec.normalized = false - rec.type = rec.buffer.dtype - rec.offset = 0 - rec.stride = 0 - rec.divisor = 0 - rec.state = 1 - } else if (bufferState.getBuffer(spec.buffer)) { - rec.buffer = bufferState.getBuffer(spec.buffer) - rec.size = ((+spec.size) || rec.buffer.dimension) | 0 - rec.normalized = !!spec.normalized || false - if ('type' in spec) { - check$1.parameter(spec.type, glTypes, 'invalid buffer type') - rec.type = glTypes[spec.type] - } else { - rec.type = rec.buffer.dtype - } - rec.offset = (spec.offset || 0) | 0 - rec.stride = (spec.stride || 0) | 0 - rec.divisor = (spec.divisor || 0) | 0 - rec.state = 1 - - check$1(rec.size >= 1 && rec.size <= 4, 'size must be between 1 and 4') - check$1(rec.offset >= 0, 'invalid offset') - check$1(rec.stride >= 0 && rec.stride <= 255, 'stride must be between 0 and 255') - check$1(rec.divisor >= 0, 'divisor must be positive') - check$1(!rec.divisor || !!extensions.angle_instanced_arrays, 'ANGLE_instanced_arrays must be enabled to use divisor') - } else if ('x' in spec) { - check$1(i > 0, 'first attribute must not be a constant') - rec.x = +spec.x || 0 - rec.y = +spec.y || 0 - rec.z = +spec.z || 0 - rec.w = +spec.w || 0 - rec.state = 2 - } else { - check$1(false, 'invalid attribute spec for location ' + i) - } - } - - // retire unused buffers - for (var j = 0; j < vao.buffers.length; ++j) { - if (!bufUpdated[j] && vao.buffers[j]) { - vao.buffers[j].destroy() - vao.buffers[j] = null - } - } - - vao.refresh() - return updateVAO - } - - updateVAO.destroy = function () { - for (var j = 0; j < vao.buffers.length; ++j) { - if (vao.buffers[j]) { - vao.buffers[j].destroy() - } - } - vao.buffers.length = 0 - - if (vao.ownsElements) { - vao.elements.destroy() - vao.elements = null - vao.ownsElements = false - } - - vao.destroy() - } - - updateVAO._vao = vao - updateVAO._reglType = 'vao' - - return updateVAO(_attr) - } - - return state -} - -var GL_FRAGMENT_SHADER = 35632 -var GL_VERTEX_SHADER = 35633 - -var GL_ACTIVE_UNIFORMS = 0x8B86 -var GL_ACTIVE_ATTRIBUTES = 0x8B89 - -function wrapShaderState (gl, stringStore, stats, config) { - // =================================================== - // glsl compilation and linking - // =================================================== - var fragShaders = {} - var vertShaders = {} - - function ActiveInfo (name, id, location, info) { - this.name = name - this.id = id - this.location = location - this.info = info - } - - function insertActiveInfo (list, info) { - for (var i = 0; i < list.length; ++i) { - if (list[i].id === info.id) { - list[i].location = info.location - return - } - } - list.push(info) - } - - function getShader (type, id, command) { - var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders - var shader = cache[id] - - if (!shader) { - var source = stringStore.str(id) - shader = gl.createShader(type) - gl.shaderSource(shader, source) - gl.compileShader(shader) - check$1.shaderError(gl, shader, source, type, command) - cache[id] = shader - } - - return shader - } - - // =================================================== - // program linking - // =================================================== - var programCache = {} - var programList = [] - - var PROGRAM_COUNTER = 0 - - function REGLProgram (fragId, vertId) { - this.id = PROGRAM_COUNTER++ - this.fragId = fragId - this.vertId = vertId - this.program = null - this.uniforms = [] - this.attributes = [] - this.refCount = 1 - - if (config.profile) { - this.stats = { - uniformsCount: 0, - attributesCount: 0 - } - } - } - - function linkProgram (desc, command, attributeLocations) { - var i, info - - // ------------------------------- - // compile & link - // ------------------------------- - var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId) - var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId) - - var program = desc.program = gl.createProgram() - gl.attachShader(program, fragShader) - gl.attachShader(program, vertShader) - if (attributeLocations) { - for (i = 0; i < attributeLocations.length; ++i) { - var binding = attributeLocations[i] - gl.bindAttribLocation(program, binding[0], binding[1]) - } - } - - gl.linkProgram(program) - check$1.linkError( - gl, - program, - stringStore.str(desc.fragId), - stringStore.str(desc.vertId), - command) - - // ------------------------------- - // grab uniforms - // ------------------------------- - var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS) - if (config.profile) { - desc.stats.uniformsCount = numUniforms - } - var uniforms = desc.uniforms - for (i = 0; i < numUniforms; ++i) { - info = gl.getActiveUniform(program, i) - if (info) { - if (info.size > 1) { - for (var j = 0; j < info.size; ++j) { - var name = info.name.replace('[0]', '[' + j + ']') - insertActiveInfo(uniforms, new ActiveInfo( - name, - stringStore.id(name), - gl.getUniformLocation(program, name), - info)) - } - } - var uniName = info.name - if (info.size > 1) { - uniName = uniName.replace('[0]', '') - } - insertActiveInfo(uniforms, new ActiveInfo( - uniName, - stringStore.id(uniName), - gl.getUniformLocation(program, uniName), - info)) - } - } - - // ------------------------------- - // grab attributes - // ------------------------------- - var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES) - if (config.profile) { - desc.stats.attributesCount = numAttributes - } - - var attributes = desc.attributes - for (i = 0; i < numAttributes; ++i) { - info = gl.getActiveAttrib(program, i) - if (info) { - insertActiveInfo(attributes, new ActiveInfo( - info.name, - stringStore.id(info.name), - gl.getAttribLocation(program, info.name), - info)) - } - } - } - - if (config.profile) { - stats.getMaxUniformsCount = function () { - var m = 0 - programList.forEach(function (desc) { - if (desc.stats.uniformsCount > m) { - m = desc.stats.uniformsCount - } - }) - return m - } - - stats.getMaxAttributesCount = function () { - var m = 0 - programList.forEach(function (desc) { - if (desc.stats.attributesCount > m) { - m = desc.stats.attributesCount - } - }) - return m - } - } - - function restoreShaders () { - fragShaders = {} - vertShaders = {} - for (var i = 0; i < programList.length; ++i) { - linkProgram(programList[i], null, programList[i].attributes.map(function (info) { - return [info.location, info.name] - })) - } - } - - return { - clear: function () { - var deleteShader = gl.deleteShader.bind(gl) - values(fragShaders).forEach(deleteShader) - fragShaders = {} - values(vertShaders).forEach(deleteShader) - vertShaders = {} - - programList.forEach(function (desc) { - gl.deleteProgram(desc.program) - }) - programList.length = 0 - programCache = {} - - stats.shaderCount = 0 - }, - - program: function (vertId, fragId, command, attribLocations) { - check$1.command(vertId >= 0, 'missing vertex shader', command) - check$1.command(fragId >= 0, 'missing fragment shader', command) - - var cache = programCache[fragId] - if (!cache) { - cache = programCache[fragId] = {} - } - var prevProgram = cache[vertId] - if (prevProgram) { - prevProgram.refCount++ - if (!attribLocations) { - return prevProgram - } - } - var program = new REGLProgram(fragId, vertId) - stats.shaderCount++ - linkProgram(program, command, attribLocations) - if (!prevProgram) { - cache[vertId] = program - } - programList.push(program) - return extend(program, { - destroy: function () { - program.refCount-- - if (program.refCount <= 0) { - gl.deleteProgram(program.program) - var idx = programList.indexOf(program) - programList.splice(idx, 1) - stats.shaderCount-- - } - // no program is linked to this vert anymore - if (cache[program.vertId].refCount <= 0) { - gl.deleteShader(vertShaders[program.vertId]) - delete vertShaders[program.vertId] - delete programCache[program.fragId][program.vertId] - } - // no program is linked to this frag anymore - if (!Object.keys(programCache[program.fragId]).length) { - gl.deleteShader(fragShaders[program.fragId]) - delete fragShaders[program.fragId] - delete programCache[program.fragId] - } - } - }) - }, - - restore: restoreShaders, - - shader: getShader, - - frag: -1, - vert: -1 - } -} - -var GL_RGBA$3 = 6408 -var GL_UNSIGNED_BYTE$7 = 5121 -var GL_PACK_ALIGNMENT = 0x0D05 -var GL_FLOAT$7 = 0x1406 // 5126 - -function wrapReadPixels ( - gl, - framebufferState, - reglPoll, - context, - glAttributes, - extensions, - limits) { - function readPixelsImpl (input) { - var type - if (framebufferState.next === null) { - check$1( - glAttributes.preserveDrawingBuffer, - 'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer') - type = GL_UNSIGNED_BYTE$7 - } else { - check$1( - framebufferState.next.colorAttachments[0].texture !== null, - 'You cannot read from a renderbuffer') - type = framebufferState.next.colorAttachments[0].texture._texture.type - - check$1.optional(function () { - if (extensions.oes_texture_float) { - check$1( - type === GL_UNSIGNED_BYTE$7 || type === GL_FLOAT$7, - 'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\'') - - if (type === GL_FLOAT$7) { - check$1(limits.readFloat, 'Reading \'float\' values is not permitted in your browser. For a fallback, please see: https://www.npmjs.com/package/glsl-read-float') - } - } else { - check$1( - type === GL_UNSIGNED_BYTE$7, - 'Reading from a framebuffer is only allowed for the type \'uint8\'') - } - }) - } - - var x = 0 - var y = 0 - var width = context.framebufferWidth - var height = context.framebufferHeight - var data = null - - if (isTypedArray(input)) { - data = input - } else if (input) { - check$1.type(input, 'object', 'invalid arguments to regl.read()') - x = input.x | 0 - y = input.y | 0 - check$1( - x >= 0 && x < context.framebufferWidth, - 'invalid x offset for regl.read') - check$1( - y >= 0 && y < context.framebufferHeight, - 'invalid y offset for regl.read') - width = (input.width || (context.framebufferWidth - x)) | 0 - height = (input.height || (context.framebufferHeight - y)) | 0 - data = input.data || null - } - - // sanity check input.data - if (data) { - if (type === GL_UNSIGNED_BYTE$7) { - check$1( - data instanceof Uint8Array, - 'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\'') - } else if (type === GL_FLOAT$7) { - check$1( - data instanceof Float32Array, - 'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\'') - } - } - - check$1( - width > 0 && width + x <= context.framebufferWidth, - 'invalid width for read pixels') - check$1( - height > 0 && height + y <= context.framebufferHeight, - 'invalid height for read pixels') - - // Update WebGL state - reglPoll() - - // Compute size - var size = width * height * 4 - - // Allocate data - if (!data) { - if (type === GL_UNSIGNED_BYTE$7) { - data = new Uint8Array(size) - } else if (type === GL_FLOAT$7) { - data = data || new Float32Array(size) - } - } - - // Type check - check$1.isTypedArray(data, 'data buffer for regl.read() must be a typedarray') - check$1(data.byteLength >= size, 'data buffer for regl.read() too small') - - // Run read pixels - gl.pixelStorei(GL_PACK_ALIGNMENT, 4) - gl.readPixels(x, y, width, height, GL_RGBA$3, - type, - data) - - return data - } - - function readPixelsFBO (options) { - var result - framebufferState.setFBO({ - framebuffer: options.framebuffer - }, function () { - result = readPixelsImpl(options) - }) - return result - } - - function readPixels (options) { - if (!options || !('framebuffer' in options)) { - return readPixelsImpl(options) - } else { - return readPixelsFBO(options) - } - } - - return readPixels -} - -function slice (x) { - return Array.prototype.slice.call(x) -} - -function join (x) { - return slice(x).join('') -} - -function createEnvironment () { - // Unique variable id counter - var varCounter = 0 - - // Linked values are passed from this scope into the generated code block - // Calling link() passes a value into the generated scope and returns - // the variable name which it is bound to - var linkedNames = [] - var linkedValues = [] - function link (value) { - for (var i = 0; i < linkedValues.length; ++i) { - if (linkedValues[i] === value) { - return linkedNames[i] - } - } - - var name = 'g' + (varCounter++) - linkedNames.push(name) - linkedValues.push(value) - return name - } - - // create a code block - function block () { - var code = [] - function push () { - code.push.apply(code, slice(arguments)) - } - - var vars = [] - function def () { - var name = 'v' + (varCounter++) - vars.push(name) - - if (arguments.length > 0) { - code.push(name, '=') - code.push.apply(code, slice(arguments)) - code.push(';') - } - - return name - } - - return extend(push, { - def: def, - toString: function () { - return join([ - (vars.length > 0 ? 'var ' + vars.join(',') + ';' : ''), - join(code) - ]) - } - }) - } - - function scope () { - var entry = block() - var exit = block() - - var entryToString = entry.toString - var exitToString = exit.toString - - function save (object, prop) { - exit(object, prop, '=', entry.def(object, prop), ';') - } - - return extend(function () { - entry.apply(entry, slice(arguments)) - }, { - def: entry.def, - entry: entry, - exit: exit, - save: save, - set: function (object, prop, value) { - save(object, prop) - entry(object, prop, '=', value, ';') - }, - toString: function () { - return entryToString() + exitToString() - } - }) - } - - function conditional () { - var pred = join(arguments) - var thenBlock = scope() - var elseBlock = scope() - - var thenToString = thenBlock.toString - var elseToString = elseBlock.toString - - return extend(thenBlock, { - then: function () { - thenBlock.apply(thenBlock, slice(arguments)) - return this - }, - else: function () { - elseBlock.apply(elseBlock, slice(arguments)) - return this - }, - toString: function () { - var elseClause = elseToString() - if (elseClause) { - elseClause = 'else{' + elseClause + '}' - } - return join([ - 'if(', pred, '){', - thenToString(), - '}', elseClause - ]) - } - }) - } - - // procedure list - var globalBlock = block() - var procedures = {} - function proc (name, count) { - var args = [] - function arg () { - var name = 'a' + args.length - args.push(name) - return name - } - - count = count || 0 - for (var i = 0; i < count; ++i) { - arg() - } - - var body = scope() - var bodyToString = body.toString - - var result = procedures[name] = extend(body, { - arg: arg, - toString: function () { - return join([ - 'function(', args.join(), '){', - bodyToString(), - '}' - ]) - } - }) - - return result - } - - function compile () { - var code = ['"use strict";', - globalBlock, - 'return {'] - Object.keys(procedures).forEach(function (name) { - code.push('"', name, '":', procedures[name].toString(), ',') - }) - code.push('}') - var src = join(code) - .replace(/;/g, ';\n') - .replace(/}/g, '}\n') - .replace(/{/g, '{\n') - var proc = Function.apply(null, linkedNames.concat(src)) - return proc.apply(null, linkedValues) - } - - return { - global: globalBlock, - link: link, - block: block, - proc: proc, - scope: scope, - cond: conditional, - compile: compile - } -} - -// "cute" names for vector components -var CUTE_COMPONENTS = 'xyzw'.split('') - -var GL_UNSIGNED_BYTE$8 = 5121 - -var ATTRIB_STATE_POINTER = 1 -var ATTRIB_STATE_CONSTANT = 2 - -var DYN_FUNC$1 = 0 -var DYN_PROP$1 = 1 -var DYN_CONTEXT$1 = 2 -var DYN_STATE$1 = 3 -var DYN_THUNK = 4 -var DYN_CONSTANT$1 = 5 -var DYN_ARRAY$1 = 6 - -var S_DITHER = 'dither' -var S_BLEND_ENABLE = 'blend.enable' -var S_BLEND_COLOR = 'blend.color' -var S_BLEND_EQUATION = 'blend.equation' -var S_BLEND_FUNC = 'blend.func' -var S_DEPTH_ENABLE = 'depth.enable' -var S_DEPTH_FUNC = 'depth.func' -var S_DEPTH_RANGE = 'depth.range' -var S_DEPTH_MASK = 'depth.mask' -var S_COLOR_MASK = 'colorMask' -var S_CULL_ENABLE = 'cull.enable' -var S_CULL_FACE = 'cull.face' -var S_FRONT_FACE = 'frontFace' -var S_LINE_WIDTH = 'lineWidth' -var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable' -var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset' -var S_SAMPLE_ALPHA = 'sample.alpha' -var S_SAMPLE_ENABLE = 'sample.enable' -var S_SAMPLE_COVERAGE = 'sample.coverage' -var S_STENCIL_ENABLE = 'stencil.enable' -var S_STENCIL_MASK = 'stencil.mask' -var S_STENCIL_FUNC = 'stencil.func' -var S_STENCIL_OPFRONT = 'stencil.opFront' -var S_STENCIL_OPBACK = 'stencil.opBack' -var S_SCISSOR_ENABLE = 'scissor.enable' -var S_SCISSOR_BOX = 'scissor.box' -var S_VIEWPORT = 'viewport' - -var S_PROFILE = 'profile' - -var S_FRAMEBUFFER = 'framebuffer' -var S_VERT = 'vert' -var S_FRAG = 'frag' -var S_ELEMENTS = 'elements' -var S_PRIMITIVE = 'primitive' -var S_COUNT = 'count' -var S_OFFSET = 'offset' -var S_INSTANCES = 'instances' -var S_VAO = 'vao' - -var SUFFIX_WIDTH = 'Width' -var SUFFIX_HEIGHT = 'Height' - -var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH -var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT -var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH -var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT -var S_DRAWINGBUFFER = 'drawingBuffer' -var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH -var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT - -var NESTED_OPTIONS = [ - S_BLEND_FUNC, - S_BLEND_EQUATION, - S_STENCIL_FUNC, - S_STENCIL_OPFRONT, - S_STENCIL_OPBACK, - S_SAMPLE_COVERAGE, - S_VIEWPORT, - S_SCISSOR_BOX, - S_POLYGON_OFFSET_OFFSET -] - -var GL_ARRAY_BUFFER$2 = 34962 -var GL_ELEMENT_ARRAY_BUFFER$2 = 34963 - -var GL_FRAGMENT_SHADER$1 = 35632 -var GL_VERTEX_SHADER$1 = 35633 - -var GL_TEXTURE_2D$3 = 0x0DE1 -var GL_TEXTURE_CUBE_MAP$2 = 0x8513 - -var GL_CULL_FACE = 0x0B44 -var GL_BLEND = 0x0BE2 -var GL_DITHER = 0x0BD0 -var GL_STENCIL_TEST = 0x0B90 -var GL_DEPTH_TEST = 0x0B71 -var GL_SCISSOR_TEST = 0x0C11 -var GL_POLYGON_OFFSET_FILL = 0x8037 -var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E -var GL_SAMPLE_COVERAGE = 0x80A0 - -var GL_FLOAT$8 = 5126 -var GL_FLOAT_VEC2 = 35664 -var GL_FLOAT_VEC3 = 35665 -var GL_FLOAT_VEC4 = 35666 -var GL_INT$3 = 5124 -var GL_INT_VEC2 = 35667 -var GL_INT_VEC3 = 35668 -var GL_INT_VEC4 = 35669 -var GL_BOOL = 35670 -var GL_BOOL_VEC2 = 35671 -var GL_BOOL_VEC3 = 35672 -var GL_BOOL_VEC4 = 35673 -var GL_FLOAT_MAT2 = 35674 -var GL_FLOAT_MAT3 = 35675 -var GL_FLOAT_MAT4 = 35676 -var GL_SAMPLER_2D = 35678 -var GL_SAMPLER_CUBE = 35680 - -var GL_TRIANGLES$1 = 4 - -var GL_FRONT = 1028 -var GL_BACK = 1029 -var GL_CW = 0x0900 -var GL_CCW = 0x0901 -var GL_MIN_EXT = 0x8007 -var GL_MAX_EXT = 0x8008 -var GL_ALWAYS = 519 -var GL_KEEP = 7680 -var GL_ZERO = 0 -var GL_ONE = 1 -var GL_FUNC_ADD = 0x8006 -var GL_LESS = 513 - -var GL_FRAMEBUFFER$2 = 0x8D40 -var GL_COLOR_ATTACHMENT0$2 = 0x8CE0 - -var blendFuncs = { - '0': 0, - '1': 1, - 'zero': 0, - 'one': 1, - 'src color': 768, - 'one minus src color': 769, - 'src alpha': 770, - 'one minus src alpha': 771, - 'dst color': 774, - 'one minus dst color': 775, - 'dst alpha': 772, - 'one minus dst alpha': 773, - 'constant color': 32769, - 'one minus constant color': 32770, - 'constant alpha': 32771, - 'one minus constant alpha': 32772, - 'src alpha saturate': 776 -} - -// There are invalid values for srcRGB and dstRGB. See: -// https://www.khronos.org/registry/webgl/specs/1.0/#6.13 -// https://github.com/KhronosGroup/WebGL/blob/0d3201f5f7ec3c0060bc1f04077461541f1987b9/conformance-suites/1.0.3/conformance/misc/webgl-specific.html#L56 -var invalidBlendCombinations = [ - 'constant color, constant alpha', - 'one minus constant color, constant alpha', - 'constant color, one minus constant alpha', - 'one minus constant color, one minus constant alpha', - 'constant alpha, constant color', - 'constant alpha, one minus constant color', - 'one minus constant alpha, constant color', - 'one minus constant alpha, one minus constant color' -] - -var compareFuncs = { - 'never': 512, - 'less': 513, - '<': 513, - 'equal': 514, - '=': 514, - '==': 514, - '===': 514, - 'lequal': 515, - '<=': 515, - 'greater': 516, - '>': 516, - 'notequal': 517, - '!=': 517, - '!==': 517, - 'gequal': 518, - '>=': 518, - 'always': 519 -} - -var stencilOps = { - '0': 0, - 'zero': 0, - 'keep': 7680, - 'replace': 7681, - 'increment': 7682, - 'decrement': 7683, - 'increment wrap': 34055, - 'decrement wrap': 34056, - 'invert': 5386 -} - -var shaderType = { - 'frag': GL_FRAGMENT_SHADER$1, - 'vert': GL_VERTEX_SHADER$1 -} - -var orientationType = { - 'cw': GL_CW, - 'ccw': GL_CCW -} - -function isBufferArgs (x) { - return Array.isArray(x) || - isTypedArray(x) || - isNDArrayLike(x) -} - -// Make sure viewport is processed first -function sortState (state) { - return state.sort(function (a, b) { - if (a === S_VIEWPORT) { - return -1 - } else if (b === S_VIEWPORT) { - return 1 - } - return (a < b) ? -1 : 1 - }) -} - -function Declaration (thisDep, contextDep, propDep, append) { - this.thisDep = thisDep - this.contextDep = contextDep - this.propDep = propDep - this.append = append -} - -function isStatic (decl) { - return decl && !(decl.thisDep || decl.contextDep || decl.propDep) -} - -function createStaticDecl (append) { - return new Declaration(false, false, false, append) -} - -function createDynamicDecl (dyn, append) { - var type = dyn.type - if (type === DYN_FUNC$1) { - var numArgs = dyn.data.length - return new Declaration( - true, - numArgs >= 1, - numArgs >= 2, - append) - } else if (type === DYN_THUNK) { - var data = dyn.data - return new Declaration( - data.thisDep, - data.contextDep, - data.propDep, - append) - } else if (type === DYN_CONSTANT$1) { - return new Declaration( - false, - false, - false, - append) - } else if (type === DYN_ARRAY$1) { - var thisDep = false - var contextDep = false - var propDep = false - for (var i = 0; i < dyn.data.length; ++i) { - var subDyn = dyn.data[i] - if (subDyn.type === DYN_PROP$1) { - propDep = true - } else if (subDyn.type === DYN_CONTEXT$1) { - contextDep = true - } else if (subDyn.type === DYN_STATE$1) { - thisDep = true - } else if (subDyn.type === DYN_FUNC$1) { - thisDep = true - var subArgs = subDyn.data - if (subArgs >= 1) { - contextDep = true - } - if (subArgs >= 2) { - propDep = true - } - } else if (subDyn.type === DYN_THUNK) { - thisDep = thisDep || subDyn.data.thisDep - contextDep = contextDep || subDyn.data.contextDep - propDep = propDep || subDyn.data.propDep - } - } - return new Declaration( - thisDep, - contextDep, - propDep, - append) - } else { - return new Declaration( - type === DYN_STATE$1, - type === DYN_CONTEXT$1, - type === DYN_PROP$1, - append) - } -} - -var SCOPE_DECL = new Declaration(false, false, false, function () {}) - -function reglCore ( - gl, - stringStore, - extensions, - limits, - bufferState, - elementState, - textureState, - framebufferState, - uniformState, - attributeState, - shaderState, - drawState, - contextState, - timer, - config) { - var AttributeRecord = attributeState.Record - - var blendEquations = { - 'add': 32774, - 'subtract': 32778, - 'reverse subtract': 32779 - } - if (extensions.ext_blend_minmax) { - blendEquations.min = GL_MIN_EXT - blendEquations.max = GL_MAX_EXT - } - - var extInstancing = extensions.angle_instanced_arrays - var extDrawBuffers = extensions.webgl_draw_buffers - var extVertexArrays = extensions.oes_vertex_array_object - - // =================================================== - // =================================================== - // WEBGL STATE - // =================================================== - // =================================================== - var currentState = { - dirty: true, - profile: config.profile - } - var nextState = {} - var GL_STATE_NAMES = [] - var GL_FLAGS = {} - var GL_VARIABLES = {} - - function propName (name) { - return name.replace('.', '_') - } - - function stateFlag (sname, cap, init) { - var name = propName(sname) - GL_STATE_NAMES.push(sname) - nextState[name] = currentState[name] = !!init - GL_FLAGS[name] = cap - } - - function stateVariable (sname, func, init) { - var name = propName(sname) - GL_STATE_NAMES.push(sname) - if (Array.isArray(init)) { - currentState[name] = init.slice() - nextState[name] = init.slice() - } else { - currentState[name] = nextState[name] = init - } - GL_VARIABLES[name] = func - } - - // Dithering - stateFlag(S_DITHER, GL_DITHER) - - // Blending - stateFlag(S_BLEND_ENABLE, GL_BLEND) - stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0]) - stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate', - [GL_FUNC_ADD, GL_FUNC_ADD]) - stateVariable(S_BLEND_FUNC, 'blendFuncSeparate', - [GL_ONE, GL_ZERO, GL_ONE, GL_ZERO]) - - // Depth - stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true) - stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS) - stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1]) - stateVariable(S_DEPTH_MASK, 'depthMask', true) - - // Color mask - stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true]) - - // Face culling - stateFlag(S_CULL_ENABLE, GL_CULL_FACE) - stateVariable(S_CULL_FACE, 'cullFace', GL_BACK) - - // Front face orientation - stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW) - - // Line width - stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1) - - // Polygon offset - stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL) - stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0]) - - // Sample coverage - stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE) - stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE) - stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false]) - - // Stencil - stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST) - stateVariable(S_STENCIL_MASK, 'stencilMask', -1) - stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1]) - stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate', - [GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP]) - stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate', - [GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP]) - - // Scissor - stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST) - stateVariable(S_SCISSOR_BOX, 'scissor', - [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]) - - // Viewport - stateVariable(S_VIEWPORT, S_VIEWPORT, - [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]) - - // =================================================== - // =================================================== - // ENVIRONMENT - // =================================================== - // =================================================== - var sharedState = { - gl: gl, - context: contextState, - strings: stringStore, - next: nextState, - current: currentState, - draw: drawState, - elements: elementState, - buffer: bufferState, - shader: shaderState, - attributes: attributeState.state, - vao: attributeState, - uniforms: uniformState, - framebuffer: framebufferState, - extensions: extensions, - - timer: timer, - isBufferArgs: isBufferArgs - } - - var sharedConstants = { - primTypes: primTypes, - compareFuncs: compareFuncs, - blendFuncs: blendFuncs, - blendEquations: blendEquations, - stencilOps: stencilOps, - glTypes: glTypes, - orientationType: orientationType - } - - check$1.optional(function () { - sharedState.isArrayLike = isArrayLike - }) - - if (extDrawBuffers) { - sharedConstants.backBuffer = [GL_BACK] - sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) { - if (i === 0) { - return [0] - } - return loop(i, function (j) { - return GL_COLOR_ATTACHMENT0$2 + j - }) - }) - } - - var drawCallCounter = 0 - function createREGLEnvironment () { - var env = createEnvironment() - var link = env.link - var global = env.global - env.id = drawCallCounter++ - - env.batchId = '0' - - // link shared state - var SHARED = link(sharedState) - var shared = env.shared = { - props: 'a0' - } - Object.keys(sharedState).forEach(function (prop) { - shared[prop] = global.def(SHARED, '.', prop) - }) - - // Inject runtime assertion stuff for debug builds - check$1.optional(function () { - env.CHECK = link(check$1) - env.commandStr = check$1.guessCommand() - env.command = link(env.commandStr) - env.assert = function (block, pred, message) { - block( - 'if(!(', pred, '))', - this.CHECK, '.commandRaise(', link(message), ',', this.command, ');') - } - - sharedConstants.invalidBlendCombinations = invalidBlendCombinations - }) - - // Copy GL state variables over - var nextVars = env.next = {} - var currentVars = env.current = {} - Object.keys(GL_VARIABLES).forEach(function (variable) { - if (Array.isArray(currentState[variable])) { - nextVars[variable] = global.def(shared.next, '.', variable) - currentVars[variable] = global.def(shared.current, '.', variable) - } - }) - - // Initialize shared constants - var constants = env.constants = {} - Object.keys(sharedConstants).forEach(function (name) { - constants[name] = global.def(JSON.stringify(sharedConstants[name])) - }) - - // Helper function for calling a block - env.invoke = function (block, x) { - switch (x.type) { - case DYN_FUNC$1: - var argList = [ - 'this', - shared.context, - shared.props, - env.batchId - ] - return block.def( - link(x.data), '.call(', - argList.slice(0, Math.max(x.data.length + 1, 4)), - ')') - case DYN_PROP$1: - return block.def(shared.props, x.data) - case DYN_CONTEXT$1: - return block.def(shared.context, x.data) - case DYN_STATE$1: - return block.def('this', x.data) - case DYN_THUNK: - x.data.append(env, block) - return x.data.ref - case DYN_CONSTANT$1: - return x.data.toString() - case DYN_ARRAY$1: - return x.data.map(function (y) { - return env.invoke(block, y) - }) - } - } - - env.attribCache = {} - - var scopeAttribs = {} - env.scopeAttrib = function (name) { - var id = stringStore.id(name) - if (id in scopeAttribs) { - return scopeAttribs[id] - } - var binding = attributeState.scope[id] - if (!binding) { - binding = attributeState.scope[id] = new AttributeRecord() - } - var result = scopeAttribs[id] = link(binding) - return result - } - - return env - } - - // =================================================== - // =================================================== - // PARSING - // =================================================== - // =================================================== - function parseProfile (options) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - var profileEnable - if (S_PROFILE in staticOptions) { - var value = !!staticOptions[S_PROFILE] - profileEnable = createStaticDecl(function (env, scope) { - return value - }) - profileEnable.enable = value - } else if (S_PROFILE in dynamicOptions) { - var dyn = dynamicOptions[S_PROFILE] - profileEnable = createDynamicDecl(dyn, function (env, scope) { - return env.invoke(scope, dyn) - }) - } - - return profileEnable - } - - function parseFramebuffer (options, env) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - if (S_FRAMEBUFFER in staticOptions) { - var framebuffer = staticOptions[S_FRAMEBUFFER] - if (framebuffer) { - framebuffer = framebufferState.getFramebuffer(framebuffer) - check$1.command(framebuffer, 'invalid framebuffer object') - return createStaticDecl(function (env, block) { - var FRAMEBUFFER = env.link(framebuffer) - var shared = env.shared - block.set( - shared.framebuffer, - '.next', - FRAMEBUFFER) - var CONTEXT = shared.context - block.set( - CONTEXT, - '.' + S_FRAMEBUFFER_WIDTH, - FRAMEBUFFER + '.width') - block.set( - CONTEXT, - '.' + S_FRAMEBUFFER_HEIGHT, - FRAMEBUFFER + '.height') - return FRAMEBUFFER - }) - } else { - return createStaticDecl(function (env, scope) { - var shared = env.shared - scope.set( - shared.framebuffer, - '.next', - 'null') - var CONTEXT = shared.context - scope.set( - CONTEXT, - '.' + S_FRAMEBUFFER_WIDTH, - CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH) - scope.set( - CONTEXT, - '.' + S_FRAMEBUFFER_HEIGHT, - CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT) - return 'null' - }) - } - } else if (S_FRAMEBUFFER in dynamicOptions) { - var dyn = dynamicOptions[S_FRAMEBUFFER] - return createDynamicDecl(dyn, function (env, scope) { - var FRAMEBUFFER_FUNC = env.invoke(scope, dyn) - var shared = env.shared - var FRAMEBUFFER_STATE = shared.framebuffer - var FRAMEBUFFER = scope.def( - FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')') - - check$1.optional(function () { - env.assert(scope, - '!' + FRAMEBUFFER_FUNC + '||' + FRAMEBUFFER, - 'invalid framebuffer object') - }) - - scope.set( - FRAMEBUFFER_STATE, - '.next', - FRAMEBUFFER) - var CONTEXT = shared.context - scope.set( - CONTEXT, - '.' + S_FRAMEBUFFER_WIDTH, - FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' + - CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH) - scope.set( - CONTEXT, - '.' + S_FRAMEBUFFER_HEIGHT, - FRAMEBUFFER + - '?' + FRAMEBUFFER + '.height:' + - CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT) - return FRAMEBUFFER - }) - } else { - return null - } - } - - function parseViewportScissor (options, framebuffer, env) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - function parseBox (param) { - if (param in staticOptions) { - var box = staticOptions[param] - check$1.commandType(box, 'object', 'invalid ' + param, env.commandStr) - - var isStatic = true - var x = box.x | 0 - var y = box.y | 0 - var w, h - if ('width' in box) { - w = box.width | 0 - check$1.command(w >= 0, 'invalid ' + param, env.commandStr) - } else { - isStatic = false - } - if ('height' in box) { - h = box.height | 0 - check$1.command(h >= 0, 'invalid ' + param, env.commandStr) - } else { - isStatic = false - } - - return new Declaration( - !isStatic && framebuffer && framebuffer.thisDep, - !isStatic && framebuffer && framebuffer.contextDep, - !isStatic && framebuffer && framebuffer.propDep, - function (env, scope) { - var CONTEXT = env.shared.context - var BOX_W = w - if (!('width' in box)) { - BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x) - } - var BOX_H = h - if (!('height' in box)) { - BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y) - } - return [x, y, BOX_W, BOX_H] - }) - } else if (param in dynamicOptions) { - var dynBox = dynamicOptions[param] - var result = createDynamicDecl(dynBox, function (env, scope) { - var BOX = env.invoke(scope, dynBox) - - check$1.optional(function () { - env.assert(scope, - BOX + '&&typeof ' + BOX + '==="object"', - 'invalid ' + param) - }) - - var CONTEXT = env.shared.context - var BOX_X = scope.def(BOX, '.x|0') - var BOX_Y = scope.def(BOX, '.y|0') - var BOX_W = scope.def( - '"width" in ', BOX, '?', BOX, '.width|0:', - '(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')') - var BOX_H = scope.def( - '"height" in ', BOX, '?', BOX, '.height|0:', - '(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')') - - check$1.optional(function () { - env.assert(scope, - BOX_W + '>=0&&' + - BOX_H + '>=0', - 'invalid ' + param) - }) - - return [BOX_X, BOX_Y, BOX_W, BOX_H] - }) - if (framebuffer) { - result.thisDep = result.thisDep || framebuffer.thisDep - result.contextDep = result.contextDep || framebuffer.contextDep - result.propDep = result.propDep || framebuffer.propDep - } - return result - } else if (framebuffer) { - return new Declaration( - framebuffer.thisDep, - framebuffer.contextDep, - framebuffer.propDep, - function (env, scope) { - var CONTEXT = env.shared.context - return [ - 0, 0, - scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH), - scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)] - }) - } else { - return null - } - } - - var viewport = parseBox(S_VIEWPORT) - - if (viewport) { - var prevViewport = viewport - viewport = new Declaration( - viewport.thisDep, - viewport.contextDep, - viewport.propDep, - function (env, scope) { - var VIEWPORT = prevViewport.append(env, scope) - var CONTEXT = env.shared.context - scope.set( - CONTEXT, - '.' + S_VIEWPORT_WIDTH, - VIEWPORT[2]) - scope.set( - CONTEXT, - '.' + S_VIEWPORT_HEIGHT, - VIEWPORT[3]) - return VIEWPORT - }) - } - - return { - viewport: viewport, - scissor_box: parseBox(S_SCISSOR_BOX) - } - } - - function parseAttribLocations (options, attributes) { - var staticOptions = options.static - var staticProgram = - typeof staticOptions[S_FRAG] === 'string' && - typeof staticOptions[S_VERT] === 'string' - if (staticProgram) { - if (Object.keys(attributes.dynamic).length > 0) { - return null - } - var staticAttributes = attributes.static - var sAttributes = Object.keys(staticAttributes) - if (sAttributes.length > 0 && typeof staticAttributes[sAttributes[0]] === 'number') { - var bindings = [] - for (var i = 0; i < sAttributes.length; ++i) { - check$1(typeof staticAttributes[sAttributes[i]] === 'number', 'must specify all vertex attribute locations when using vaos') - bindings.push([staticAttributes[sAttributes[i]] | 0, sAttributes[i]]) - } - return bindings - } - } - return null - } - - function parseProgram (options, env, attribLocations) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - function parseShader (name) { - if (name in staticOptions) { - var id = stringStore.id(staticOptions[name]) - check$1.optional(function () { - shaderState.shader(shaderType[name], id, check$1.guessCommand()) - }) - var result = createStaticDecl(function () { - return id - }) - result.id = id - return result - } else if (name in dynamicOptions) { - var dyn = dynamicOptions[name] - return createDynamicDecl(dyn, function (env, scope) { - var str = env.invoke(scope, dyn) - var id = scope.def(env.shared.strings, '.id(', str, ')') - check$1.optional(function () { - scope( - env.shared.shader, '.shader(', - shaderType[name], ',', - id, ',', - env.command, ');') - }) - return id - }) - } - return null - } - - var frag = parseShader(S_FRAG) - var vert = parseShader(S_VERT) - - var program = null - var progVar - if (isStatic(frag) && isStatic(vert)) { - program = shaderState.program(vert.id, frag.id, null, attribLocations) - progVar = createStaticDecl(function (env, scope) { - return env.link(program) - }) - } else { - progVar = new Declaration( - (frag && frag.thisDep) || (vert && vert.thisDep), - (frag && frag.contextDep) || (vert && vert.contextDep), - (frag && frag.propDep) || (vert && vert.propDep), - function (env, scope) { - var SHADER_STATE = env.shared.shader - var fragId - if (frag) { - fragId = frag.append(env, scope) - } else { - fragId = scope.def(SHADER_STATE, '.', S_FRAG) - } - var vertId - if (vert) { - vertId = vert.append(env, scope) - } else { - vertId = scope.def(SHADER_STATE, '.', S_VERT) - } - var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId - check$1.optional(function () { - progDef += ',' + env.command - }) - return scope.def(progDef + ')') - }) - } - - return { - frag: frag, - vert: vert, - progVar: progVar, - program: program - } - } - - function parseDraw (options, env) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - // TODO: should use VAO to get default values for offset properties - // should move vao parse into here and out of the old stuff - - var staticDraw = {} - var vaoActive = false - - function parseVAO () { - if (S_VAO in staticOptions) { - var vao = staticOptions[S_VAO] - if (vao !== null && attributeState.getVAO(vao) === null) { - vao = attributeState.createVAO(vao) - } - - vaoActive = true - staticDraw.vao = vao - - return createStaticDecl(function (env) { - var vaoRef = attributeState.getVAO(vao) - if (vaoRef) { - return env.link(vaoRef) - } else { - return 'null' - } - }) - } else if (S_VAO in dynamicOptions) { - vaoActive = true - var dyn = dynamicOptions[S_VAO] - return createDynamicDecl(dyn, function (env, scope) { - var vaoRef = env.invoke(scope, dyn) - return scope.def(env.shared.vao + '.getVAO(' + vaoRef + ')') - }) - } - return null - } - - var vao = parseVAO() - - var elementsActive = false - - function parseElements () { - if (S_ELEMENTS in staticOptions) { - var elements = staticOptions[S_ELEMENTS] - staticDraw.elements = elements - if (isBufferArgs(elements)) { - var e = staticDraw.elements = elementState.create(elements, true) - elements = elementState.getElements(e) - elementsActive = true - } else if (elements) { - elements = elementState.getElements(elements) - elementsActive = true - check$1.command(elements, 'invalid elements', env.commandStr) - } - - var result = createStaticDecl(function (env, scope) { - if (elements) { - var result = env.link(elements) - env.ELEMENTS = result - return result - } - env.ELEMENTS = null - return null - }) - result.value = elements - return result - } else if (S_ELEMENTS in dynamicOptions) { - elementsActive = true - - var dyn = dynamicOptions[S_ELEMENTS] - return createDynamicDecl(dyn, function (env, scope) { - var shared = env.shared - - var IS_BUFFER_ARGS = shared.isBufferArgs - var ELEMENT_STATE = shared.elements - - var elementDefn = env.invoke(scope, dyn) - var elements = scope.def('null') - var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')') - - var ifte = env.cond(elementStream) - .then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');') - .else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');') - - check$1.optional(function () { - env.assert(ifte.else, - '!' + elementDefn + '||' + elements, - 'invalid elements') - }) - - scope.entry(ifte) - scope.exit( - env.cond(elementStream) - .then(ELEMENT_STATE, '.destroyStream(', elements, ');')) - - env.ELEMENTS = elements - - return elements - }) - } else if (vaoActive) { - return new Declaration( - vao.thisDep, - vao.contextDep, - vao.propDep, - function (env, scope) { - return scope.def(env.shared.vao + '.currentVAO?' + env.shared.elements + '.getElements(' + env.shared.vao + '.currentVAO.elements):null') - }) - } - return null - } - - var elements = parseElements() - - function parsePrimitive () { - if (S_PRIMITIVE in staticOptions) { - var primitive = staticOptions[S_PRIMITIVE] - staticDraw.primitive = primitive - check$1.commandParameter(primitive, primTypes, 'invalid primitve', env.commandStr) - return createStaticDecl(function (env, scope) { - return primTypes[primitive] - }) - } else if (S_PRIMITIVE in dynamicOptions) { - var dynPrimitive = dynamicOptions[S_PRIMITIVE] - return createDynamicDecl(dynPrimitive, function (env, scope) { - var PRIM_TYPES = env.constants.primTypes - var prim = env.invoke(scope, dynPrimitive) - check$1.optional(function () { - env.assert(scope, - prim + ' in ' + PRIM_TYPES, - 'invalid primitive, must be one of ' + Object.keys(primTypes)) - }) - return scope.def(PRIM_TYPES, '[', prim, ']') - }) - } else if (elementsActive) { - if (isStatic(elements)) { - if (elements.value) { - return createStaticDecl(function (env, scope) { - return scope.def(env.ELEMENTS, '.primType') - }) - } else { - return createStaticDecl(function () { - return GL_TRIANGLES$1 - }) - } - } else { - return new Declaration( - elements.thisDep, - elements.contextDep, - elements.propDep, - function (env, scope) { - var elements = env.ELEMENTS - return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES$1) - }) - } - } else if (vaoActive) { - return new Declaration( - vao.thisDep, - vao.contextDep, - vao.propDep, - function (env, scope) { - return scope.def(env.shared.vao + '.currentVAO?' + env.shared.vao + '.currentVAO.primitive:' + GL_TRIANGLES$1) - }) - } - return null - } - - function parseParam (param, isOffset) { - if (param in staticOptions) { - var value = staticOptions[param] | 0 - if (isOffset) { - staticDraw.offset = value - } else { - staticDraw.instances = value - } - check$1.command(!isOffset || value >= 0, 'invalid ' + param, env.commandStr) - return createStaticDecl(function (env, scope) { - if (isOffset) { - env.OFFSET = value - } - return value - }) - } else if (param in dynamicOptions) { - var dynValue = dynamicOptions[param] - return createDynamicDecl(dynValue, function (env, scope) { - var result = env.invoke(scope, dynValue) - if (isOffset) { - env.OFFSET = result - check$1.optional(function () { - env.assert(scope, - result + '>=0', - 'invalid ' + param) - }) - } - return result - }) - } else if (isOffset) { - if (elementsActive) { - return createStaticDecl(function (env, scope) { - env.OFFSET = 0 - return 0 - }) - } else if (vaoActive) { - return new Declaration( - vao.thisDep, - vao.contextDep, - vao.propDep, - function (env, scope) { - return scope.def(env.shared.vao + '.currentVAO?' + env.shared.vao + '.currentVAO.offset:0') - }) - } - } else if (vaoActive) { - return new Declaration( - vao.thisDep, - vao.contextDep, - vao.propDep, - function (env, scope) { - return scope.def(env.shared.vao + '.currentVAO?' + env.shared.vao + '.currentVAO.instances:-1') - }) - } - return null - } - - var OFFSET = parseParam(S_OFFSET, true) - - function parseVertCount () { - if (S_COUNT in staticOptions) { - var count = staticOptions[S_COUNT] | 0 - staticDraw.count = count - check$1.command( - typeof count === 'number' && count >= 0, 'invalid vertex count', env.commandStr) - return createStaticDecl(function () { - return count - }) - } else if (S_COUNT in dynamicOptions) { - var dynCount = dynamicOptions[S_COUNT] - return createDynamicDecl(dynCount, function (env, scope) { - var result = env.invoke(scope, dynCount) - check$1.optional(function () { - env.assert(scope, - 'typeof ' + result + '==="number"&&' + - result + '>=0&&' + - result + '===(' + result + '|0)', - 'invalid vertex count') - }) - return result - }) - } else if (elementsActive) { - if (isStatic(elements)) { - if (elements) { - if (OFFSET) { - return new Declaration( - OFFSET.thisDep, - OFFSET.contextDep, - OFFSET.propDep, - function (env, scope) { - var result = scope.def( - env.ELEMENTS, '.vertCount-', env.OFFSET) - - check$1.optional(function () { - env.assert(scope, - result + '>=0', - 'invalid vertex offset/element buffer too small') - }) - - return result - }) - } else { - return createStaticDecl(function (env, scope) { - return scope.def(env.ELEMENTS, '.vertCount') - }) - } - } else { - var result = createStaticDecl(function () { - return -1 - }) - check$1.optional(function () { - result.MISSING = true - }) - return result - } - } else { - var variable = new Declaration( - elements.thisDep || OFFSET.thisDep, - elements.contextDep || OFFSET.contextDep, - elements.propDep || OFFSET.propDep, - function (env, scope) { - var elements = env.ELEMENTS - if (env.OFFSET) { - return scope.def(elements, '?', elements, '.vertCount-', - env.OFFSET, ':-1') - } - return scope.def(elements, '?', elements, '.vertCount:-1') - }) - check$1.optional(function () { - variable.DYNAMIC = true - }) - return variable - } - } else if (vaoActive) { - var countVariable = new Declaration( - vao.thisDep, - vao.contextDep, - vao.propDep, - function (env, scope) { - return scope.def(env.shared.vao, '.currentVAO?', env.shared.vao, '.currentVAO.count:-1') - }) - return countVariable - } - return null - } - - var primitive = parsePrimitive() - var count = parseVertCount() - var instances = parseParam(S_INSTANCES, false) - - return { - elements: elements, - primitive: primitive, - count: count, - instances: instances, - offset: OFFSET, - vao: vao, - - vaoActive: vaoActive, - elementsActive: elementsActive, - - // static draw props - static: staticDraw - } - } - - function parseGLState (options, env) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - var STATE = {} - - GL_STATE_NAMES.forEach(function (prop) { - var param = propName(prop) - - function parseParam (parseStatic, parseDynamic) { - if (prop in staticOptions) { - var value = parseStatic(staticOptions[prop]) - STATE[param] = createStaticDecl(function () { - return value - }) - } else if (prop in dynamicOptions) { - var dyn = dynamicOptions[prop] - STATE[param] = createDynamicDecl(dyn, function (env, scope) { - return parseDynamic(env, scope, env.invoke(scope, dyn)) - }) - } - } - - switch (prop) { - case S_CULL_ENABLE: - case S_BLEND_ENABLE: - case S_DITHER: - case S_STENCIL_ENABLE: - case S_DEPTH_ENABLE: - case S_SCISSOR_ENABLE: - case S_POLYGON_OFFSET_ENABLE: - case S_SAMPLE_ALPHA: - case S_SAMPLE_ENABLE: - case S_DEPTH_MASK: - return parseParam( - function (value) { - check$1.commandType(value, 'boolean', prop, env.commandStr) - return value - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - 'typeof ' + value + '==="boolean"', - 'invalid flag ' + prop, env.commandStr) - }) - return value - }) - - case S_DEPTH_FUNC: - return parseParam( - function (value) { - check$1.commandParameter(value, compareFuncs, 'invalid ' + prop, env.commandStr) - return compareFuncs[value] - }, - function (env, scope, value) { - var COMPARE_FUNCS = env.constants.compareFuncs - check$1.optional(function () { - env.assert(scope, - value + ' in ' + COMPARE_FUNCS, - 'invalid ' + prop + ', must be one of ' + Object.keys(compareFuncs)) - }) - return scope.def(COMPARE_FUNCS, '[', value, ']') - }) - - case S_DEPTH_RANGE: - return parseParam( - function (value) { - check$1.command( - isArrayLike(value) && - value.length === 2 && - typeof value[0] === 'number' && - typeof value[1] === 'number' && - value[0] <= value[1], - 'depth range is 2d array', - env.commandStr) - return value - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - env.shared.isArrayLike + '(' + value + ')&&' + - value + '.length===2&&' + - 'typeof ' + value + '[0]==="number"&&' + - 'typeof ' + value + '[1]==="number"&&' + - value + '[0]<=' + value + '[1]', - 'depth range must be a 2d array') - }) - - var Z_NEAR = scope.def('+', value, '[0]') - var Z_FAR = scope.def('+', value, '[1]') - return [Z_NEAR, Z_FAR] - }) - - case S_BLEND_FUNC: - return parseParam( - function (value) { - check$1.commandType(value, 'object', 'blend.func', env.commandStr) - var srcRGB = ('srcRGB' in value ? value.srcRGB : value.src) - var srcAlpha = ('srcAlpha' in value ? value.srcAlpha : value.src) - var dstRGB = ('dstRGB' in value ? value.dstRGB : value.dst) - var dstAlpha = ('dstAlpha' in value ? value.dstAlpha : value.dst) - check$1.commandParameter(srcRGB, blendFuncs, param + '.srcRGB', env.commandStr) - check$1.commandParameter(srcAlpha, blendFuncs, param + '.srcAlpha', env.commandStr) - check$1.commandParameter(dstRGB, blendFuncs, param + '.dstRGB', env.commandStr) - check$1.commandParameter(dstAlpha, blendFuncs, param + '.dstAlpha', env.commandStr) - - check$1.command( - (invalidBlendCombinations.indexOf(srcRGB + ', ' + dstRGB) === -1), - 'unallowed blending combination (srcRGB, dstRGB) = (' + srcRGB + ', ' + dstRGB + ')', env.commandStr) - - return [ - blendFuncs[srcRGB], - blendFuncs[dstRGB], - blendFuncs[srcAlpha], - blendFuncs[dstAlpha] - ] - }, - function (env, scope, value) { - var BLEND_FUNCS = env.constants.blendFuncs - - check$1.optional(function () { - env.assert(scope, - value + '&&typeof ' + value + '==="object"', - 'invalid blend func, must be an object') - }) - - function read (prefix, suffix) { - var func = scope.def( - '"', prefix, suffix, '" in ', value, - '?', value, '.', prefix, suffix, - ':', value, '.', prefix) - - check$1.optional(function () { - env.assert(scope, - func + ' in ' + BLEND_FUNCS, - 'invalid ' + prop + '.' + prefix + suffix + ', must be one of ' + Object.keys(blendFuncs)) - }) - - return func - } - - var srcRGB = read('src', 'RGB') - var dstRGB = read('dst', 'RGB') - - check$1.optional(function () { - var INVALID_BLEND_COMBINATIONS = env.constants.invalidBlendCombinations - - env.assert(scope, - INVALID_BLEND_COMBINATIONS + - '.indexOf(' + srcRGB + '+", "+' + dstRGB + ') === -1 ', - 'unallowed blending combination for (srcRGB, dstRGB)' - ) - }) - - var SRC_RGB = scope.def(BLEND_FUNCS, '[', srcRGB, ']') - var SRC_ALPHA = scope.def(BLEND_FUNCS, '[', read('src', 'Alpha'), ']') - var DST_RGB = scope.def(BLEND_FUNCS, '[', dstRGB, ']') - var DST_ALPHA = scope.def(BLEND_FUNCS, '[', read('dst', 'Alpha'), ']') - - return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA] - }) - - case S_BLEND_EQUATION: - return parseParam( - function (value) { - if (typeof value === 'string') { - check$1.commandParameter(value, blendEquations, 'invalid ' + prop, env.commandStr) - return [ - blendEquations[value], - blendEquations[value] - ] - } else if (typeof value === 'object') { - check$1.commandParameter( - value.rgb, blendEquations, prop + '.rgb', env.commandStr) - check$1.commandParameter( - value.alpha, blendEquations, prop + '.alpha', env.commandStr) - return [ - blendEquations[value.rgb], - blendEquations[value.alpha] - ] - } else { - check$1.commandRaise('invalid blend.equation', env.commandStr) - } - }, - function (env, scope, value) { - var BLEND_EQUATIONS = env.constants.blendEquations - - var RGB = scope.def() - var ALPHA = scope.def() - - var ifte = env.cond('typeof ', value, '==="string"') - - check$1.optional(function () { - function checkProp (block, name, value) { - env.assert(block, - value + ' in ' + BLEND_EQUATIONS, - 'invalid ' + name + ', must be one of ' + Object.keys(blendEquations)) - } - checkProp(ifte.then, prop, value) - - env.assert(ifte.else, - value + '&&typeof ' + value + '==="object"', - 'invalid ' + prop) - checkProp(ifte.else, prop + '.rgb', value + '.rgb') - checkProp(ifte.else, prop + '.alpha', value + '.alpha') - }) - - ifte.then( - RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];') - ifte.else( - RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];', - ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];') - - scope(ifte) - - return [RGB, ALPHA] - }) - - case S_BLEND_COLOR: - return parseParam( - function (value) { - check$1.command( - isArrayLike(value) && - value.length === 4, - 'blend.color must be a 4d array', env.commandStr) - return loop(4, function (i) { - return +value[i] - }) - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - env.shared.isArrayLike + '(' + value + ')&&' + - value + '.length===4', - 'blend.color must be a 4d array') - }) - return loop(4, function (i) { - return scope.def('+', value, '[', i, ']') - }) - }) - - case S_STENCIL_MASK: - return parseParam( - function (value) { - check$1.commandType(value, 'number', param, env.commandStr) - return value | 0 - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - 'typeof ' + value + '==="number"', - 'invalid stencil.mask') - }) - return scope.def(value, '|0') - }) - - case S_STENCIL_FUNC: - return parseParam( - function (value) { - check$1.commandType(value, 'object', param, env.commandStr) - var cmp = value.cmp || 'keep' - var ref = value.ref || 0 - var mask = 'mask' in value ? value.mask : -1 - check$1.commandParameter(cmp, compareFuncs, prop + '.cmp', env.commandStr) - check$1.commandType(ref, 'number', prop + '.ref', env.commandStr) - check$1.commandType(mask, 'number', prop + '.mask', env.commandStr) - return [ - compareFuncs[cmp], - ref, - mask - ] - }, - function (env, scope, value) { - var COMPARE_FUNCS = env.constants.compareFuncs - check$1.optional(function () { - function assert () { - env.assert(scope, - Array.prototype.join.call(arguments, ''), - 'invalid stencil.func') - } - assert(value + '&&typeof ', value, '==="object"') - assert('!("cmp" in ', value, ')||(', - value, '.cmp in ', COMPARE_FUNCS, ')') - }) - var cmp = scope.def( - '"cmp" in ', value, - '?', COMPARE_FUNCS, '[', value, '.cmp]', - ':', GL_KEEP) - var ref = scope.def(value, '.ref|0') - var mask = scope.def( - '"mask" in ', value, - '?', value, '.mask|0:-1') - return [cmp, ref, mask] - }) - - case S_STENCIL_OPFRONT: - case S_STENCIL_OPBACK: - return parseParam( - function (value) { - check$1.commandType(value, 'object', param, env.commandStr) - var fail = value.fail || 'keep' - var zfail = value.zfail || 'keep' - var zpass = value.zpass || 'keep' - check$1.commandParameter(fail, stencilOps, prop + '.fail', env.commandStr) - check$1.commandParameter(zfail, stencilOps, prop + '.zfail', env.commandStr) - check$1.commandParameter(zpass, stencilOps, prop + '.zpass', env.commandStr) - return [ - prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, - stencilOps[fail], - stencilOps[zfail], - stencilOps[zpass] - ] - }, - function (env, scope, value) { - var STENCIL_OPS = env.constants.stencilOps - - check$1.optional(function () { - env.assert(scope, - value + '&&typeof ' + value + '==="object"', - 'invalid ' + prop) - }) - - function read (name) { - check$1.optional(function () { - env.assert(scope, - '!("' + name + '" in ' + value + ')||' + - '(' + value + '.' + name + ' in ' + STENCIL_OPS + ')', - 'invalid ' + prop + '.' + name + ', must be one of ' + Object.keys(stencilOps)) - }) - - return scope.def( - '"', name, '" in ', value, - '?', STENCIL_OPS, '[', value, '.', name, ']:', - GL_KEEP) - } - - return [ - prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT, - read('fail'), - read('zfail'), - read('zpass') - ] - }) - - case S_POLYGON_OFFSET_OFFSET: - return parseParam( - function (value) { - check$1.commandType(value, 'object', param, env.commandStr) - var factor = value.factor | 0 - var units = value.units | 0 - check$1.commandType(factor, 'number', param + '.factor', env.commandStr) - check$1.commandType(units, 'number', param + '.units', env.commandStr) - return [factor, units] - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - value + '&&typeof ' + value + '==="object"', - 'invalid ' + prop) - }) - - var FACTOR = scope.def(value, '.factor|0') - var UNITS = scope.def(value, '.units|0') - - return [FACTOR, UNITS] - }) - - case S_CULL_FACE: - return parseParam( - function (value) { - var face = 0 - if (value === 'front') { - face = GL_FRONT - } else if (value === 'back') { - face = GL_BACK - } - check$1.command(!!face, param, env.commandStr) - return face - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - value + '==="front"||' + - value + '==="back"', - 'invalid cull.face') - }) - return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK) - }) - - case S_LINE_WIDTH: - return parseParam( - function (value) { - check$1.command( - typeof value === 'number' && - value >= limits.lineWidthDims[0] && - value <= limits.lineWidthDims[1], - 'invalid line width, must be a positive number between ' + - limits.lineWidthDims[0] + ' and ' + limits.lineWidthDims[1], env.commandStr) - return value - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - 'typeof ' + value + '==="number"&&' + - value + '>=' + limits.lineWidthDims[0] + '&&' + - value + '<=' + limits.lineWidthDims[1], - 'invalid line width') - }) - - return value - }) - - case S_FRONT_FACE: - return parseParam( - function (value) { - check$1.commandParameter(value, orientationType, param, env.commandStr) - return orientationType[value] - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - value + '==="cw"||' + - value + '==="ccw"', - 'invalid frontFace, must be one of cw,ccw') - }) - return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW) - }) - - case S_COLOR_MASK: - return parseParam( - function (value) { - check$1.command( - isArrayLike(value) && value.length === 4, - 'color.mask must be length 4 array', env.commandStr) - return value.map(function (v) { return !!v }) - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - env.shared.isArrayLike + '(' + value + ')&&' + - value + '.length===4', - 'invalid color.mask') - }) - return loop(4, function (i) { - return '!!' + value + '[' + i + ']' - }) - }) - - case S_SAMPLE_COVERAGE: - return parseParam( - function (value) { - check$1.command(typeof value === 'object' && value, param, env.commandStr) - var sampleValue = 'value' in value ? value.value : 1 - var sampleInvert = !!value.invert - check$1.command( - typeof sampleValue === 'number' && - sampleValue >= 0 && sampleValue <= 1, - 'sample.coverage.value must be a number between 0 and 1', env.commandStr) - return [sampleValue, sampleInvert] - }, - function (env, scope, value) { - check$1.optional(function () { - env.assert(scope, - value + '&&typeof ' + value + '==="object"', - 'invalid sample.coverage') - }) - var VALUE = scope.def( - '"value" in ', value, '?+', value, '.value:1') - var INVERT = scope.def('!!', value, '.invert') - return [VALUE, INVERT] - }) - } - }) - - return STATE - } - - function parseUniforms (uniforms, env) { - var staticUniforms = uniforms.static - var dynamicUniforms = uniforms.dynamic - - var UNIFORMS = {} - - Object.keys(staticUniforms).forEach(function (name) { - var value = staticUniforms[name] - var result - if (typeof value === 'number' || - typeof value === 'boolean') { - result = createStaticDecl(function () { - return value - }) - } else if (typeof value === 'function') { - var reglType = value._reglType - if (reglType === 'texture2d' || - reglType === 'textureCube') { - result = createStaticDecl(function (env) { - return env.link(value) - }) - } else if (reglType === 'framebuffer' || - reglType === 'framebufferCube') { - check$1.command(value.color.length > 0, - 'missing color attachment for framebuffer sent to uniform "' + name + '"', env.commandStr) - result = createStaticDecl(function (env) { - return env.link(value.color[0]) - }) - } else { - check$1.commandRaise('invalid data for uniform "' + name + '"', env.commandStr) - } - } else if (isArrayLike(value)) { - result = createStaticDecl(function (env) { - var ITEM = env.global.def('[', - loop(value.length, function (i) { - check$1.command( - typeof value[i] === 'number' || - typeof value[i] === 'boolean', - 'invalid uniform ' + name, env.commandStr) - return value[i] - }), ']') - return ITEM - }) - } else { - check$1.commandRaise('invalid or missing data for uniform "' + name + '"', env.commandStr) - } - result.value = value - UNIFORMS[name] = result - }) - - Object.keys(dynamicUniforms).forEach(function (key) { - var dyn = dynamicUniforms[key] - UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) { - return env.invoke(scope, dyn) - }) - }) - - return UNIFORMS - } - - function parseAttributes (attributes, env) { - var staticAttributes = attributes.static - var dynamicAttributes = attributes.dynamic - - var attributeDefs = {} - - Object.keys(staticAttributes).forEach(function (attribute) { - var value = staticAttributes[attribute] - var id = stringStore.id(attribute) - - var record = new AttributeRecord() - if (isBufferArgs(value)) { - record.state = ATTRIB_STATE_POINTER - record.buffer = bufferState.getBuffer( - bufferState.create(value, GL_ARRAY_BUFFER$2, false, true)) - record.type = 0 - } else { - var buffer = bufferState.getBuffer(value) - if (buffer) { - record.state = ATTRIB_STATE_POINTER - record.buffer = buffer - record.type = 0 - } else { - check$1.command(typeof value === 'object' && value, - 'invalid data for attribute ' + attribute, env.commandStr) - if ('constant' in value) { - var constant = value.constant - record.buffer = 'null' - record.state = ATTRIB_STATE_CONSTANT - if (typeof constant === 'number') { - record.x = constant - } else { - check$1.command( - isArrayLike(constant) && - constant.length > 0 && - constant.length <= 4, - 'invalid constant for attribute ' + attribute, env.commandStr) - CUTE_COMPONENTS.forEach(function (c, i) { - if (i < constant.length) { - record[c] = constant[i] - } - }) - } - } else { - if (isBufferArgs(value.buffer)) { - buffer = bufferState.getBuffer( - bufferState.create(value.buffer, GL_ARRAY_BUFFER$2, false, true)) - } else { - buffer = bufferState.getBuffer(value.buffer) - } - check$1.command(!!buffer, 'missing buffer for attribute "' + attribute + '"', env.commandStr) - - var offset = value.offset | 0 - check$1.command(offset >= 0, - 'invalid offset for attribute "' + attribute + '"', env.commandStr) - - var stride = value.stride | 0 - check$1.command(stride >= 0 && stride < 256, - 'invalid stride for attribute "' + attribute + '", must be integer betweeen [0, 255]', env.commandStr) - - var size = value.size | 0 - check$1.command(!('size' in value) || (size > 0 && size <= 4), - 'invalid size for attribute "' + attribute + '", must be 1,2,3,4', env.commandStr) - - var normalized = !!value.normalized - - var type = 0 - if ('type' in value) { - check$1.commandParameter( - value.type, glTypes, - 'invalid type for attribute ' + attribute, env.commandStr) - type = glTypes[value.type] - } - - var divisor = value.divisor | 0 - check$1.optional(function () { - if ('divisor' in value) { - check$1.command(divisor === 0 || extInstancing, - 'cannot specify divisor for attribute "' + attribute + '", instancing not supported', env.commandStr) - check$1.command(divisor >= 0, - 'invalid divisor for attribute "' + attribute + '"', env.commandStr) - } - - var command = env.commandStr - - var VALID_KEYS = [ - 'buffer', - 'offset', - 'divisor', - 'normalized', - 'type', - 'size', - 'stride' - ] - - Object.keys(value).forEach(function (prop) { - check$1.command( - VALID_KEYS.indexOf(prop) >= 0, - 'unknown parameter "' + prop + '" for attribute pointer "' + attribute + '" (valid parameters are ' + VALID_KEYS + ')', - command) - }) - }) - - record.buffer = buffer - record.state = ATTRIB_STATE_POINTER - record.size = size - record.normalized = normalized - record.type = type || buffer.dtype - record.offset = offset - record.stride = stride - record.divisor = divisor - } - } - } - - attributeDefs[attribute] = createStaticDecl(function (env, scope) { - var cache = env.attribCache - if (id in cache) { - return cache[id] - } - var result = { - isStream: false - } - Object.keys(record).forEach(function (key) { - result[key] = record[key] - }) - if (record.buffer) { - result.buffer = env.link(record.buffer) - result.type = result.type || (result.buffer + '.dtype') - } - cache[id] = result - return result - }) - }) - - Object.keys(dynamicAttributes).forEach(function (attribute) { - var dyn = dynamicAttributes[attribute] - - function appendAttributeCode (env, block) { - var VALUE = env.invoke(block, dyn) - - var shared = env.shared - var constants = env.constants - - var IS_BUFFER_ARGS = shared.isBufferArgs - var BUFFER_STATE = shared.buffer - - // Perform validation on attribute - check$1.optional(function () { - env.assert(block, - VALUE + '&&(typeof ' + VALUE + '==="object"||typeof ' + - VALUE + '==="function")&&(' + - IS_BUFFER_ARGS + '(' + VALUE + ')||' + - BUFFER_STATE + '.getBuffer(' + VALUE + ')||' + - BUFFER_STATE + '.getBuffer(' + VALUE + '.buffer)||' + - IS_BUFFER_ARGS + '(' + VALUE + '.buffer)||' + - '("constant" in ' + VALUE + - '&&(typeof ' + VALUE + '.constant==="number"||' + - shared.isArrayLike + '(' + VALUE + '.constant))))', - 'invalid dynamic attribute "' + attribute + '"') - }) - - // allocate names for result - var result = { - isStream: block.def(false) - } - var defaultRecord = new AttributeRecord() - defaultRecord.state = ATTRIB_STATE_POINTER - Object.keys(defaultRecord).forEach(function (key) { - result[key] = block.def('' + defaultRecord[key]) - }) - - var BUFFER = result.buffer - var TYPE = result.type - block( - 'if(', IS_BUFFER_ARGS, '(', VALUE, ')){', - result.isStream, '=true;', - BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$2, ',', VALUE, ');', - TYPE, '=', BUFFER, '.dtype;', - '}else{', - BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');', - 'if(', BUFFER, '){', - TYPE, '=', BUFFER, '.dtype;', - '}else if("constant" in ', VALUE, '){', - result.state, '=', ATTRIB_STATE_CONSTANT, ';', - 'if(typeof ' + VALUE + '.constant === "number"){', - result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;', - CUTE_COMPONENTS.slice(1).map(function (n) { - return result[n] - }).join('='), '=0;', - '}else{', - CUTE_COMPONENTS.map(function (name, i) { - return ( - result[name] + '=' + VALUE + '.constant.length>' + i + - '?' + VALUE + '.constant[' + i + ']:0;' - ) - }).join(''), - '}}else{', - 'if(', IS_BUFFER_ARGS, '(', VALUE, '.buffer)){', - BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$2, ',', VALUE, '.buffer);', - '}else{', - BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);', - '}', - TYPE, '="type" in ', VALUE, '?', - constants.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;', - result.normalized, '=!!', VALUE, '.normalized;') - function emitReadRecord (name) { - block(result[name], '=', VALUE, '.', name, '|0;') - } - emitReadRecord('size') - emitReadRecord('offset') - emitReadRecord('stride') - emitReadRecord('divisor') - - block('}}') - - block.exit( - 'if(', result.isStream, '){', - BUFFER_STATE, '.destroyStream(', BUFFER, ');', - '}') - - return result - } - - attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode) - }) - - return attributeDefs - } - - function parseContext (context) { - var staticContext = context.static - var dynamicContext = context.dynamic - var result = {} - - Object.keys(staticContext).forEach(function (name) { - var value = staticContext[name] - result[name] = createStaticDecl(function (env, scope) { - if (typeof value === 'number' || typeof value === 'boolean') { - return '' + value - } else { - return env.link(value) - } - }) - }) - - Object.keys(dynamicContext).forEach(function (name) { - var dyn = dynamicContext[name] - result[name] = createDynamicDecl(dyn, function (env, scope) { - return env.invoke(scope, dyn) - }) - }) - - return result - } - - function parseArguments (options, attributes, uniforms, context, env) { - var staticOptions = options.static - var dynamicOptions = options.dynamic - - check$1.optional(function () { - var KEY_NAMES = [ - S_FRAMEBUFFER, - S_VERT, - S_FRAG, - S_ELEMENTS, - S_PRIMITIVE, - S_OFFSET, - S_COUNT, - S_INSTANCES, - S_PROFILE, - S_VAO - ].concat(GL_STATE_NAMES) - - function checkKeys (dict) { - Object.keys(dict).forEach(function (key) { - check$1.command( - KEY_NAMES.indexOf(key) >= 0, - 'unknown parameter "' + key + '"', - env.commandStr) - }) - } - - checkKeys(staticOptions) - checkKeys(dynamicOptions) - }) - - var attribLocations = parseAttribLocations(options, attributes) - - var framebuffer = parseFramebuffer(options, env) - var viewportAndScissor = parseViewportScissor(options, framebuffer, env) - var draw = parseDraw(options, env) - var state = parseGLState(options, env) - var shader = parseProgram(options, env, attribLocations) - - function copyBox (name) { - var defn = viewportAndScissor[name] - if (defn) { - state[name] = defn - } - } - copyBox(S_VIEWPORT) - copyBox(propName(S_SCISSOR_BOX)) - - var dirty = Object.keys(state).length > 0 - - var result = { - framebuffer: framebuffer, - draw: draw, - shader: shader, - state: state, - dirty: dirty, - scopeVAO: null, - drawVAO: null, - useVAO: false, - attributes: {} - } - - result.profile = parseProfile(options, env) - result.uniforms = parseUniforms(uniforms, env) - result.drawVAO = result.scopeVAO = draw.vao - // special case: check if we can statically allocate a vertex array object for this program - if (!result.drawVAO && - shader.program && - !attribLocations && - extensions.angle_instanced_arrays && - draw.static.elements) { - var useVAO = true - var staticBindings = shader.program.attributes.map(function (attr) { - var binding = attributes.static[attr] - useVAO = useVAO && !!binding - return binding - }) - if (useVAO && staticBindings.length > 0) { - var vao = attributeState.getVAO(attributeState.createVAO({ - attributes: staticBindings, - elements: draw.static.elements - })) - result.drawVAO = new Declaration(null, null, null, function (env, scope) { - return env.link(vao) - }) - result.useVAO = true - } - } - if (attribLocations) { - result.useVAO = true - } else { - result.attributes = parseAttributes(attributes, env) - } - result.context = parseContext(context, env) - return result - } - - // =================================================== - // =================================================== - // COMMON UPDATE FUNCTIONS - // =================================================== - // =================================================== - function emitContext (env, scope, context) { - var shared = env.shared - var CONTEXT = shared.context - - var contextEnter = env.scope() - - Object.keys(context).forEach(function (name) { - scope.save(CONTEXT, '.' + name) - var defn = context[name] - var value = defn.append(env, scope) - if (Array.isArray(value)) { - contextEnter(CONTEXT, '.', name, '=[', value.join(), '];') - } else { - contextEnter(CONTEXT, '.', name, '=', value, ';') - } - }) - - scope(contextEnter) - } - - // =================================================== - // =================================================== - // COMMON DRAWING FUNCTIONS - // =================================================== - // =================================================== - function emitPollFramebuffer (env, scope, framebuffer, skipCheck) { - var shared = env.shared - - var GL = shared.gl - var FRAMEBUFFER_STATE = shared.framebuffer - var EXT_DRAW_BUFFERS - if (extDrawBuffers) { - EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers') - } - - var constants = env.constants - - var DRAW_BUFFERS = constants.drawBuffer - var BACK_BUFFER = constants.backBuffer - - var NEXT - if (framebuffer) { - NEXT = framebuffer.append(env, scope) - } else { - NEXT = scope.def(FRAMEBUFFER_STATE, '.next') - } - - if (!skipCheck) { - scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){') - } - scope( - 'if(', NEXT, '){', - GL, '.bindFramebuffer(', GL_FRAMEBUFFER$2, ',', NEXT, '.framebuffer);') - if (extDrawBuffers) { - scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', - DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);') - } - scope('}else{', - GL, '.bindFramebuffer(', GL_FRAMEBUFFER$2, ',null);') - if (extDrawBuffers) { - scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');') - } - scope( - '}', - FRAMEBUFFER_STATE, '.cur=', NEXT, ';') - if (!skipCheck) { - scope('}') - } - } - - function emitPollState (env, scope, args) { - var shared = env.shared - - var GL = shared.gl - - var CURRENT_VARS = env.current - var NEXT_VARS = env.next - var CURRENT_STATE = shared.current - var NEXT_STATE = shared.next - - var block = env.cond(CURRENT_STATE, '.dirty') - - GL_STATE_NAMES.forEach(function (prop) { - var param = propName(prop) - if (param in args.state) { - return - } - - var NEXT, CURRENT - if (param in NEXT_VARS) { - NEXT = NEXT_VARS[param] - CURRENT = CURRENT_VARS[param] - var parts = loop(currentState[param].length, function (i) { - return block.def(NEXT, '[', i, ']') - }) - block(env.cond(parts.map(function (p, i) { - return p + '!==' + CURRENT + '[' + i + ']' - }).join('||')) - .then( - GL, '.', GL_VARIABLES[param], '(', parts, ');', - parts.map(function (p, i) { - return CURRENT + '[' + i + ']=' + p - }).join(';'), ';')) - } else { - NEXT = block.def(NEXT_STATE, '.', param) - var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param) - block(ifte) - if (param in GL_FLAGS) { - ifte( - env.cond(NEXT) - .then(GL, '.enable(', GL_FLAGS[param], ');') - .else(GL, '.disable(', GL_FLAGS[param], ');'), - CURRENT_STATE, '.', param, '=', NEXT, ';') - } else { - ifte( - GL, '.', GL_VARIABLES[param], '(', NEXT, ');', - CURRENT_STATE, '.', param, '=', NEXT, ';') - } - } - }) - if (Object.keys(args.state).length === 0) { - block(CURRENT_STATE, '.dirty=false;') - } - scope(block) - } - - function emitSetOptions (env, scope, options, filter) { - var shared = env.shared - var CURRENT_VARS = env.current - var CURRENT_STATE = shared.current - var GL = shared.gl - sortState(Object.keys(options)).forEach(function (param) { - var defn = options[param] - if (filter && !filter(defn)) { - return - } - var variable = defn.append(env, scope) - if (GL_FLAGS[param]) { - var flag = GL_FLAGS[param] - if (isStatic(defn)) { - if (variable) { - scope(GL, '.enable(', flag, ');') - } else { - scope(GL, '.disable(', flag, ');') - } - } else { - scope(env.cond(variable) - .then(GL, '.enable(', flag, ');') - .else(GL, '.disable(', flag, ');')) - } - scope(CURRENT_STATE, '.', param, '=', variable, ';') - } else if (isArrayLike(variable)) { - var CURRENT = CURRENT_VARS[param] - scope( - GL, '.', GL_VARIABLES[param], '(', variable, ');', - variable.map(function (v, i) { - return CURRENT + '[' + i + ']=' + v - }).join(';'), ';') - } else { - scope( - GL, '.', GL_VARIABLES[param], '(', variable, ');', - CURRENT_STATE, '.', param, '=', variable, ';') - } - }) - } - - function injectExtensions (env, scope) { - if (extInstancing) { - env.instancing = scope.def( - env.shared.extensions, '.angle_instanced_arrays') - } - } - - function emitProfile (env, scope, args, useScope, incrementCounter) { - var shared = env.shared - var STATS = env.stats - var CURRENT_STATE = shared.current - var TIMER = shared.timer - var profileArg = args.profile - - function perfCounter () { - if (typeof performance === 'undefined') { - return 'Date.now()' - } else { - return 'performance.now()' - } - } - - var CPU_START, QUERY_COUNTER - function emitProfileStart (block) { - CPU_START = scope.def() - block(CPU_START, '=', perfCounter(), ';') - if (typeof incrementCounter === 'string') { - block(STATS, '.count+=', incrementCounter, ';') - } else { - block(STATS, '.count++;') - } - if (timer) { - if (useScope) { - QUERY_COUNTER = scope.def() - block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();') - } else { - block(TIMER, '.beginQuery(', STATS, ');') - } - } - } - - function emitProfileEnd (block) { - block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';') - if (timer) { - if (useScope) { - block(TIMER, '.pushScopeStats(', - QUERY_COUNTER, ',', - TIMER, '.getNumPendingQueries(),', - STATS, ');') - } else { - block(TIMER, '.endQuery();') - } - } - } - - function scopeProfile (value) { - var prev = scope.def(CURRENT_STATE, '.profile') - scope(CURRENT_STATE, '.profile=', value, ';') - scope.exit(CURRENT_STATE, '.profile=', prev, ';') - } - - var USE_PROFILE - if (profileArg) { - if (isStatic(profileArg)) { - if (profileArg.enable) { - emitProfileStart(scope) - emitProfileEnd(scope.exit) - scopeProfile('true') - } else { - scopeProfile('false') - } - return - } - USE_PROFILE = profileArg.append(env, scope) - scopeProfile(USE_PROFILE) - } else { - USE_PROFILE = scope.def(CURRENT_STATE, '.profile') - } - - var start = env.block() - emitProfileStart(start) - scope('if(', USE_PROFILE, '){', start, '}') - var end = env.block() - emitProfileEnd(end) - scope.exit('if(', USE_PROFILE, '){', end, '}') - } - - function emitAttributes (env, scope, args, attributes, filter) { - var shared = env.shared - - function typeLength (x) { - switch (x) { - case GL_FLOAT_VEC2: - case GL_INT_VEC2: - case GL_BOOL_VEC2: - return 2 - case GL_FLOAT_VEC3: - case GL_INT_VEC3: - case GL_BOOL_VEC3: - return 3 - case GL_FLOAT_VEC4: - case GL_INT_VEC4: - case GL_BOOL_VEC4: - return 4 - default: - return 1 - } - } - - function emitBindAttribute (ATTRIBUTE, size, record) { - var GL = shared.gl - - var LOCATION = scope.def(ATTRIBUTE, '.location') - var BINDING = scope.def(shared.attributes, '[', LOCATION, ']') - - var STATE = record.state - var BUFFER = record.buffer - var CONST_COMPONENTS = [ - record.x, - record.y, - record.z, - record.w - ] - - var COMMON_KEYS = [ - 'buffer', - 'normalized', - 'offset', - 'stride' - ] - - function emitBuffer () { - scope( - 'if(!', BINDING, '.buffer){', - GL, '.enableVertexAttribArray(', LOCATION, ');}') - - var TYPE = record.type - var SIZE - if (!record.size) { - SIZE = size - } else { - SIZE = scope.def(record.size, '||', size) - } - - scope('if(', - BINDING, '.type!==', TYPE, '||', - BINDING, '.size!==', SIZE, '||', - COMMON_KEYS.map(function (key) { - return BINDING + '.' + key + '!==' + record[key] - }).join('||'), - '){', - GL, '.bindBuffer(', GL_ARRAY_BUFFER$2, ',', BUFFER, '.buffer);', - GL, '.vertexAttribPointer(', [ - LOCATION, - SIZE, - TYPE, - record.normalized, - record.stride, - record.offset - ], ');', - BINDING, '.type=', TYPE, ';', - BINDING, '.size=', SIZE, ';', - COMMON_KEYS.map(function (key) { - return BINDING + '.' + key + '=' + record[key] + ';' - }).join(''), - '}') - - if (extInstancing) { - var DIVISOR = record.divisor - scope( - 'if(', BINDING, '.divisor!==', DIVISOR, '){', - env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');', - BINDING, '.divisor=', DIVISOR, ';}') - } - } - - function emitConstant () { - scope( - 'if(', BINDING, '.buffer){', - GL, '.disableVertexAttribArray(', LOCATION, ');', - BINDING, '.buffer=null;', - '}if(', CUTE_COMPONENTS.map(function (c, i) { - return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i] - }).join('||'), '){', - GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');', - CUTE_COMPONENTS.map(function (c, i) { - return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';' - }).join(''), - '}') - } - - if (STATE === ATTRIB_STATE_POINTER) { - emitBuffer() - } else if (STATE === ATTRIB_STATE_CONSTANT) { - emitConstant() - } else { - scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){') - emitBuffer() - scope('}else{') - emitConstant() - scope('}') - } - } - - attributes.forEach(function (attribute) { - var name = attribute.name - var arg = args.attributes[name] - var record - if (arg) { - if (!filter(arg)) { - return - } - record = arg.append(env, scope) - } else { - if (!filter(SCOPE_DECL)) { - return - } - var scopeAttrib = env.scopeAttrib(name) - check$1.optional(function () { - env.assert(scope, - scopeAttrib + '.state', - 'missing attribute ' + name) - }) - record = {} - Object.keys(new AttributeRecord()).forEach(function (key) { - record[key] = scope.def(scopeAttrib, '.', key) - }) - } - emitBindAttribute( - env.link(attribute), typeLength(attribute.info.type), record) - }) - } - - function emitUniforms (env, scope, args, uniforms, filter, isBatchInnerLoop) { - var shared = env.shared - var GL = shared.gl - - var definedArrUniforms = {} - var infix - for (var i = 0; i < uniforms.length; ++i) { - var uniform = uniforms[i] - var name = uniform.name - var type = uniform.info.type - var size = uniform.info.size - var arg = args.uniforms[name] - if (size > 1) { - // either foo[n] or foos, avoid define both - if (!arg) { - continue - } - var arrUniformName = name.replace('[0]', '') - if (definedArrUniforms[arrUniformName]) { - continue - } - definedArrUniforms[arrUniformName] = 1 - } - var UNIFORM = env.link(uniform) - var LOCATION = UNIFORM + '.location' - - var VALUE - if (arg) { - if (!filter(arg)) { - continue - } - if (isStatic(arg)) { - var value = arg.value - check$1.command( - value !== null && typeof value !== 'undefined', - 'missing uniform "' + name + '"', env.commandStr) - if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) { - check$1.command( - typeof value === 'function' && - ((type === GL_SAMPLER_2D && - (value._reglType === 'texture2d' || - value._reglType === 'framebuffer')) || - (type === GL_SAMPLER_CUBE && - (value._reglType === 'textureCube' || - value._reglType === 'framebufferCube'))), - 'invalid texture for uniform ' + name, env.commandStr) - var TEX_VALUE = env.link(value._texture || value.color[0]._texture) - scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());') - scope.exit(TEX_VALUE, '.unbind();') - } else if ( - type === GL_FLOAT_MAT2 || - type === GL_FLOAT_MAT3 || - type === GL_FLOAT_MAT4) { - check$1.optional(function () { - check$1.command(isArrayLike(value), - 'invalid matrix for uniform ' + name, env.commandStr) - check$1.command( - (type === GL_FLOAT_MAT2 && value.length === 4) || - (type === GL_FLOAT_MAT3 && value.length === 9) || - (type === GL_FLOAT_MAT4 && value.length === 16), - 'invalid length for matrix uniform ' + name, env.commandStr) - }) - var MAT_VALUE = env.global.def('new Float32Array([' + - Array.prototype.slice.call(value) + '])') - var dim = 2 - if (type === GL_FLOAT_MAT3) { - dim = 3 - } else if (type === GL_FLOAT_MAT4) { - dim = 4 - } - scope( - GL, '.uniformMatrix', dim, 'fv(', - LOCATION, ',false,', MAT_VALUE, ');') - } else { - switch (type) { - case GL_FLOAT$8: - if (size === 1) { - check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr) - } else { - check$1.command( - isArrayLike(value) && (value.length === size), - 'uniform ' + name, env.commandStr) - } - infix = '1f' - break - case GL_FLOAT_VEC2: - check$1.command( - isArrayLike(value) && (value.length && value.length % 2 === 0 && value.length <= size * 2), - 'uniform ' + name, env.commandStr) - infix = '2f' - break - case GL_FLOAT_VEC3: - check$1.command( - isArrayLike(value) && (value.length && value.length % 3 === 0 && value.length <= size * 3), - 'uniform ' + name, env.commandStr) - infix = '3f' - break - case GL_FLOAT_VEC4: - check$1.command( - isArrayLike(value) && (value.length && value.length % 4 === 0 && value.length <= size * 4), - 'uniform ' + name, env.commandStr) - infix = '4f' - break - case GL_BOOL: - if (size === 1) { - check$1.commandType(value, 'boolean', 'uniform ' + name, env.commandStr) - } else { - check$1.command( - isArrayLike(value) && (value.length === size), - 'uniform ' + name, env.commandStr) - } - infix = '1i' - break - case GL_INT$3: - if (size === 1) { - check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr) - } else { - check$1.command( - isArrayLike(value) && (value.length === size), - 'uniform ' + name, env.commandStr) - } - infix = '1i' - break - case GL_BOOL_VEC2: - check$1.command( - isArrayLike(value) && (value.length && value.length % 2 === 0 && value.length <= size * 2), - 'uniform ' + name, env.commandStr) - infix = '2i' - break - case GL_INT_VEC2: - check$1.command( - isArrayLike(value) && (value.length && value.length % 2 === 0 && value.length <= size * 2), - 'uniform ' + name, env.commandStr) - infix = '2i' - break - case GL_BOOL_VEC3: - check$1.command( - isArrayLike(value) && (value.length && value.length % 3 === 0 && value.length <= size * 3), - 'uniform ' + name, env.commandStr) - infix = '3i' - break - case GL_INT_VEC3: - check$1.command( - isArrayLike(value) && (value.length && value.length % 3 === 0 && value.length <= size * 3), - 'uniform ' + name, env.commandStr) - infix = '3i' - break - case GL_BOOL_VEC4: - check$1.command( - isArrayLike(value) && (value.length && value.length % 4 === 0 && value.length <= size * 4), - 'uniform ' + name, env.commandStr) - infix = '4i' - break - case GL_INT_VEC4: - check$1.command( - isArrayLike(value) && (value.length && value.length % 4 === 0 && value.length <= size * 4), - 'uniform ' + name, env.commandStr) - infix = '4i' - break - } - if (size > 1) { - infix += 'v' - value = env.global.def('[' + - Array.prototype.slice.call(value) + ']') - } else { - value = isArrayLike(value) ? Array.prototype.slice.call(value) : value - } - scope(GL, '.uniform', infix, '(', LOCATION, ',', - value, - ');') - } - continue - } else { - VALUE = arg.append(env, scope) - } - } else { - if (!filter(SCOPE_DECL)) { - continue - } - VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']') - } - - if (type === GL_SAMPLER_2D) { - check$1(!Array.isArray(VALUE), 'must specify a scalar prop for textures') - scope( - 'if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){', - VALUE, '=', VALUE, '.color[0];', - '}') - } else if (type === GL_SAMPLER_CUBE) { - check$1(!Array.isArray(VALUE), 'must specify a scalar prop for cube maps') - scope( - 'if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){', - VALUE, '=', VALUE, '.color[0];', - '}') - } - - // perform type validation - check$1.optional(function () { - function emitCheck (pred, message) { - env.assert(scope, pred, - 'bad data or missing for uniform "' + name + '". ' + message) - } - - function checkType (type, size) { - if (size === 1) { - check$1(!Array.isArray(VALUE), 'must not specify an array type for uniform') - } - emitCheck( - 'Array.isArray(' + VALUE + ') && typeof ' + VALUE + '[0]===" ' + type + '"' + - ' || typeof ' + VALUE + '==="' + type + '"', - 'invalid type, expected ' + type) - } - - function checkVector (n, type, size) { - if (Array.isArray(VALUE)) { - check$1(VALUE.length && VALUE.length % n === 0 && VALUE.length <= n * size, 'must have length of ' + (size === 1 ? '' : 'n * ') + n) - } else { - emitCheck( - shared.isArrayLike + '(' + VALUE + ')&&' + VALUE + '.length && ' + VALUE + '.length % ' + n + ' === 0' + - ' && ' + VALUE + '.length<=' + n * size, - 'invalid vector, should have length of ' + (size === 1 ? '' : 'n * ') + n, env.commandStr) - } - } - - function checkTexture (target) { - check$1(!Array.isArray(VALUE), 'must not specify a value type') - emitCheck( - 'typeof ' + VALUE + '==="function"&&' + - VALUE + '._reglType==="texture' + - (target === GL_TEXTURE_2D$3 ? '2d' : 'Cube') + '"', - 'invalid texture type', env.commandStr) - } - - switch (type) { - case GL_INT$3: - checkType('number', size) - break - case GL_INT_VEC2: - checkVector(2, 'number', size) - break - case GL_INT_VEC3: - checkVector(3, 'number', size) - break - case GL_INT_VEC4: - checkVector(4, 'number', size) - break - case GL_FLOAT$8: - checkType('number', size) - break - case GL_FLOAT_VEC2: - checkVector(2, 'number', size) - break - case GL_FLOAT_VEC3: - checkVector(3, 'number', size) - break - case GL_FLOAT_VEC4: - checkVector(4, 'number', size) - break - case GL_BOOL: - checkType('boolean', size) - break - case GL_BOOL_VEC2: - checkVector(2, 'boolean', size) - break - case GL_BOOL_VEC3: - checkVector(3, 'boolean', size) - break - case GL_BOOL_VEC4: - checkVector(4, 'boolean', size) - break - case GL_FLOAT_MAT2: - checkVector(4, 'number', size) - break - case GL_FLOAT_MAT3: - checkVector(9, 'number', size) - break - case GL_FLOAT_MAT4: - checkVector(16, 'number', size) - break - case GL_SAMPLER_2D: - checkTexture(GL_TEXTURE_2D$3) - break - case GL_SAMPLER_CUBE: - checkTexture(GL_TEXTURE_CUBE_MAP$2) - break - } - }) - - var unroll = 1 - switch (type) { - case GL_SAMPLER_2D: - case GL_SAMPLER_CUBE: - var TEX = scope.def(VALUE, '._texture') - scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());') - scope.exit(TEX, '.unbind();') - continue - - case GL_INT$3: - case GL_BOOL: - infix = '1i' - break - - case GL_INT_VEC2: - case GL_BOOL_VEC2: - infix = '2i' - unroll = 2 - break - - case GL_INT_VEC3: - case GL_BOOL_VEC3: - infix = '3i' - unroll = 3 - break - - case GL_INT_VEC4: - case GL_BOOL_VEC4: - infix = '4i' - unroll = 4 - break - - case GL_FLOAT$8: - infix = '1f' - break - - case GL_FLOAT_VEC2: - infix = '2f' - unroll = 2 - break - - case GL_FLOAT_VEC3: - infix = '3f' - unroll = 3 - break - - case GL_FLOAT_VEC4: - infix = '4f' - unroll = 4 - break - - case GL_FLOAT_MAT2: - infix = 'Matrix2fv' - break - - case GL_FLOAT_MAT3: - infix = 'Matrix3fv' - break - - case GL_FLOAT_MAT4: - infix = 'Matrix4fv' - break - } - - if (infix.indexOf('Matrix') === -1 && size > 1) { - infix += 'v' - unroll = 1 - } - - if (infix.charAt(0) === 'M') { - scope(GL, '.uniform', infix, '(', LOCATION, ',') - var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2) - var STORAGE = env.global.def('new Float32Array(', matSize, ')') - if (Array.isArray(VALUE)) { - scope( - 'false,(', - loop(matSize, function (i) { - return STORAGE + '[' + i + ']=' + VALUE[i] - }), ',', STORAGE, ')') - } else { - scope( - 'false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(', - loop(matSize, function (i) { - return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']' - }), ',', STORAGE, ')') - } - scope(');') - } else if (unroll > 1) { - var prev = [] - var cur = [] - for (var j = 0; j < unroll; ++j) { - if (Array.isArray(VALUE)) { - cur.push(VALUE[j]) - } else { - cur.push(scope.def(VALUE + '[' + j + ']')) - } - if (isBatchInnerLoop) { - prev.push(scope.def()) - } - } - if (isBatchInnerLoop) { - scope('if(!', env.batchId, '||', prev.map(function (p, i) { - return p + '!==' + cur[i] - }).join('||'), '){', prev.map(function (p, i) { - return p + '=' + cur[i] + ';' - }).join('')) - } - scope(GL, '.uniform', infix, '(', LOCATION, ',', cur.join(','), ');') - if (isBatchInnerLoop) { - scope('}') - } - } else { - check$1(!Array.isArray(VALUE), 'uniform value must not be an array') - if (isBatchInnerLoop) { - var prevS = scope.def() - scope('if(!', env.batchId, '||', prevS, '!==', VALUE, '){', - prevS, '=', VALUE, ';') - } - scope(GL, '.uniform', infix, '(', LOCATION, ',', VALUE, ');') - if (isBatchInnerLoop) { - scope('}') - } - } - } - } - - function emitDraw (env, outer, inner, args) { - var shared = env.shared - var GL = shared.gl - var DRAW_STATE = shared.draw - - var drawOptions = args.draw - - function emitElements () { - var defn = drawOptions.elements - var ELEMENTS - var scope = outer - if (defn) { - if ((defn.contextDep && args.contextDynamic) || defn.propDep) { - scope = inner - } - ELEMENTS = defn.append(env, scope) - if (drawOptions.elementsActive) { - scope( - 'if(' + ELEMENTS + ')' + - GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$2 + ',' + ELEMENTS + '.buffer.buffer);') - } - } else { - ELEMENTS = scope.def() - scope( - ELEMENTS, '=', DRAW_STATE, '.', S_ELEMENTS, ';', - 'if(', ELEMENTS, '){', - GL, '.bindBuffer(', GL_ELEMENT_ARRAY_BUFFER$2, ',', ELEMENTS, '.buffer.buffer);}', - 'else if(', shared.vao, '.currentVAO){', - ELEMENTS, '=', env.shared.elements + '.getElements(' + shared.vao, '.currentVAO.elements);', - (!extVertexArrays ? 'if(' + ELEMENTS + ')' + GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$2 + ',' + ELEMENTS + '.buffer.buffer);' : ''), - '}') - } - return ELEMENTS - } - - function emitCount () { - var defn = drawOptions.count - var COUNT - var scope = outer - if (defn) { - if ((defn.contextDep && args.contextDynamic) || defn.propDep) { - scope = inner - } - COUNT = defn.append(env, scope) - check$1.optional(function () { - if (defn.MISSING) { - env.assert(outer, 'false', 'missing vertex count') - } - if (defn.DYNAMIC) { - env.assert(scope, COUNT + '>=0', 'missing vertex count') - } - }) - } else { - COUNT = scope.def(DRAW_STATE, '.', S_COUNT) - check$1.optional(function () { - env.assert(scope, COUNT + '>=0', 'missing vertex count') - }) - } - return COUNT - } - - var ELEMENTS = emitElements() - function emitValue (name) { - var defn = drawOptions[name] - if (defn) { - if ((defn.contextDep && args.contextDynamic) || defn.propDep) { - return defn.append(env, inner) - } else { - return defn.append(env, outer) - } - } else { - return outer.def(DRAW_STATE, '.', name) - } - } - - var PRIMITIVE = emitValue(S_PRIMITIVE) - var OFFSET = emitValue(S_OFFSET) - - var COUNT = emitCount() - if (typeof COUNT === 'number') { - if (COUNT === 0) { - return - } - } else { - inner('if(', COUNT, '){') - inner.exit('}') - } - - var INSTANCES, EXT_INSTANCING - if (extInstancing) { - INSTANCES = emitValue(S_INSTANCES) - EXT_INSTANCING = env.instancing - } - - var ELEMENT_TYPE = ELEMENTS + '.type' - - var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements) && !drawOptions.vaoActive - - function emitInstancing () { - function drawElements () { - inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [ - PRIMITIVE, - COUNT, - ELEMENT_TYPE, - OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$8 + ')>>1)', - INSTANCES - ], ');') - } - - function drawArrays () { - inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(', - [PRIMITIVE, OFFSET, COUNT, INSTANCES], ');') - } - - if (ELEMENTS && ELEMENTS !== 'null') { - if (!elementsStatic) { - inner('if(', ELEMENTS, '){') - drawElements() - inner('}else{') - drawArrays() - inner('}') - } else { - drawElements() - } - } else { - drawArrays() - } - } - - function emitRegular () { - function drawElements () { - inner(GL + '.drawElements(' + [ - PRIMITIVE, - COUNT, - ELEMENT_TYPE, - OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$8 + ')>>1)' - ] + ');') - } - - function drawArrays () { - inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');') - } - - if (ELEMENTS && ELEMENTS !== 'null') { - if (!elementsStatic) { - inner('if(', ELEMENTS, '){') - drawElements() - inner('}else{') - drawArrays() - inner('}') - } else { - drawElements() - } - } else { - drawArrays() - } - } - - if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) { - if (typeof INSTANCES === 'string') { - inner('if(', INSTANCES, '>0){') - emitInstancing() - inner('}else if(', INSTANCES, '<0){') - emitRegular() - inner('}') - } else { - emitInstancing() - } - } else { - emitRegular() - } - } - - function createBody (emitBody, parentEnv, args, program, count) { - var env = createREGLEnvironment() - var scope = env.proc('body', count) - check$1.optional(function () { - env.commandStr = parentEnv.commandStr - env.command = env.link(parentEnv.commandStr) - }) - if (extInstancing) { - env.instancing = scope.def( - env.shared.extensions, '.angle_instanced_arrays') - } - emitBody(env, scope, args, program) - return env.compile().body - } - - // =================================================== - // =================================================== - // DRAW PROC - // =================================================== - // =================================================== - function emitDrawBody (env, draw, args, program) { - injectExtensions(env, draw) - if (args.useVAO) { - if (args.drawVAO) { - draw(env.shared.vao, '.setVAO(', args.drawVAO.append(env, draw), ');') - } else { - draw(env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);') - } - } else { - draw(env.shared.vao, '.setVAO(null);') - emitAttributes(env, draw, args, program.attributes, function () { - return true - }) - } - emitUniforms(env, draw, args, program.uniforms, function () { - return true - }, false) - emitDraw(env, draw, draw, args) - } - - function emitDrawProc (env, args) { - var draw = env.proc('draw', 1) - - injectExtensions(env, draw) - - emitContext(env, draw, args.context) - emitPollFramebuffer(env, draw, args.framebuffer) - - emitPollState(env, draw, args) - emitSetOptions(env, draw, args.state) - - emitProfile(env, draw, args, false, true) - - var program = args.shader.progVar.append(env, draw) - draw(env.shared.gl, '.useProgram(', program, '.program);') - - if (args.shader.program) { - emitDrawBody(env, draw, args, args.shader.program) - } else { - draw(env.shared.vao, '.setVAO(null);') - var drawCache = env.global.def('{}') - var PROG_ID = draw.def(program, '.id') - var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']') - draw( - env.cond(CACHED_PROC) - .then(CACHED_PROC, '.call(this,a0);') - .else( - CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=', - env.link(function (program) { - return createBody(emitDrawBody, env, args, program, 1) - }), '(', program, ');', - CACHED_PROC, '.call(this,a0);')) - } - - if (Object.keys(args.state).length > 0) { - draw(env.shared.current, '.dirty=true;') - } - if (env.shared.vao) { - draw(env.shared.vao, '.setVAO(null);') - } - } - - // =================================================== - // =================================================== - // BATCH PROC - // =================================================== - // =================================================== - - function emitBatchDynamicShaderBody (env, scope, args, program) { - env.batchId = 'a1' - - injectExtensions(env, scope) - - function all () { - return true - } - - emitAttributes(env, scope, args, program.attributes, all) - emitUniforms(env, scope, args, program.uniforms, all, false) - emitDraw(env, scope, scope, args) - } - - function emitBatchBody (env, scope, args, program) { - injectExtensions(env, scope) - - var contextDynamic = args.contextDep - - var BATCH_ID = scope.def() - var PROP_LIST = 'a0' - var NUM_PROPS = 'a1' - var PROPS = scope.def() - env.shared.props = PROPS - env.batchId = BATCH_ID - - var outer = env.scope() - var inner = env.scope() - - scope( - outer.entry, - 'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){', - PROPS, '=', PROP_LIST, '[', BATCH_ID, '];', - inner, - '}', - outer.exit) - - function isInnerDefn (defn) { - return ((defn.contextDep && contextDynamic) || defn.propDep) - } - - function isOuterDefn (defn) { - return !isInnerDefn(defn) - } - - if (args.needsContext) { - emitContext(env, inner, args.context) - } - if (args.needsFramebuffer) { - emitPollFramebuffer(env, inner, args.framebuffer) - } - emitSetOptions(env, inner, args.state, isInnerDefn) - - if (args.profile && isInnerDefn(args.profile)) { - emitProfile(env, inner, args, false, true) - } - - if (!program) { - var progCache = env.global.def('{}') - var PROGRAM = args.shader.progVar.append(env, inner) - var PROG_ID = inner.def(PROGRAM, '.id') - var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']') - inner( - env.shared.gl, '.useProgram(', PROGRAM, '.program);', - 'if(!', CACHED_PROC, '){', - CACHED_PROC, '=', progCache, '[', PROG_ID, ']=', - env.link(function (program) { - return createBody( - emitBatchDynamicShaderBody, env, args, program, 2) - }), '(', PROGRAM, ');}', - CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');') - } else { - if (args.useVAO) { - if (args.drawVAO) { - if (isInnerDefn(args.drawVAO)) { - // vao is a prop - inner(env.shared.vao, '.setVAO(', args.drawVAO.append(env, inner), ');') - } else { - // vao is invariant - outer(env.shared.vao, '.setVAO(', args.drawVAO.append(env, outer), ');') - } - } else { - // scoped vao binding - outer(env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);') - } - } else { - outer(env.shared.vao, '.setVAO(null);') - emitAttributes(env, outer, args, program.attributes, isOuterDefn) - emitAttributes(env, inner, args, program.attributes, isInnerDefn) - } - emitUniforms(env, outer, args, program.uniforms, isOuterDefn, false) - emitUniforms(env, inner, args, program.uniforms, isInnerDefn, true) - emitDraw(env, outer, inner, args) - } - } - - function emitBatchProc (env, args) { - var batch = env.proc('batch', 2) - env.batchId = '0' - - injectExtensions(env, batch) - - // Check if any context variables depend on props - var contextDynamic = false - var needsContext = true - Object.keys(args.context).forEach(function (name) { - contextDynamic = contextDynamic || args.context[name].propDep - }) - if (!contextDynamic) { - emitContext(env, batch, args.context) - needsContext = false - } - - // framebuffer state affects framebufferWidth/height context vars - var framebuffer = args.framebuffer - var needsFramebuffer = false - if (framebuffer) { - if (framebuffer.propDep) { - contextDynamic = needsFramebuffer = true - } else if (framebuffer.contextDep && contextDynamic) { - needsFramebuffer = true - } - if (!needsFramebuffer) { - emitPollFramebuffer(env, batch, framebuffer) - } - } else { - emitPollFramebuffer(env, batch, null) - } - - // viewport is weird because it can affect context vars - if (args.state.viewport && args.state.viewport.propDep) { - contextDynamic = true - } - - function isInnerDefn (defn) { - return (defn.contextDep && contextDynamic) || defn.propDep - } - - // set webgl options - emitPollState(env, batch, args) - emitSetOptions(env, batch, args.state, function (defn) { - return !isInnerDefn(defn) - }) - - if (!args.profile || !isInnerDefn(args.profile)) { - emitProfile(env, batch, args, false, 'a1') - } - - // Save these values to args so that the batch body routine can use them - args.contextDep = contextDynamic - args.needsContext = needsContext - args.needsFramebuffer = needsFramebuffer - - // determine if shader is dynamic - var progDefn = args.shader.progVar - if ((progDefn.contextDep && contextDynamic) || progDefn.propDep) { - emitBatchBody( - env, - batch, - args, - null) - } else { - var PROGRAM = progDefn.append(env, batch) - batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);') - if (args.shader.program) { - emitBatchBody( - env, - batch, - args, - args.shader.program) - } else { - batch(env.shared.vao, '.setVAO(null);') - var batchCache = env.global.def('{}') - var PROG_ID = batch.def(PROGRAM, '.id') - var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']') - batch( - env.cond(CACHED_PROC) - .then(CACHED_PROC, '.call(this,a0,a1);') - .else( - CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=', - env.link(function (program) { - return createBody(emitBatchBody, env, args, program, 2) - }), '(', PROGRAM, ');', - CACHED_PROC, '.call(this,a0,a1);')) - } - } - - if (Object.keys(args.state).length > 0) { - batch(env.shared.current, '.dirty=true;') - } - - if (env.shared.vao) { - batch(env.shared.vao, '.setVAO(null);') - } - } - - // =================================================== - // =================================================== - // SCOPE COMMAND - // =================================================== - // =================================================== - function emitScopeProc (env, args) { - var scope = env.proc('scope', 3) - env.batchId = 'a2' - - var shared = env.shared - var CURRENT_STATE = shared.current - - emitContext(env, scope, args.context) - - if (args.framebuffer) { - args.framebuffer.append(env, scope) - } - - sortState(Object.keys(args.state)).forEach(function (name) { - var defn = args.state[name] - var value = defn.append(env, scope) - if (isArrayLike(value)) { - value.forEach(function (v, i) { - scope.set(env.next[name], '[' + i + ']', v) - }) - } else { - scope.set(shared.next, '.' + name, value) - } - }) - - emitProfile(env, scope, args, true, true) - - ;[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach( - function (opt) { - var variable = args.draw[opt] - if (!variable) { - return - } - scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope)) - }) - - Object.keys(args.uniforms).forEach(function (opt) { - var value = args.uniforms[opt].append(env, scope) - if (Array.isArray(value)) { - value = '[' + value.join() + ']' - } - scope.set( - shared.uniforms, - '[' + stringStore.id(opt) + ']', - value) - }) - - Object.keys(args.attributes).forEach(function (name) { - var record = args.attributes[name].append(env, scope) - var scopeAttrib = env.scopeAttrib(name) - Object.keys(new AttributeRecord()).forEach(function (prop) { - scope.set(scopeAttrib, '.' + prop, record[prop]) - }) - }) - - if (args.scopeVAO) { - scope.set(shared.vao, '.targetVAO', args.scopeVAO.append(env, scope)) - } - - function saveShader (name) { - var shader = args.shader[name] - if (shader) { - scope.set(shared.shader, '.' + name, shader.append(env, scope)) - } - } - saveShader(S_VERT) - saveShader(S_FRAG) - - if (Object.keys(args.state).length > 0) { - scope(CURRENT_STATE, '.dirty=true;') - scope.exit(CURRENT_STATE, '.dirty=true;') - } - - scope('a1(', env.shared.context, ',a0,', env.batchId, ');') - } - - function isDynamicObject (object) { - if (typeof object !== 'object' || isArrayLike(object)) { - return - } - var props = Object.keys(object) - for (var i = 0; i < props.length; ++i) { - if (dynamic.isDynamic(object[props[i]])) { - return true - } - } - return false - } - - function splatObject (env, options, name) { - var object = options.static[name] - if (!object || !isDynamicObject(object)) { - return - } - - var globals = env.global - var keys = Object.keys(object) - var thisDep = false - var contextDep = false - var propDep = false - var objectRef = env.global.def('{}') - keys.forEach(function (key) { - var value = object[key] - if (dynamic.isDynamic(value)) { - if (typeof value === 'function') { - value = object[key] = dynamic.unbox(value) - } - var deps = createDynamicDecl(value, null) - thisDep = thisDep || deps.thisDep - propDep = propDep || deps.propDep - contextDep = contextDep || deps.contextDep - } else { - globals(objectRef, '.', key, '=') - switch (typeof value) { - case 'number': - globals(value) - break - case 'string': - globals('"', value, '"') - break - case 'object': - if (Array.isArray(value)) { - globals('[', value.join(), ']') - } - break - default: - globals(env.link(value)) - break - } - globals(';') - } - }) - - function appendBlock (env, block) { - keys.forEach(function (key) { - var value = object[key] - if (!dynamic.isDynamic(value)) { - return - } - var ref = env.invoke(block, value) - block(objectRef, '.', key, '=', ref, ';') - }) - } - - options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, { - thisDep: thisDep, - contextDep: contextDep, - propDep: propDep, - ref: objectRef, - append: appendBlock - }) - delete options.static[name] - } - - // =========================================================================== - // =========================================================================== - // MAIN DRAW COMMAND - // =========================================================================== - // =========================================================================== - function compileCommand (options, attributes, uniforms, context, stats) { - var env = createREGLEnvironment() - - // link stats, so that we can easily access it in the program. - env.stats = env.link(stats) - - // splat options and attributes to allow for dynamic nested properties - Object.keys(attributes.static).forEach(function (key) { - splatObject(env, attributes, key) - }) - NESTED_OPTIONS.forEach(function (name) { - splatObject(env, options, name) - }) - - var args = parseArguments(options, attributes, uniforms, context, env) - - emitDrawProc(env, args) - emitScopeProc(env, args) - emitBatchProc(env, args) - - return extend(env.compile(), { - destroy: function () { - args.shader.program.destroy() - } - }) - } - - // =========================================================================== - // =========================================================================== - // POLL / REFRESH - // =========================================================================== - // =========================================================================== - return { - next: nextState, - current: currentState, - procs: (function () { - var env = createREGLEnvironment() - var poll = env.proc('poll') - var refresh = env.proc('refresh') - var common = env.block() - poll(common) - refresh(common) - - var shared = env.shared - var GL = shared.gl - var NEXT_STATE = shared.next - var CURRENT_STATE = shared.current - - common(CURRENT_STATE, '.dirty=false;') - - emitPollFramebuffer(env, poll) - emitPollFramebuffer(env, refresh, null, true) - - // Refresh updates all attribute state changes - var INSTANCING - if (extInstancing) { - INSTANCING = env.link(extInstancing) - } - - // update vertex array bindings - if (extensions.oes_vertex_array_object) { - refresh(env.link(extensions.oes_vertex_array_object), '.bindVertexArrayOES(null);') - } - for (var i = 0; i < limits.maxAttributes; ++i) { - var BINDING = refresh.def(shared.attributes, '[', i, ']') - var ifte = env.cond(BINDING, '.buffer') - ifte.then( - GL, '.enableVertexAttribArray(', i, ');', - GL, '.bindBuffer(', - GL_ARRAY_BUFFER$2, ',', - BINDING, '.buffer.buffer);', - GL, '.vertexAttribPointer(', - i, ',', - BINDING, '.size,', - BINDING, '.type,', - BINDING, '.normalized,', - BINDING, '.stride,', - BINDING, '.offset);' - ).else( - GL, '.disableVertexAttribArray(', i, ');', - GL, '.vertexAttrib4f(', - i, ',', - BINDING, '.x,', - BINDING, '.y,', - BINDING, '.z,', - BINDING, '.w);', - BINDING, '.buffer=null;') - refresh(ifte) - if (extInstancing) { - refresh( - INSTANCING, '.vertexAttribDivisorANGLE(', - i, ',', - BINDING, '.divisor);') - } - } - refresh( - env.shared.vao, '.currentVAO=null;', - env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);') - - Object.keys(GL_FLAGS).forEach(function (flag) { - var cap = GL_FLAGS[flag] - var NEXT = common.def(NEXT_STATE, '.', flag) - var block = env.block() - block('if(', NEXT, '){', - GL, '.enable(', cap, ')}else{', - GL, '.disable(', cap, ')}', - CURRENT_STATE, '.', flag, '=', NEXT, ';') - refresh(block) - poll( - 'if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){', - block, - '}') - }) - - Object.keys(GL_VARIABLES).forEach(function (name) { - var func = GL_VARIABLES[name] - var init = currentState[name] - var NEXT, CURRENT - var block = env.block() - block(GL, '.', func, '(') - if (isArrayLike(init)) { - var n = init.length - NEXT = env.global.def(NEXT_STATE, '.', name) - CURRENT = env.global.def(CURRENT_STATE, '.', name) - block( - loop(n, function (i) { - return NEXT + '[' + i + ']' - }), ');', - loop(n, function (i) { - return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];' - }).join('')) - poll( - 'if(', loop(n, function (i) { - return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']' - }).join('||'), '){', - block, - '}') - } else { - NEXT = common.def(NEXT_STATE, '.', name) - CURRENT = common.def(CURRENT_STATE, '.', name) - block( - NEXT, ');', - CURRENT_STATE, '.', name, '=', NEXT, ';') - poll( - 'if(', NEXT, '!==', CURRENT, '){', - block, - '}') - } - refresh(block) - }) - - return env.compile() - })(), - compile: compileCommand - } -} - -function stats () { - return { - vaoCount: 0, - bufferCount: 0, - elementsCount: 0, - framebufferCount: 0, - shaderCount: 0, - textureCount: 0, - cubeCount: 0, - renderbufferCount: 0, - maxTextureUnits: 0 - } -} - -var GL_QUERY_RESULT_EXT = 0x8866 -var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867 -var GL_TIME_ELAPSED_EXT = 0x88BF - -var createTimer = function (gl, extensions) { - if (!extensions.ext_disjoint_timer_query) { - return null - } - - // QUERY POOL BEGIN - var queryPool = [] - function allocQuery () { - return queryPool.pop() || extensions.ext_disjoint_timer_query.createQueryEXT() - } - function freeQuery (query) { - queryPool.push(query) - } - // QUERY POOL END - - var pendingQueries = [] - function beginQuery (stats) { - var query = allocQuery() - extensions.ext_disjoint_timer_query.beginQueryEXT(GL_TIME_ELAPSED_EXT, query) - pendingQueries.push(query) - pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats) - } - - function endQuery () { - extensions.ext_disjoint_timer_query.endQueryEXT(GL_TIME_ELAPSED_EXT) - } - - // - // Pending stats pool. - // - function PendingStats () { - this.startQueryIndex = -1 - this.endQueryIndex = -1 - this.sum = 0 - this.stats = null - } - var pendingStatsPool = [] - function allocPendingStats () { - return pendingStatsPool.pop() || new PendingStats() - } - function freePendingStats (pendingStats) { - pendingStatsPool.push(pendingStats) - } - // Pending stats pool end - - var pendingStats = [] - function pushScopeStats (start, end, stats) { - var ps = allocPendingStats() - ps.startQueryIndex = start - ps.endQueryIndex = end - ps.sum = 0 - ps.stats = stats - pendingStats.push(ps) - } - - // we should call this at the beginning of the frame, - // in order to update gpuTime - var timeSum = [] - var queryPtr = [] - function update () { - var ptr, i - - var n = pendingQueries.length - if (n === 0) { - return - } - - // Reserve space - queryPtr.length = Math.max(queryPtr.length, n + 1) - timeSum.length = Math.max(timeSum.length, n + 1) - timeSum[0] = 0 - queryPtr[0] = 0 - - // Update all pending timer queries - var queryTime = 0 - ptr = 0 - for (i = 0; i < pendingQueries.length; ++i) { - var query = pendingQueries[i] - if (extensions.ext_disjoint_timer_query.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) { - queryTime += extensions.ext_disjoint_timer_query.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT) - freeQuery(query) - } else { - pendingQueries[ptr++] = query - } - timeSum[i + 1] = queryTime - queryPtr[i + 1] = ptr - } - pendingQueries.length = ptr - - // Update all pending stat queries - ptr = 0 - for (i = 0; i < pendingStats.length; ++i) { - var stats = pendingStats[i] - var start = stats.startQueryIndex - var end = stats.endQueryIndex - stats.sum += timeSum[end] - timeSum[start] - var startPtr = queryPtr[start] - var endPtr = queryPtr[end] - if (endPtr === startPtr) { - stats.stats.gpuTime += stats.sum / 1e6 - freePendingStats(stats) - } else { - stats.startQueryIndex = startPtr - stats.endQueryIndex = endPtr - pendingStats[ptr++] = stats - } - } - pendingStats.length = ptr - } - - return { - beginQuery: beginQuery, - endQuery: endQuery, - pushScopeStats: pushScopeStats, - update: update, - getNumPendingQueries: function () { - return pendingQueries.length - }, - clear: function () { - queryPool.push.apply(queryPool, pendingQueries) - for (var i = 0; i < queryPool.length; i++) { - extensions.ext_disjoint_timer_query.deleteQueryEXT(queryPool[i]) - } - pendingQueries.length = 0 - queryPool.length = 0 - }, - restore: function () { - pendingQueries.length = 0 - queryPool.length = 0 - } - } -} - -var GL_COLOR_BUFFER_BIT = 16384 -var GL_DEPTH_BUFFER_BIT = 256 -var GL_STENCIL_BUFFER_BIT = 1024 - -var GL_ARRAY_BUFFER = 34962 - -var CONTEXT_LOST_EVENT = 'webglcontextlost' -var CONTEXT_RESTORED_EVENT = 'webglcontextrestored' - -var DYN_PROP = 1 -var DYN_CONTEXT = 2 -var DYN_STATE = 3 - -function find (haystack, needle) { - for (var i = 0; i < haystack.length; ++i) { - if (haystack[i] === needle) { - return i - } - } - return -1 -} - -function wrapREGL (args) { - var config = parseArgs(args) - if (!config) { - return null - } - - var gl = config.gl - var glAttributes = gl.getContextAttributes() - var contextLost = gl.isContextLost() - - var extensionState = createExtensionCache(gl, config) - if (!extensionState) { - return null - } - - var stringStore = createStringStore() - var stats$$1 = stats() - var extensions = extensionState.extensions - var timer = createTimer(gl, extensions) - - var START_TIME = clock() - var WIDTH = gl.drawingBufferWidth - var HEIGHT = gl.drawingBufferHeight - - var contextState = { - tick: 0, - time: 0, - viewportWidth: WIDTH, - viewportHeight: HEIGHT, - framebufferWidth: WIDTH, - framebufferHeight: HEIGHT, - drawingBufferWidth: WIDTH, - drawingBufferHeight: HEIGHT, - pixelRatio: config.pixelRatio - } - var uniformState = {} - var drawState = { - elements: null, - primitive: 4, // GL_TRIANGLES - count: -1, - offset: 0, - instances: -1 - } - - var limits = wrapLimits(gl, extensions) - var bufferState = wrapBufferState( - gl, - stats$$1, - config, - destroyBuffer) - var elementState = wrapElementsState(gl, extensions, bufferState, stats$$1) - var attributeState = wrapAttributeState( - gl, - extensions, - limits, - stats$$1, - bufferState, - elementState, - drawState) - function destroyBuffer (buffer) { - return attributeState.destroyBuffer(buffer) - } - var shaderState = wrapShaderState(gl, stringStore, stats$$1, config) - var textureState = createTextureSet( - gl, - extensions, - limits, - function () { core.procs.poll() }, - contextState, - stats$$1, - config) - var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats$$1, config) - var framebufferState = wrapFBOState( - gl, - extensions, - limits, - textureState, - renderbufferState, - stats$$1) - var core = reglCore( - gl, - stringStore, - extensions, - limits, - bufferState, - elementState, - textureState, - framebufferState, - uniformState, - attributeState, - shaderState, - drawState, - contextState, - timer, - config) - var readPixels = wrapReadPixels( - gl, - framebufferState, - core.procs.poll, - contextState, - glAttributes, extensions, limits) - - var nextState = core.next - var canvas = gl.canvas - - var rafCallbacks = [] - var lossCallbacks = [] - var restoreCallbacks = [] - var destroyCallbacks = [config.onDestroy] - - var activeRAF = null - function handleRAF () { - if (rafCallbacks.length === 0) { - if (timer) { - timer.update() - } - activeRAF = null - return - } - - // schedule next animation frame - activeRAF = raf.next(handleRAF) - - // poll for changes - poll() - - // fire a callback for all pending rafs - for (var i = rafCallbacks.length - 1; i >= 0; --i) { - var cb = rafCallbacks[i] - if (cb) { - cb(contextState, null, 0) - } - } - - // flush all pending webgl calls - gl.flush() - - // poll GPU timers *after* gl.flush so we don't delay command dispatch - if (timer) { - timer.update() - } - } - - function startRAF () { - if (!activeRAF && rafCallbacks.length > 0) { - activeRAF = raf.next(handleRAF) - } - } - - function stopRAF () { - if (activeRAF) { - raf.cancel(handleRAF) - activeRAF = null - } - } - - function handleContextLoss (event) { - event.preventDefault() - - // set context lost flag - contextLost = true - - // pause request animation frame - stopRAF() - - // lose context - lossCallbacks.forEach(function (cb) { - cb() - }) - } - - function handleContextRestored (event) { - // clear error code - gl.getError() - - // clear context lost flag - contextLost = false - - // refresh state - extensionState.restore() - shaderState.restore() - bufferState.restore() - textureState.restore() - renderbufferState.restore() - framebufferState.restore() - attributeState.restore() - if (timer) { - timer.restore() - } - - // refresh state - core.procs.refresh() - - // restart RAF - startRAF() - - // restore context - restoreCallbacks.forEach(function (cb) { - cb() - }) - } - - if (canvas) { - canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false) - canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false) - } - - function destroy () { - rafCallbacks.length = 0 - stopRAF() - - if (canvas) { - canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss) - canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored) - } - - shaderState.clear() - framebufferState.clear() - renderbufferState.clear() - attributeState.clear() - textureState.clear() - elementState.clear() - bufferState.clear() - - if (timer) { - timer.clear() - } - - destroyCallbacks.forEach(function (cb) { - cb() - }) - } - - function compileProcedure (options) { - check$1(!!options, 'invalid args to regl({...})') - check$1.type(options, 'object', 'invalid args to regl({...})') - - function flattenNestedOptions (options) { - var result = extend({}, options) - delete result.uniforms - delete result.attributes - delete result.context - delete result.vao - - if ('stencil' in result && result.stencil.op) { - result.stencil.opBack = result.stencil.opFront = result.stencil.op - delete result.stencil.op - } - - function merge (name) { - if (name in result) { - var child = result[name] - delete result[name] - Object.keys(child).forEach(function (prop) { - result[name + '.' + prop] = child[prop] - }) - } - } - merge('blend') - merge('depth') - merge('cull') - merge('stencil') - merge('polygonOffset') - merge('scissor') - merge('sample') - - if ('vao' in options) { - result.vao = options.vao - } - - return result - } - - function separateDynamic (object, useArrays) { - var staticItems = {} - var dynamicItems = {} - Object.keys(object).forEach(function (option) { - var value = object[option] - if (dynamic.isDynamic(value)) { - dynamicItems[option] = dynamic.unbox(value, option) - return - } else if (useArrays && Array.isArray(value)) { - for (var i = 0; i < value.length; ++i) { - if (dynamic.isDynamic(value[i])) { - dynamicItems[option] = dynamic.unbox(value, option) - return - } - } - } - staticItems[option] = value - }) - return { - dynamic: dynamicItems, - static: staticItems - } - } - - // Treat context variables separate from other dynamic variables - var context = separateDynamic(options.context || {}, true) - var uniforms = separateDynamic(options.uniforms || {}, true) - var attributes = separateDynamic(options.attributes || {}, false) - var opts = separateDynamic(flattenNestedOptions(options), false) - - var stats$$1 = { - gpuTime: 0.0, - cpuTime: 0.0, - count: 0 - } - - var compiled = core.compile(opts, attributes, uniforms, context, stats$$1) - - var draw = compiled.draw - var batch = compiled.batch - var scope = compiled.scope - - // FIXME: we should modify code generation for batch commands so this - // isn't necessary - var EMPTY_ARRAY = [] - function reserve (count) { - while (EMPTY_ARRAY.length < count) { - EMPTY_ARRAY.push(null) - } - return EMPTY_ARRAY - } - - function REGLCommand (args, body) { - var i - if (contextLost) { - check$1.raise('context lost') - } - if (typeof args === 'function') { - return scope.call(this, null, args, 0) - } else if (typeof body === 'function') { - if (typeof args === 'number') { - for (i = 0; i < args; ++i) { - scope.call(this, null, body, i) - } - } else if (Array.isArray(args)) { - for (i = 0; i < args.length; ++i) { - scope.call(this, args[i], body, i) - } - } else { - return scope.call(this, args, body, 0) - } - } else if (typeof args === 'number') { - if (args > 0) { - return batch.call(this, reserve(args | 0), args | 0) - } - } else if (Array.isArray(args)) { - if (args.length) { - return batch.call(this, args, args.length) - } - } else { - return draw.call(this, args) - } - } - - return extend(REGLCommand, { - stats: stats$$1, - destroy: function () { - compiled.destroy() - } - }) - } - - var setFBO = framebufferState.setFBO = compileProcedure({ - framebuffer: dynamic.define.call(null, DYN_PROP, 'framebuffer') - }) - - function clearImpl (_, options) { - var clearFlags = 0 - core.procs.poll() - - var c = options.color - if (c) { - gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0) - clearFlags |= GL_COLOR_BUFFER_BIT - } - if ('depth' in options) { - gl.clearDepth(+options.depth) - clearFlags |= GL_DEPTH_BUFFER_BIT - } - if ('stencil' in options) { - gl.clearStencil(options.stencil | 0) - clearFlags |= GL_STENCIL_BUFFER_BIT - } - - check$1(!!clearFlags, 'called regl.clear with no buffer specified') - gl.clear(clearFlags) - } - - function clear (options) { - check$1( - typeof options === 'object' && options, - 'regl.clear() takes an object as input') - if ('framebuffer' in options) { - if (options.framebuffer && - options.framebuffer_reglType === 'framebufferCube') { - for (var i = 0; i < 6; ++i) { - setFBO(extend({ - framebuffer: options.framebuffer.faces[i] - }, options), clearImpl) - } - } else { - setFBO(options, clearImpl) - } - } else { - clearImpl(null, options) - } - } - - function frame (cb) { - check$1.type(cb, 'function', 'regl.frame() callback must be a function') - rafCallbacks.push(cb) - - function cancel () { - // FIXME: should we check something other than equals cb here? - // what if a user calls frame twice with the same callback... - // - var i = find(rafCallbacks, cb) - check$1(i >= 0, 'cannot cancel a frame twice') - function pendingCancel () { - var index = find(rafCallbacks, pendingCancel) - rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1] - rafCallbacks.length -= 1 - if (rafCallbacks.length <= 0) { - stopRAF() - } - } - rafCallbacks[i] = pendingCancel - } - - startRAF() - - return { - cancel: cancel - } - } - - // poll viewport - function pollViewport () { - var viewport = nextState.viewport - var scissorBox = nextState.scissor_box - viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0 - contextState.viewportWidth = - contextState.framebufferWidth = - contextState.drawingBufferWidth = - viewport[2] = - scissorBox[2] = gl.drawingBufferWidth - contextState.viewportHeight = - contextState.framebufferHeight = - contextState.drawingBufferHeight = - viewport[3] = - scissorBox[3] = gl.drawingBufferHeight - } - - function poll () { - contextState.tick += 1 - contextState.time = now() - pollViewport() - core.procs.poll() - } - - function refresh () { - textureState.refresh() - pollViewport() - core.procs.refresh() - if (timer) { - timer.update() - } - } - - function now () { - return (clock() - START_TIME) / 1000.0 - } - - refresh() - - function addListener (event, callback) { - check$1.type(callback, 'function', 'listener callback must be a function') - - var callbacks - switch (event) { - case 'frame': - return frame(callback) - case 'lost': - callbacks = lossCallbacks - break - case 'restore': - callbacks = restoreCallbacks - break - case 'destroy': - callbacks = destroyCallbacks - break - default: - check$1.raise('invalid event, must be one of frame,lost,restore,destroy') - } - - callbacks.push(callback) - return { - cancel: function () { - for (var i = 0; i < callbacks.length; ++i) { - if (callbacks[i] === callback) { - callbacks[i] = callbacks[callbacks.length - 1] - callbacks.pop() - return - } - } - } - } - } - - var regl = extend(compileProcedure, { - // Clear current FBO - clear: clear, - - // Short cuts for dynamic variables - prop: dynamic.define.bind(null, DYN_PROP), - context: dynamic.define.bind(null, DYN_CONTEXT), - this: dynamic.define.bind(null, DYN_STATE), - - // executes an empty draw command - draw: compileProcedure({}), - - // Resources - buffer: function (options) { - return bufferState.create(options, GL_ARRAY_BUFFER, false, false) - }, - elements: function (options) { - return elementState.create(options, false) - }, - texture: textureState.create2D, - cube: textureState.createCube, - renderbuffer: renderbufferState.create, - framebuffer: framebufferState.create, - framebufferCube: framebufferState.createCube, - vao: attributeState.createVAO, - - // Expose context attributes - attributes: glAttributes, - - // Frame rendering - frame: frame, - on: addListener, - - // System limits - limits: limits, - hasExtension: function (name) { - return limits.extensions.indexOf(name.toLowerCase()) >= 0 - }, - - // Read pixels - read: readPixels, - - // Destroy regl and all associated resources - destroy: destroy, - - // Direct GL state manipulation - _gl: gl, - _refresh: refresh, - - poll: function () { - poll() - if (timer) { - timer.update() - } - }, - - // Current time - now: now, - - // regl Statistics Information - stats: stats$$1 - }) - - config.onDone(null, regl) - - return regl -} - -return wrapREGL; - -}))); -//# sourceMappingURL=regl.js.map diff --git a/lib/webgl-debug.js b/lib/webgl-debug.js deleted file mode 100644 index ac417e3..0000000 --- a/lib/webgl-debug.js +++ /dev/null @@ -1,1195 +0,0 @@ -/* -** Copyright (c) 2012 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ - -// Various functions for helping debug WebGL apps. - -WebGLDebugUtils = function() { - -/** - * Wrapped logging function. - * @param {string} msg Message to log. - */ -var log = function(msg) { - if (window.console && window.console.log) { - window.console.log(msg); - } -}; - -/** - * Wrapped error logging function. - * @param {string} msg Message to log. - */ -var error = function(msg) { - if (window.console && window.console.error) { - window.console.error(msg); - } else { - log(msg); - } -}; - - -/** - * Which arguments are enums based on the number of arguments to the function. - * So - * 'texImage2D': { - * 9: { 0:true, 2:true, 6:true, 7:true }, - * 6: { 0:true, 2:true, 3:true, 4:true }, - * }, - * - * means if there are 9 arguments then 6 and 7 are enums, if there are 6 - * arguments 3 and 4 are enums - * - * @type {!Object.} - */ -var glValidEnumContexts = { - // Generic setters and getters - - 'enable': {1: { 0:true }}, - 'disable': {1: { 0:true }}, - 'getParameter': {1: { 0:true }}, - - // Rendering - - 'drawArrays': {3:{ 0:true }}, - 'drawElements': {4:{ 0:true, 2:true }}, - - // Shaders - - 'createShader': {1: { 0:true }}, - 'getShaderParameter': {2: { 1:true }}, - 'getProgramParameter': {2: { 1:true }}, - 'getShaderPrecisionFormat': {2: { 0: true, 1:true }}, - - // Vertex attributes - - 'getVertexAttrib': {2: { 1:true }}, - 'vertexAttribPointer': {6: { 2:true }}, - - // Textures - - 'bindTexture': {2: { 0:true }}, - 'activeTexture': {1: { 0:true }}, - 'getTexParameter': {2: { 0:true, 1:true }}, - 'texParameterf': {3: { 0:true, 1:true }}, - 'texParameteri': {3: { 0:true, 1:true, 2:true }}, - // texImage2D and texSubImage2D are defined below with WebGL 2 entrypoints - 'copyTexImage2D': {8: { 0:true, 2:true }}, - 'copyTexSubImage2D': {8: { 0:true }}, - 'generateMipmap': {1: { 0:true }}, - // compressedTexImage2D and compressedTexSubImage2D are defined below with WebGL 2 entrypoints - - // Buffer objects - - 'bindBuffer': {2: { 0:true }}, - // bufferData and bufferSubData are defined below with WebGL 2 entrypoints - 'getBufferParameter': {2: { 0:true, 1:true }}, - - // Renderbuffers and framebuffers - - 'pixelStorei': {2: { 0:true, 1:true }}, - // readPixels is defined below with WebGL 2 entrypoints - 'bindRenderbuffer': {2: { 0:true }}, - 'bindFramebuffer': {2: { 0:true }}, - 'checkFramebufferStatus': {1: { 0:true }}, - 'framebufferRenderbuffer': {4: { 0:true, 1:true, 2:true }}, - 'framebufferTexture2D': {5: { 0:true, 1:true, 2:true }}, - 'getFramebufferAttachmentParameter': {3: { 0:true, 1:true, 2:true }}, - 'getRenderbufferParameter': {2: { 0:true, 1:true }}, - 'renderbufferStorage': {4: { 0:true, 1:true }}, - - // Frame buffer operations (clear, blend, depth test, stencil) - - 'clear': {1: { 0: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }}}, - 'depthFunc': {1: { 0:true }}, - 'blendFunc': {2: { 0:true, 1:true }}, - 'blendFuncSeparate': {4: { 0:true, 1:true, 2:true, 3:true }}, - 'blendEquation': {1: { 0:true }}, - 'blendEquationSeparate': {2: { 0:true, 1:true }}, - 'stencilFunc': {3: { 0:true }}, - 'stencilFuncSeparate': {4: { 0:true, 1:true }}, - 'stencilMaskSeparate': {2: { 0:true }}, - 'stencilOp': {3: { 0:true, 1:true, 2:true }}, - 'stencilOpSeparate': {4: { 0:true, 1:true, 2:true, 3:true }}, - - // Culling - - 'cullFace': {1: { 0:true }}, - 'frontFace': {1: { 0:true }}, - - // ANGLE_instanced_arrays extension - - 'drawArraysInstancedANGLE': {4: { 0:true }}, - 'drawElementsInstancedANGLE': {5: { 0:true, 2:true }}, - - // EXT_blend_minmax extension - - 'blendEquationEXT': {1: { 0:true }}, - - // WebGL 2 Buffer objects - - 'bufferData': { - 3: { 0:true, 2:true }, // WebGL 1 - 4: { 0:true, 2:true }, // WebGL 2 - 5: { 0:true, 2:true } // WebGL 2 - }, - 'bufferSubData': { - 3: { 0:true }, // WebGL 1 - 4: { 0:true }, // WebGL 2 - 5: { 0:true } // WebGL 2 - }, - 'copyBufferSubData': {5: { 0:true, 1:true }}, - 'getBufferSubData': {3: { 0:true }, 4: { 0:true }, 5: { 0:true }}, - - // WebGL 2 Framebuffer objects - - 'blitFramebuffer': {10: { 8: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }, 9:true }}, - 'framebufferTextureLayer': {5: { 0:true, 1:true }}, - 'invalidateFramebuffer': {2: { 0:true }}, - 'invalidateSubFramebuffer': {6: { 0:true }}, - 'readBuffer': {1: { 0:true }}, - - // WebGL 2 Renderbuffer objects - - 'getInternalformatParameter': {3: { 0:true, 1:true, 2:true }}, - 'renderbufferStorageMultisample': {5: { 0:true, 2:true }}, - - // WebGL 2 Texture objects - - 'texStorage2D': {5: { 0:true, 2:true }}, - 'texStorage3D': {6: { 0:true, 2:true }}, - 'texImage2D': { - 9: { 0:true, 2:true, 6:true, 7:true }, // WebGL 1 & 2 - 6: { 0:true, 2:true, 3:true, 4:true }, // WebGL 1 - 10: { 0:true, 2:true, 6:true, 7:true } // WebGL 2 - }, - 'texImage3D': { - 10: { 0:true, 2:true, 7:true, 8:true }, - 11: { 0:true, 2:true, 7:true, 8:true } - }, - 'texSubImage2D': { - 9: { 0:true, 6:true, 7:true }, // WebGL 1 & 2 - 7: { 0:true, 4:true, 5:true }, // WebGL 1 - 10: { 0:true, 6:true, 7:true } // WebGL 2 - }, - 'texSubImage3D': { - 11: { 0:true, 8:true, 9:true }, - 12: { 0:true, 8:true, 9:true } - }, - 'copyTexSubImage3D': {9: { 0:true }}, - 'compressedTexImage2D': { - 7: { 0: true, 2:true }, // WebGL 1 & 2 - 8: { 0: true, 2:true }, // WebGL 2 - 9: { 0: true, 2:true } // WebGL 2 - }, - 'compressedTexImage3D': { - 8: { 0: true, 2:true }, - 9: { 0: true, 2:true }, - 10: { 0: true, 2:true } - }, - 'compressedTexSubImage2D': { - 8: { 0: true, 6:true }, // WebGL 1 & 2 - 9: { 0: true, 6:true }, // WebGL 2 - 10: { 0: true, 6:true } // WebGL 2 - }, - 'compressedTexSubImage3D': { - 10: { 0: true, 8:true }, - 11: { 0: true, 8:true }, - 12: { 0: true, 8:true } - }, - - // WebGL 2 Vertex attribs - - 'vertexAttribIPointer': {5: { 2:true }}, - - // WebGL 2 Writing to the drawing buffer - - 'drawArraysInstanced': {4: { 0:true }}, - 'drawElementsInstanced': {5: { 0:true, 2:true }}, - 'drawRangeElements': {6: { 0:true, 4:true }}, - - // WebGL 2 Reading back pixels - - 'readPixels': { - 7: { 4:true, 5:true }, // WebGL 1 & 2 - 8: { 4:true, 5:true } // WebGL 2 - }, - - // WebGL 2 Multiple Render Targets - - 'clearBufferfv': {3: { 0:true }, 4: { 0:true }}, - 'clearBufferiv': {3: { 0:true }, 4: { 0:true }}, - 'clearBufferuiv': {3: { 0:true }, 4: { 0:true }}, - 'clearBufferfi': {4: { 0:true }}, - - // WebGL 2 Query objects - - 'beginQuery': {2: { 0:true }}, - 'endQuery': {1: { 0:true }}, - 'getQuery': {2: { 0:true, 1:true }}, - 'getQueryParameter': {2: { 1:true }}, - - // WebGL 2 Sampler objects - - 'samplerParameteri': {3: { 1:true, 2:true }}, - 'samplerParameterf': {3: { 1:true }}, - 'getSamplerParameter': {2: { 1:true }}, - - // WebGL 2 Sync objects - - 'fenceSync': {2: { 0:true, 1: { 'enumBitwiseOr': [] } }}, - 'clientWaitSync': {3: { 1: { 'enumBitwiseOr': ['SYNC_FLUSH_COMMANDS_BIT'] } }}, - 'waitSync': {3: { 1: { 'enumBitwiseOr': [] } }}, - 'getSyncParameter': {2: { 1:true }}, - - // WebGL 2 Transform Feedback - - 'bindTransformFeedback': {2: { 0:true }}, - 'beginTransformFeedback': {1: { 0:true }}, - 'transformFeedbackVaryings': {3: { 2:true }}, - - // WebGL2 Uniform Buffer Objects and Transform Feedback Buffers - - 'bindBufferBase': {3: { 0:true }}, - 'bindBufferRange': {5: { 0:true }}, - 'getIndexedParameter': {2: { 0:true }}, - 'getActiveUniforms': {3: { 2:true }}, - 'getActiveUniformBlockParameter': {3: { 2:true }} -}; - -/** - * Map of numbers to names. - * @type {Object} - */ -var glEnums = null; - -/** - * Map of names to numbers. - * @type {Object} - */ -var enumStringToValue = null; - -/** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebGL context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ -function init(ctx) { - if (glEnums == null) { - glEnums = { }; - enumStringToValue = { }; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'number') { - glEnums[ctx[propertyName]] = propertyName; - enumStringToValue[propertyName] = ctx[propertyName]; - } - } - } -} - -/** - * Checks the utils have been initialized. - */ -function checkInit() { - if (glEnums == null) { - throw 'WebGLDebugUtils.init(ctx) not called'; - } -} - -/** - * Returns true or false if value matches any WebGL enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebGL defined enums - */ -function mightBeEnum(value) { - checkInit(); - return (glEnums[value] !== undefined); -} - -/** - * Gets an string version of an WebGL enum. - * - * Example: - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ -function glEnumToString(value) { - checkInit(); - var name = glEnums[value]; - return (name !== undefined) ? ("gl." + name) : - ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + ""); -} - -/** - * Returns the string version of a WebGL argument. - * Attempts to convert enum arguments to strings. - * @param {string} functionName the name of the WebGL function. - * @param {number} numArgs the number of arguments passed to the function. - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ -function glFunctionArgToString(functionName, numArgs, argumentIndex, value) { - var funcInfo = glValidEnumContexts[functionName]; - if (funcInfo !== undefined) { - var funcInfo = funcInfo[numArgs]; - if (funcInfo !== undefined) { - if (funcInfo[argumentIndex]) { - if (typeof funcInfo[argumentIndex] === 'object' && - funcInfo[argumentIndex]['enumBitwiseOr'] !== undefined) { - var enums = funcInfo[argumentIndex]['enumBitwiseOr']; - var orResult = 0; - var orEnums = []; - for (var i = 0; i < enums.length; ++i) { - var enumValue = enumStringToValue[enums[i]]; - if ((value & enumValue) !== 0) { - orResult |= enumValue; - orEnums.push(glEnumToString(enumValue)); - } - } - if (orResult === value) { - return orEnums.join(' | '); - } else { - return glEnumToString(value); - } - } else { - return glEnumToString(value); - } - } - } - } - if (value === null) { - return "null"; - } else if (value === undefined) { - return "undefined"; - } else if (ArrayBuffer.isView(value)) { - // Large typed array views are common in WebGL APIs and create - // huge strings in logs. - return "<" + value.constructor.name + ">"; - } else { - return value.toString(); - } -} - -/** - * Converts the arguments of a WebGL function to a string. - * Attempts to convert enum arguments to strings. - * - * @param {string} functionName the name of the WebGL function. - * @param {number} args The arguments. - * @return {string} The arguments as a string. - */ -function glFunctionArgsToString(functionName, args) { - // apparently we can't do args.join(","); - var argStr = ""; - var numArgs = args.length; - for (var ii = 0; ii < numArgs; ++ii) { - argStr += ((ii == 0) ? '' : ', ') + - glFunctionArgToString(functionName, numArgs, ii, args[ii]); - } - return argStr; -}; - - -function makePropertyWrapper(wrapper, original, propertyName) { - //log("wrap prop: " + propertyName); - wrapper.__defineGetter__(propertyName, function() { - return original[propertyName]; - }); - // TODO(gmane): this needs to handle properties that take more than - // one value? - wrapper.__defineSetter__(propertyName, function(value) { - //log("set: " + propertyName); - original[propertyName] = value; - }); -} - -// Makes a function that calls a function on another object. -function makeFunctionWrapper(original, functionName) { - //log("wrap fn: " + functionName); - var f = original[functionName]; - return function() { - //log("call: " + functionName); - var result = f.apply(original, arguments); - return result; - }; -} - -/** - * Given a WebGL context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not gl.NO_ERROR. - * - * @param {!WebGLRenderingContext} ctx The webgl context to - * wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc - * The function to call when gl.getError returns an - * error. If not specified the default function calls - * console.log with a message. - * @param {!function(funcName, args): void} opt_onFunc The - * function to call when each webgl function is called. - * You can use this to log all calls for example. - * @param {!WebGLRenderingContext} opt_err_ctx The webgl context - * to call getError on if different than ctx. - */ -function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc, opt_err_ctx) { - opt_err_ctx = opt_err_ctx || ctx; - init(ctx); - opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { - // apparently we can't do args.join(","); - var argStr = ""; - var numArgs = args.length; - for (var ii = 0; ii < numArgs; ++ii) { - argStr += ((ii == 0) ? '' : ', ') + - glFunctionArgToString(functionName, numArgs, ii, args[ii]); - } - error("WebGL error "+ glEnumToString(err) + " in "+ functionName + - "(" + argStr + ")"); - }; - - // Holds booleans for each GL error so after we get the error ourselves - // we can still return it to the client app. - var glErrorShadow = { }; - - // Makes a function that calls a WebGL function and then calls getError. - function makeErrorWrapper(ctx, functionName) { - return function() { - var result = ctx[functionName].apply(ctx, arguments); - var err = opt_err_ctx.getError(); - if (err != 0) { - glErrorShadow[err] = true; - opt_onErrorFunc(err, functionName, arguments); - } - if (opt_onFunc) { - opt_onFunc(functionName, arguments, result); - } - return result; - }; - } - - // Make a an object that has a copy of every property of the WebGL context - // but wraps all functions. - var wrapper = {}; - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - if (propertyName != 'getExtension') { - wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); - } else { - var wrapped = makeErrorWrapper(ctx, propertyName); - wrapper[propertyName] = function () { - var result = wrapped.apply(ctx, arguments); - if (!result) { - return null; - } - return makeDebugContext(result, opt_onErrorFunc, opt_onFunc, opt_err_ctx); - }; - } - } else { - makePropertyWrapper(wrapper, ctx, propertyName); - } - } - - // Override the getError function with one that returns our saved results. - wrapper.getError = function() { - for (var err in glErrorShadow) { - if (glErrorShadow.hasOwnProperty(err)) { - if (glErrorShadow[err]) { - glErrorShadow[err] = false; - return err; - } - } - } - return ctx.NO_ERROR; - }; - - return wrapper; -} - -function resetToInitialState(ctx) { - var isWebGL2RenderingContext = !!ctx.createTransformFeedback; - - if (isWebGL2RenderingContext) { - ctx.bindVertexArray(null); - } - - var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); - var tmp = ctx.createBuffer(); - ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp); - for (var ii = 0; ii < numAttribs; ++ii) { - ctx.disableVertexAttribArray(ii); - ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0); - ctx.vertexAttrib1f(ii, 0); - if (isWebGL2RenderingContext) { - ctx.vertexAttribDivisor(ii, 0); - } - } - ctx.deleteBuffer(tmp); - - var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); - for (var ii = 0; ii < numTextureUnits; ++ii) { - ctx.activeTexture(ctx.TEXTURE0 + ii); - ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null); - ctx.bindTexture(ctx.TEXTURE_2D, null); - if (isWebGL2RenderingContext) { - ctx.bindTexture(ctx.TEXTURE_2D_ARRAY, null); - ctx.bindTexture(ctx.TEXTURE_3D, null); - ctx.bindSampler(ii, null); - } - } - - ctx.activeTexture(ctx.TEXTURE0); - ctx.useProgram(null); - ctx.bindBuffer(ctx.ARRAY_BUFFER, null); - ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); - ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); - ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); - ctx.disable(ctx.BLEND); - ctx.disable(ctx.CULL_FACE); - ctx.disable(ctx.DEPTH_TEST); - ctx.disable(ctx.DITHER); - ctx.disable(ctx.SCISSOR_TEST); - ctx.blendColor(0, 0, 0, 0); - ctx.blendEquation(ctx.FUNC_ADD); - ctx.blendFunc(ctx.ONE, ctx.ZERO); - ctx.clearColor(0, 0, 0, 0); - ctx.clearDepth(1); - ctx.clearStencil(-1); - ctx.colorMask(true, true, true, true); - ctx.cullFace(ctx.BACK); - ctx.depthFunc(ctx.LESS); - ctx.depthMask(true); - ctx.depthRange(0, 1); - ctx.frontFace(ctx.CCW); - ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE); - ctx.lineWidth(1); - ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4); - ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false); - ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); - // TODO: Delete this IF. - if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) { - ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL); - } - ctx.polygonOffset(0, 0); - ctx.sampleCoverage(1, false); - ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height); - ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF); - ctx.stencilMask(0xFFFFFFFF); - ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP); - ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); - ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT); - - if (isWebGL2RenderingContext) { - ctx.drawBuffers([ctx.BACK]); - ctx.readBuffer(ctx.BACK); - ctx.bindBuffer(ctx.COPY_READ_BUFFER, null); - ctx.bindBuffer(ctx.COPY_WRITE_BUFFER, null); - ctx.bindBuffer(ctx.PIXEL_PACK_BUFFER, null); - ctx.bindBuffer(ctx.PIXEL_UNPACK_BUFFER, null); - var numTransformFeedbacks = ctx.getParameter(ctx.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS); - for (var ii = 0; ii < numTransformFeedbacks; ++ii) { - ctx.bindBufferBase(ctx.TRANSFORM_FEEDBACK_BUFFER, ii, null); - } - var numUBOs = ctx.getParameter(ctx.MAX_UNIFORM_BUFFER_BINDINGS); - for (var ii = 0; ii < numUBOs; ++ii) { - ctx.bindBufferBase(ctx.UNIFORM_BUFFER, ii, null); - } - ctx.disable(ctx.RASTERIZER_DISCARD); - ctx.pixelStorei(ctx.UNPACK_IMAGE_HEIGHT, 0); - ctx.pixelStorei(ctx.UNPACK_SKIP_IMAGES, 0); - ctx.pixelStorei(ctx.UNPACK_ROW_LENGTH, 0); - ctx.pixelStorei(ctx.UNPACK_SKIP_ROWS, 0); - ctx.pixelStorei(ctx.UNPACK_SKIP_PIXELS, 0); - ctx.pixelStorei(ctx.PACK_ROW_LENGTH, 0); - ctx.pixelStorei(ctx.PACK_SKIP_ROWS, 0); - ctx.pixelStorei(ctx.PACK_SKIP_PIXELS, 0); - ctx.hint(ctx.FRAGMENT_SHADER_DERIVATIVE_HINT, ctx.DONT_CARE); - } - - // TODO: This should NOT be needed but Firefox fails with 'hint' - while(ctx.getError()); -} - -function makeLostContextSimulatingCanvas(canvas) { - var unwrappedContext_; - var wrappedContext_; - var onLost_ = []; - var onRestored_ = []; - var wrappedContext_ = {}; - var contextId_ = 1; - var contextLost_ = false; - var resourceId_ = 0; - var resourceDb_ = []; - var numCallsToLoseContext_ = 0; - var numCalls_ = 0; - var canRestore_ = false; - var restoreTimeout_ = 0; - var isWebGL2RenderingContext; - - // Holds booleans for each GL error so can simulate errors. - var glErrorShadow_ = { }; - - canvas.getContext = function(f) { - return function() { - var ctx = f.apply(canvas, arguments); - // Did we get a context and is it a WebGL context? - if ((ctx instanceof WebGLRenderingContext) || (window.WebGL2RenderingContext && (ctx instanceof WebGL2RenderingContext))) { - if (ctx != unwrappedContext_) { - if (unwrappedContext_) { - throw "got different context" - } - isWebGL2RenderingContext = window.WebGL2RenderingContext && (ctx instanceof WebGL2RenderingContext); - unwrappedContext_ = ctx; - wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_); - } - return wrappedContext_; - } - return ctx; - } - }(canvas.getContext); - - function wrapEvent(listener) { - if (typeof(listener) == "function") { - return listener; - } else { - return function(info) { - listener.handleEvent(info); - } - } - } - - var addOnContextLostListener = function(listener) { - onLost_.push(wrapEvent(listener)); - }; - - var addOnContextRestoredListener = function(listener) { - onRestored_.push(wrapEvent(listener)); - }; - - - function wrapAddEventListener(canvas) { - var f = canvas.addEventListener; - canvas.addEventListener = function(type, listener, bubble) { - switch (type) { - case 'webglcontextlost': - addOnContextLostListener(listener); - break; - case 'webglcontextrestored': - addOnContextRestoredListener(listener); - break; - default: - f.apply(canvas, arguments); - } - }; - } - - wrapAddEventListener(canvas); - - canvas.loseContext = function() { - if (!contextLost_) { - contextLost_ = true; - numCallsToLoseContext_ = 0; - ++contextId_; - while (unwrappedContext_.getError()); - clearErrors(); - glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true; - var event = makeWebGLContextEvent("context lost"); - var callbacks = onLost_.slice(); - setTimeout(function() { - //log("numCallbacks:" + callbacks.length); - for (var ii = 0; ii < callbacks.length; ++ii) { - //log("calling callback:" + ii); - callbacks[ii](event); - } - if (restoreTimeout_ >= 0) { - setTimeout(function() { - canvas.restoreContext(); - }, restoreTimeout_); - } - }, 0); - } - }; - - canvas.restoreContext = function() { - if (contextLost_) { - if (onRestored_.length) { - setTimeout(function() { - if (!canRestore_) { - throw "can not restore. webglcontestlost listener did not call event.preventDefault"; - } - freeResources(); - resetToInitialState(unwrappedContext_); - contextLost_ = false; - numCalls_ = 0; - canRestore_ = false; - var callbacks = onRestored_.slice(); - var event = makeWebGLContextEvent("context restored"); - for (var ii = 0; ii < callbacks.length; ++ii) { - callbacks[ii](event); - } - }, 0); - } - } - }; - - canvas.loseContextInNCalls = function(numCalls) { - if (contextLost_) { - throw "You can not ask a lost contet to be lost"; - } - numCallsToLoseContext_ = numCalls_ + numCalls; - }; - - canvas.getNumCalls = function() { - return numCalls_; - }; - - canvas.setRestoreTimeout = function(timeout) { - restoreTimeout_ = timeout; - }; - - function isWebGLObject(obj) { - //return false; - return (obj instanceof WebGLBuffer || - obj instanceof WebGLFramebuffer || - obj instanceof WebGLProgram || - obj instanceof WebGLRenderbuffer || - obj instanceof WebGLShader || - obj instanceof WebGLTexture); - } - - function checkResources(args) { - for (var ii = 0; ii < args.length; ++ii) { - var arg = args[ii]; - if (isWebGLObject(arg)) { - return arg.__webglDebugContextLostId__ == contextId_; - } - } - return true; - } - - function clearErrors() { - var k = Object.keys(glErrorShadow_); - for (var ii = 0; ii < k.length; ++ii) { - delete glErrorShadow_[k[ii]]; - } - } - - function loseContextIfTime() { - ++numCalls_; - if (!contextLost_) { - if (numCallsToLoseContext_ == numCalls_) { - canvas.loseContext(); - } - } - } - - // Makes a function that simulates WebGL when out of context. - function makeLostContextFunctionWrapper(ctx, functionName) { - var f = ctx[functionName]; - return function() { - // log("calling:" + functionName); - // Only call the functions if the context is not lost. - loseContextIfTime(); - if (!contextLost_) { - //if (!checkResources(arguments)) { - // glErrorShadow_[wrappedContext_.INVALID_OPERATION] = true; - // return; - //} - var result = f.apply(ctx, arguments); - return result; - } - }; - } - - function freeResources() { - for (var ii = 0; ii < resourceDb_.length; ++ii) { - var resource = resourceDb_[ii]; - if (resource instanceof WebGLBuffer) { - unwrappedContext_.deleteBuffer(resource); - } else if (resource instanceof WebGLFramebuffer) { - unwrappedContext_.deleteFramebuffer(resource); - } else if (resource instanceof WebGLProgram) { - unwrappedContext_.deleteProgram(resource); - } else if (resource instanceof WebGLRenderbuffer) { - unwrappedContext_.deleteRenderbuffer(resource); - } else if (resource instanceof WebGLShader) { - unwrappedContext_.deleteShader(resource); - } else if (resource instanceof WebGLTexture) { - unwrappedContext_.deleteTexture(resource); - } - else if (isWebGL2RenderingContext) { - if (resource instanceof WebGLQuery) { - unwrappedContext_.deleteQuery(resource); - } else if (resource instanceof WebGLSampler) { - unwrappedContext_.deleteSampler(resource); - } else if (resource instanceof WebGLSync) { - unwrappedContext_.deleteSync(resource); - } else if (resource instanceof WebGLTransformFeedback) { - unwrappedContext_.deleteTransformFeedback(resource); - } else if (resource instanceof WebGLVertexArrayObject) { - unwrappedContext_.deleteVertexArray(resource); - } - } - } - } - - function makeWebGLContextEvent(statusMessage) { - return { - statusMessage: statusMessage, - preventDefault: function() { - canRestore_ = true; - } - }; - } - - return canvas; - - function makeLostContextSimulatingContext(ctx) { - // copy all functions and properties to wrapper - for (var propertyName in ctx) { - if (typeof ctx[propertyName] == 'function') { - wrappedContext_[propertyName] = makeLostContextFunctionWrapper( - ctx, propertyName); - } else { - makePropertyWrapper(wrappedContext_, ctx, propertyName); - } - } - - // Wrap a few functions specially. - wrappedContext_.getError = function() { - loseContextIfTime(); - if (!contextLost_) { - var err; - while (err = unwrappedContext_.getError()) { - glErrorShadow_[err] = true; - } - } - for (var err in glErrorShadow_) { - if (glErrorShadow_[err]) { - delete glErrorShadow_[err]; - return err; - } - } - return wrappedContext_.NO_ERROR; - }; - - var creationFunctions = [ - "createBuffer", - "createFramebuffer", - "createProgram", - "createRenderbuffer", - "createShader", - "createTexture" - ]; - if (isWebGL2RenderingContext) { - creationFunctions.push( - "createQuery", - "createSampler", - "fenceSync", - "createTransformFeedback", - "createVertexArray" - ); - } - for (var ii = 0; ii < creationFunctions.length; ++ii) { - var functionName = creationFunctions[ii]; - wrappedContext_[functionName] = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return null; - } - var obj = f.apply(ctx, arguments); - obj.__webglDebugContextLostId__ = contextId_; - resourceDb_.push(obj); - return obj; - }; - }(ctx[functionName]); - } - - var functionsThatShouldReturnNull = [ - "getActiveAttrib", - "getActiveUniform", - "getBufferParameter", - "getContextAttributes", - "getAttachedShaders", - "getFramebufferAttachmentParameter", - "getParameter", - "getProgramParameter", - "getProgramInfoLog", - "getRenderbufferParameter", - "getShaderParameter", - "getShaderInfoLog", - "getShaderSource", - "getTexParameter", - "getUniform", - "getUniformLocation", - "getVertexAttrib" - ]; - if (isWebGL2RenderingContext) { - functionsThatShouldReturnNull.push( - "getInternalformatParameter", - "getQuery", - "getQueryParameter", - "getSamplerParameter", - "getSyncParameter", - "getTransformFeedbackVarying", - "getIndexedParameter", - "getUniformIndices", - "getActiveUniforms", - "getActiveUniformBlockParameter", - "getActiveUniformBlockName" - ); - } - for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) { - var functionName = functionsThatShouldReturnNull[ii]; - wrappedContext_[functionName] = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return null; - } - return f.apply(ctx, arguments); - } - }(wrappedContext_[functionName]); - } - - var isFunctions = [ - "isBuffer", - "isEnabled", - "isFramebuffer", - "isProgram", - "isRenderbuffer", - "isShader", - "isTexture" - ]; - if (isWebGL2RenderingContext) { - isFunctions.push( - "isQuery", - "isSampler", - "isSync", - "isTransformFeedback", - "isVertexArray" - ); - } - for (var ii = 0; ii < isFunctions.length; ++ii) { - var functionName = isFunctions[ii]; - wrappedContext_[functionName] = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return false; - } - return f.apply(ctx, arguments); - } - }(wrappedContext_[functionName]); - } - - wrappedContext_.checkFramebufferStatus = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return wrappedContext_.FRAMEBUFFER_UNSUPPORTED; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.checkFramebufferStatus); - - wrappedContext_.getAttribLocation = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return -1; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.getAttribLocation); - - wrappedContext_.getVertexAttribOffset = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return 0; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.getVertexAttribOffset); - - wrappedContext_.isContextLost = function() { - return contextLost_; - }; - - if (isWebGL2RenderingContext) { - wrappedContext_.getFragDataLocation = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return -1; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.getFragDataLocation); - - wrappedContext_.clientWaitSync = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return wrappedContext_.WAIT_FAILED; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.clientWaitSync); - - wrappedContext_.getUniformBlockIndex = function(f) { - return function() { - loseContextIfTime(); - if (contextLost_) { - return wrappedContext_.INVALID_INDEX; - } - return f.apply(ctx, arguments); - }; - }(wrappedContext_.getUniformBlockIndex); - } - - return wrappedContext_; - } -} - -return { - /** - * Initializes this module. Safe to call more than once. - * @param {!WebGLRenderingContext} ctx A WebGL context. If - * you have more than one context it doesn't matter which one - * you pass in, it is only used to pull out constants. - */ - 'init': init, - - /** - * Returns true or false if value matches any WebGL enum - * @param {*} value Value to check if it might be an enum. - * @return {boolean} True if value matches one of the WebGL defined enums - */ - 'mightBeEnum': mightBeEnum, - - /** - * Gets an string version of an WebGL enum. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); - * - * @param {number} value Value to return an enum for - * @return {string} The string version of the enum. - */ - 'glEnumToString': glEnumToString, - - /** - * Converts the argument of a WebGL function to a string. - * Attempts to convert enum arguments to strings. - * - * Example: - * WebGLDebugUtil.init(ctx); - * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 2, 0, gl.TEXTURE_2D); - * - * would return 'TEXTURE_2D' - * - * @param {string} functionName the name of the WebGL function. - * @param {number} numArgs The number of arguments - * @param {number} argumentIndx the index of the argument. - * @param {*} value The value of the argument. - * @return {string} The value as a string. - */ - 'glFunctionArgToString': glFunctionArgToString, - - /** - * Converts the arguments of a WebGL function to a string. - * Attempts to convert enum arguments to strings. - * - * @param {string} functionName the name of the WebGL function. - * @param {number} args The arguments. - * @return {string} The arguments as a string. - */ - 'glFunctionArgsToString': glFunctionArgsToString, - - /** - * Given a WebGL context returns a wrapped context that calls - * gl.getError after every command and calls a function if the - * result is not NO_ERROR. - * - * You can supply your own function if you want. For example, if you'd like - * an exception thrown on any GL error you could do this - * - * function throwOnGLError(err, funcName, args) { - * throw WebGLDebugUtils.glEnumToString(err) + - * " was caused by call to " + funcName; - * }; - * - * ctx = WebGLDebugUtils.makeDebugContext( - * canvas.getContext("webgl"), throwOnGLError); - * - * @param {!WebGLRenderingContext} ctx The webgl context to wrap. - * @param {!function(err, funcName, args): void} opt_onErrorFunc The function - * to call when gl.getError returns an error. If not specified the default - * function calls console.log with a message. - * @param {!function(funcName, args): void} opt_onFunc The - * function to call when each webgl function is called. You - * can use this to log all calls for example. - */ - 'makeDebugContext': makeDebugContext, - - /** - * Given a canvas element returns a wrapped canvas element that will - * simulate lost context. The canvas returned adds the following functions. - * - * loseContext: - * simulates a lost context event. - * - * restoreContext: - * simulates the context being restored. - * - * lostContextInNCalls: - * loses the context after N gl calls. - * - * getNumCalls: - * tells you how many gl calls there have been so far. - * - * setRestoreTimeout: - * sets the number of milliseconds until the context is restored - * after it has been lost. Defaults to 0. Pass -1 to prevent - * automatic restoring. - * - * @param {!Canvas} canvas The canvas element to wrap. - */ - 'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas, - - /** - * Resets a context to the initial state. - * @param {!WebGLRenderingContext} ctx The webgl context to - * reset. - */ - 'resetToInitialState': resetToInitialState -}; - -}(); -