UNPKG

@plotly/regl

Version:

regl is a fast functional WebGL framework.

1,988 lines (1,688 loc) 252 kB
(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 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 } 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 } } 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() } return input } function getElement (desc) { if (typeof desc === 'string') { 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 cachedCode = {} var onDone = function (err) { if (err) { } } var onDestroy = function () {} if (typeof args === 'string') { element = document.querySelector(args) } else if (typeof args === 'object') { if (isHTMLElement(args)) { element = args } else if (isWebGLContext(args)) { gl = args canvas = gl.canvas } else { 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 } if ('extensions' in args) { extensions = parseExtensions(args.extensions) } if ('optionalExtensions' in args) { optionalExtensions = parseExtensions(args.optionalExtensions) } if ('onDone' in args) { onDone = args.onDone } if ('profile' in args) { profile = !!args.profile } if ('pixelRatio' in args) { pixelRatio = +args.pixelRatio } if ('cachedCode' in args) { cachedCode = args.cachedCode } } } else { } if (element) { if (element.nodeName.toLowerCase() === 'canvas') { canvas = element } else { container = element } } if (!gl) { if (!canvas) { 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, cachedCode: cachedCode, onDone: onDone, onDestroy: onDestroy } } function createExtensionCache (gl, config) { var extensions = {} function tryLoadExtension (name_) { 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 = 5120 var GL_UNSIGNED_BYTE$1 = 5121 var GL_SHORT = 5122 var GL_UNSIGNED_SHORT = 5123 var GL_INT = 5124 var GL_UNSIGNED_INT = 5125 var GL_FLOAT$1 = 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: result = new Int8Array(alloc(n), 0, n) break case GL_UNSIGNED_BYTE$1: result = new Uint8Array(alloc(n), 0, n) break case GL_SHORT: result = new Int16Array(alloc(2 * n), 0, n) break case GL_UNSIGNED_SHORT: result = new Uint16Array(alloc(2 * n), 0, n) break case GL_INT: result = new Int32Array(alloc(4 * n), 0, n) break case GL_UNSIGNED_INT: result = new Uint32Array(alloc(4 * n), 0, n) break case GL_FLOAT$1: 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 = 0x1406 var GL_UNSIGNED_BYTE = 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, 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, 4) gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, 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, 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, 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 } } 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 ) } 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$2 = 5121 var GL_FLOAT$2 = 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$2 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$2 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$2 flatData = arrayFlatten( data, [data.length, data[0].length], buffer.dtype) initBufferFromTypedArray(buffer, flatData, usage) if (persist) { buffer.persistentData = flatData } else { pool.freeType(flatData) } } else { } } } 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 { } buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$2 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$2 buffer.dimension = dimension initBufferFromTypedArray(buffer, data, usage) if (persist) { buffer.persistentData = new Uint8Array(new Uint8Array(data)) } } else { } } function destroy (buffer) { stats.bufferCount-- // remove attribute link destroyBuffer(buffer) var handle = buffer.buffer 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) { if ('data' in options) { data = options.data } if ('usage' in options) { usage = usageTypes[options.usage] } if ('type' in options) { dtype = glTypes[options.type] } if ('dimension' in options) { dimension = options.dimension | 0 } if ('length' in options) { byteLength = options.length | 0 } } buffer.bind() if (!data) { // #475 if (byteLength) gl.bufferData(buffer.type, byteLength, usage) buffer.dtype = dtype || GL_UNSIGNED_BYTE$2 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) { 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 { } } } 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 { } 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 { } 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$1 = 5120 var GL_UNSIGNED_BYTE$3 = 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_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$3, 'uint16': GL_UNSIGNED_SHORT$1 } if (extensions.oes_element_index_uint) { elementTypes.uint32 = GL_UNSIGNED_INT$1 } 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$1 : GL_UNSIGNED_SHORT$1 } bufferState._initBuffer( elements.buffer, data, usage, predictedType, 3) } else { gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage) elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$3 elements.buffer.usage = usage elements.buffer.dimension = 3 elements.buffer.byteLength = byteLength } dtype = type if (!type) { switch (elements.buffer.dtype) { case GL_UNSIGNED_BYTE$3: case GL_BYTE$1: dtype = GL_UNSIGNED_BYTE$3 break case GL_UNSIGNED_SHORT$1: case GL_SHORT$1: dtype = GL_UNSIGNED_SHORT$1 break case GL_UNSIGNED_INT$1: case GL_INT$1: dtype = GL_UNSIGNED_INT$1 break default: } elements.buffer.dtype = dtype } elements.type = dtype // Check oes_element_index_uint extension // try to guess default primitive type and arguments var vertCount = count if (vertCount < 0) { vertCount = elements.buffer.byteLength if (dtype === GL_UNSIGNED_SHORT$1) { vertCount >>= 1 } else if (dtype === GL_UNSIGNED_INT$1) { 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-- 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$3 } else if (typeof options === 'number') { buffer(options) elements.primType = GL_TRIANGLES elements.vertCount = options | 0 elements.type = GL_UNSIGNED_BYTE$3 } 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 { if ('data' in options) { data = options.data } if ('usage' in options) { usage = usageTypes[options.usage] } if ('primitive' in options) { primType = primTypes[options.primitive] } if ('count' in options) { vertCount = options.count | 0 } if ('type' in options) { dtype = elementTypes[options.type] } if ('length' in options) { byteLength = options.length | 0 } else { byteLength = vertCount if (dtype === GL_UNSIGNED_SHORT$1 || dtype === GL_SHORT$1) { byteLength *= 2 } else if (dtype === GL_UNSIGNED_INT$1 || dtype === GL_INT$1) { 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$3 = 5123 function convertToHalfFloat (array) { var ushorts = pool.allocType(GL_UNSIGNED_SHORT$3, 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 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 = 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_DEPTH_COMPONENT = 0x1902 var GL_DEPTH_STENCIL = 0x84F9 var GL_SRGB_EXT = 0x8C40 var GL_SRGB_ALPHA_EXT = 0x8C42 var GL_HALF_FLOAT_OES = 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$4 = 0x1401 var GL_UNSIGNED_SHORT$2 = 0x1403 var GL_UNSIGNED_INT$2 = 0x1405 var GL_FLOAT$3 = 0x1406 var GL_TEXTURE_WRAP_S = 0x2802 var GL_TEXTURE_WRAP_T = 0x2803 var GL_REPEAT = 0x2901 var GL_CLAMP_TO_EDGE = 0x812F var GL_MIRRORED_REPEAT = 0x8370 var GL_TEXTURE_MAG_FILTER = 0x2800 var GL_TEXTURE_MIN_FILTER = 0x2801 var GL_NEAREST = 0x2600 var GL_LINEAR = 0x2601 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_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, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR ] 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$4] = 1 TYPE_SIZES[GL_FLOAT$3] = 4 TYPE_SIZES[GL_HALF_FLOAT_OES] = 2 TYPE_SIZES[GL_UNSIGNED_SHORT$2] = 2 TYPE_SIZES[GL_UNSIGNED_INT$2] = 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$4: case GL_UNSIGNED_SHORT$2: case GL_UNSIGNED_INT$2: case GL_FLOAT$3: var converted = pool.allocType(result.type, n) converted.set(data) result.data = converted break case GL_HALF_FLOAT_OES: result.data = convertToHalfFloat(data) break default: } } function preConvert (image, n) { return pool.allocType( image.type === GL_HALF_FLOAT_OES ? GL_FLOAT$3 : image.type, n) } function postConvert (image, data) { if (image.type === GL_HALF_FLOAT_OES) { 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, 'mirror': GL_MIRRORED_REPEAT } var magFilters = { 'nearest': GL_NEAREST, 'linear': GL_LINEAR } var minFilters = extend({ 'mipmap': GL_LINEAR_MIPMAP_LINEAR, 'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST, 'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST, 'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR, 'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR }, magFilters) var colorSpace = { 'none': 0, 'browser': GL_BROWSER_DEFAULT_WEBGL } var textureTypes = { 'uint8': GL_UNSIGNED_BYTE$4, 'rgba4': GL_UNSIGNED_SHORT_4_4_4_4, 'rgb565': GL_UNSIGNED_SHORT_5_6_5, 'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_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$3 } if (extensions.oes_texture_half_float) { textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES } if (extensions.webgl_depth_texture) { extend(textureFormats, { 'depth': GL_DEPTH_COMPONENT, 'depth stencil': GL_DEPTH_STENCIL }) extend(textureTypes, { 'uint16': GL_UNSIGNED_SHORT$2, 'uint32': GL_UNSIGNED_INT$2, 'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL }) } 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] textureTyp