@plotly/regl
Version:
regl is a fast functional WebGL framework.
1,860 lines (1,644 loc) • 313 kB
JavaScript
(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',
'cachedCode'
]
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 cachedCode = {}
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')
}
if ('cachedCode' in args) {
check$1.type(
args.cachedCode, 'object',
'invalid cachedCode')
cachedCode = args.cachedCode
}
}
} 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,
cachedCode: cachedCode,
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: crea