UNPKG

228 kBJavaScriptView Raw
1(function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 typeof define === 'function' && define.amd ? define(factory) :
4 (global.createREGL = factory());
5}(this, (function () { 'use strict';
6
7var extend = function (base, opts) {
8 var keys = Object.keys(opts)
9 for (var i = 0; i < keys.length; ++i) {
10 base[keys[i]] = opts[keys[i]]
11 }
12 return base
13}
14
15var VARIABLE_COUNTER = 0
16
17var DYN_FUNC = 0
18
19function DynamicVariable (type, data) {
20 this.id = (VARIABLE_COUNTER++)
21 this.type = type
22 this.data = data
23}
24
25function escapeStr (str) {
26 return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
27}
28
29function splitParts (str) {
30 if (str.length === 0) {
31 return []
32 }
33
34 var firstChar = str.charAt(0)
35 var lastChar = str.charAt(str.length - 1)
36
37 if (str.length > 1 &&
38 firstChar === lastChar &&
39 (firstChar === '"' || firstChar === "'")) {
40 return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"']
41 }
42
43 var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str)
44 if (parts) {
45 return (
46 splitParts(str.substr(0, parts.index))
47 .concat(splitParts(parts[1]))
48 .concat(splitParts(str.substr(parts.index + parts[0].length)))
49 )
50 }
51
52 var subparts = str.split('.')
53 if (subparts.length === 1) {
54 return ['"' + escapeStr(str) + '"']
55 }
56
57 var result = []
58 for (var i = 0; i < subparts.length; ++i) {
59 result = result.concat(splitParts(subparts[i]))
60 }
61 return result
62}
63
64function toAccessorString (str) {
65 return '[' + splitParts(str).join('][') + ']'
66}
67
68function defineDynamic (type, data) {
69 return new DynamicVariable(type, toAccessorString(data + ''))
70}
71
72function isDynamic (x) {
73 return (typeof x === 'function' && !x._reglType) ||
74 x instanceof DynamicVariable
75}
76
77function unbox (x, path) {
78 if (typeof x === 'function') {
79 return new DynamicVariable(DYN_FUNC, x)
80 }
81 return x
82}
83
84var dynamic = {
85 DynamicVariable: DynamicVariable,
86 define: defineDynamic,
87 isDynamic: isDynamic,
88 unbox: unbox,
89 accessor: toAccessorString
90};
91
92/* globals requestAnimationFrame, cancelAnimationFrame */
93var raf = {
94 next: typeof requestAnimationFrame === 'function'
95 ? function (cb) { return requestAnimationFrame(cb) }
96 : function (cb) { return setTimeout(cb, 16) },
97 cancel: typeof cancelAnimationFrame === 'function'
98 ? function (raf) { return cancelAnimationFrame(raf) }
99 : clearTimeout
100};
101
102/* globals performance */
103var clock = (typeof performance !== 'undefined' && performance.now)
104 ? function () { return performance.now() }
105 : function () { return +(new Date()) };
106
107function createStringStore () {
108 var stringIds = { '': 0 }
109 var stringValues = ['']
110 return {
111 id: function (str) {
112 var result = stringIds[str]
113 if (result) {
114 return result
115 }
116 result = stringIds[str] = stringValues.length
117 stringValues.push(str)
118 return result
119 },
120
121 str: function (id) {
122 return stringValues[id]
123 }
124 }
125}
126
127// Context and canvas creation helper functions
128
129function createCanvas (element, onDone, pixelRatio) {
130 var canvas = document.createElement('canvas')
131 extend(canvas.style, {
132 border: 0,
133 margin: 0,
134 padding: 0,
135 top: 0,
136 left: 0
137 })
138 element.appendChild(canvas)
139
140 if (element === document.body) {
141 canvas.style.position = 'absolute'
142 extend(element.style, {
143 margin: 0,
144 padding: 0
145 })
146 }
147
148 function resize () {
149 var w = window.innerWidth
150 var h = window.innerHeight
151 if (element !== document.body) {
152 var bounds = element.getBoundingClientRect()
153 w = bounds.right - bounds.left
154 h = bounds.bottom - bounds.top
155 }
156 canvas.width = pixelRatio * w
157 canvas.height = pixelRatio * h
158 extend(canvas.style, {
159 width: w + 'px',
160 height: h + 'px'
161 })
162 }
163
164 window.addEventListener('resize', resize, false)
165
166 function onDestroy () {
167 window.removeEventListener('resize', resize)
168 element.removeChild(canvas)
169 }
170
171 resize()
172
173 return {
174 canvas: canvas,
175 onDestroy: onDestroy
176 }
177}
178
179function createContext (canvas, contextAttributes) {
180 function get (name) {
181 try {
182 return canvas.getContext(name, contextAttributes)
183 } catch (e) {
184 return null
185 }
186 }
187 return (
188 get('webgl') ||
189 get('experimental-webgl') ||
190 get('webgl-experimental')
191 )
192}
193
194function isHTMLElement (obj) {
195 return (
196 typeof obj.nodeName === 'string' &&
197 typeof obj.appendChild === 'function' &&
198 typeof obj.getBoundingClientRect === 'function'
199 )
200}
201
202function isWebGLContext (obj) {
203 return (
204 typeof obj.drawArrays === 'function' ||
205 typeof obj.drawElements === 'function'
206 )
207}
208
209function parseExtensions (input) {
210 if (typeof input === 'string') {
211 return input.split()
212 }
213
214 return input
215}
216
217function getElement (desc) {
218 if (typeof desc === 'string') {
219
220 return document.querySelector(desc)
221 }
222 return desc
223}
224
225function parseArgs (args_) {
226 var args = args_ || {}
227 var element, container, canvas, gl
228 var contextAttributes = {}
229 var extensions = []
230 var optionalExtensions = []
231 var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio)
232 var profile = false
233 var onDone = function (err) {
234 if (err) {
235
236 }
237 }
238 var onDestroy = function () {}
239 if (typeof args === 'string') {
240
241 element = document.querySelector(args)
242
243 } else if (typeof args === 'object') {
244 if (isHTMLElement(args)) {
245 element = args
246 } else if (isWebGLContext(args)) {
247 gl = args
248 canvas = gl.canvas
249 } else {
250
251 if ('gl' in args) {
252 gl = args.gl
253 } else if ('canvas' in args) {
254 canvas = getElement(args.canvas)
255 } else if ('container' in args) {
256 container = getElement(args.container)
257 }
258 if ('attributes' in args) {
259 contextAttributes = args.attributes
260
261 }
262 if ('extensions' in args) {
263 extensions = parseExtensions(args.extensions)
264 }
265 if ('optionalExtensions' in args) {
266 optionalExtensions = parseExtensions(args.optionalExtensions)
267 }
268 if ('onDone' in args) {
269
270 onDone = args.onDone
271 }
272 if ('profile' in args) {
273 profile = !!args.profile
274 }
275 if ('pixelRatio' in args) {
276 pixelRatio = +args.pixelRatio
277
278 }
279 }
280 } else {
281
282 }
283
284 if (element) {
285 if (element.nodeName.toLowerCase() === 'canvas') {
286 canvas = element
287 } else {
288 container = element
289 }
290 }
291
292 if (!gl) {
293 if (!canvas) {
294
295 var result = createCanvas(container || document.body, onDone, pixelRatio)
296 if (!result) {
297 return null
298 }
299 canvas = result.canvas
300 onDestroy = result.onDestroy
301 }
302 // workaround for chromium bug, premultiplied alpha value is platform dependent
303 contextAttributes.premultipliedAlpha = contextAttributes.premultipliedAlpha || false
304 gl = createContext(canvas, contextAttributes)
305 }
306
307 if (!gl) {
308 onDestroy()
309 onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org')
310 return null
311 }
312
313 return {
314 gl: gl,
315 canvas: canvas,
316 container: container,
317 extensions: extensions,
318 optionalExtensions: optionalExtensions,
319 pixelRatio: pixelRatio,
320 profile: profile,
321 onDone: onDone,
322 onDestroy: onDestroy
323 }
324}
325
326function createExtensionCache (gl, config) {
327 var extensions = {}
328
329 function tryLoadExtension (name_) {
330
331 var name = name_.toLowerCase()
332 var ext
333 try {
334 ext = extensions[name] = gl.getExtension(name)
335 } catch (e) {}
336 return !!ext
337 }
338
339 for (var i = 0; i < config.extensions.length; ++i) {
340 var name = config.extensions[i]
341 if (!tryLoadExtension(name)) {
342 config.onDestroy()
343 config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser')
344 return null
345 }
346 }
347
348 config.optionalExtensions.forEach(tryLoadExtension)
349
350 return {
351 extensions: extensions,
352 restore: function () {
353 Object.keys(extensions).forEach(function (name) {
354 if (extensions[name] && !tryLoadExtension(name)) {
355 throw new Error('(regl): error restoring extension ' + name)
356 }
357 })
358 }
359 }
360}
361
362function loop (n, f) {
363 var result = Array(n)
364 for (var i = 0; i < n; ++i) {
365 result[i] = f(i)
366 }
367 return result
368}
369
370var GL_BYTE = 5120
371var GL_UNSIGNED_BYTE$1 = 5121
372var GL_SHORT = 5122
373var GL_UNSIGNED_SHORT = 5123
374var GL_INT = 5124
375var GL_UNSIGNED_INT = 5125
376var GL_FLOAT$1 = 5126
377
378function nextPow16 (v) {
379 for (var i = 16; i <= (1 << 28); i *= 16) {
380 if (v <= i) {
381 return i
382 }
383 }
384 return 0
385}
386
387function log2 (v) {
388 var r, shift
389 r = (v > 0xFFFF) << 4
390 v >>>= r
391 shift = (v > 0xFF) << 3
392 v >>>= shift; r |= shift
393 shift = (v > 0xF) << 2
394 v >>>= shift; r |= shift
395 shift = (v > 0x3) << 1
396 v >>>= shift; r |= shift
397 return r | (v >> 1)
398}
399
400function createPool () {
401 var bufferPool = loop(8, function () {
402 return []
403 })
404
405 function alloc (n) {
406 var sz = nextPow16(n)
407 var bin = bufferPool[log2(sz) >> 2]
408 if (bin.length > 0) {
409 return bin.pop()
410 }
411 return new ArrayBuffer(sz)
412 }
413
414 function free (buf) {
415 bufferPool[log2(buf.byteLength) >> 2].push(buf)
416 }
417
418 function allocType (type, n) {
419 var result = null
420 switch (type) {
421 case GL_BYTE:
422 result = new Int8Array(alloc(n), 0, n)
423 break
424 case GL_UNSIGNED_BYTE$1:
425 result = new Uint8Array(alloc(n), 0, n)
426 break
427 case GL_SHORT:
428 result = new Int16Array(alloc(2 * n), 0, n)
429 break
430 case GL_UNSIGNED_SHORT:
431 result = new Uint16Array(alloc(2 * n), 0, n)
432 break
433 case GL_INT:
434 result = new Int32Array(alloc(4 * n), 0, n)
435 break
436 case GL_UNSIGNED_INT:
437 result = new Uint32Array(alloc(4 * n), 0, n)
438 break
439 case GL_FLOAT$1:
440 result = new Float32Array(alloc(4 * n), 0, n)
441 break
442 default:
443 return null
444 }
445 if (result.length !== n) {
446 return result.subarray(0, n)
447 }
448 return result
449 }
450
451 function freeType (array) {
452 free(array.buffer)
453 }
454
455 return {
456 alloc: alloc,
457 free: free,
458 allocType: allocType,
459 freeType: freeType
460 }
461}
462
463var pool = createPool()
464
465// zero pool for initial zero data
466pool.zero = createPool()
467
468var GL_SUBPIXEL_BITS = 0x0D50
469var GL_RED_BITS = 0x0D52
470var GL_GREEN_BITS = 0x0D53
471var GL_BLUE_BITS = 0x0D54
472var GL_ALPHA_BITS = 0x0D55
473var GL_DEPTH_BITS = 0x0D56
474var GL_STENCIL_BITS = 0x0D57
475
476var GL_ALIASED_POINT_SIZE_RANGE = 0x846D
477var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E
478
479var GL_MAX_TEXTURE_SIZE = 0x0D33
480var GL_MAX_VIEWPORT_DIMS = 0x0D3A
481var GL_MAX_VERTEX_ATTRIBS = 0x8869
482var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB
483var GL_MAX_VARYING_VECTORS = 0x8DFC
484var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D
485var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C
486var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872
487var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD
488var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C
489var GL_MAX_RENDERBUFFER_SIZE = 0x84E8
490
491var GL_VENDOR = 0x1F00
492var GL_RENDERER = 0x1F01
493var GL_VERSION = 0x1F02
494var GL_SHADING_LANGUAGE_VERSION = 0x8B8C
495
496var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF
497
498var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF
499var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824
500
501var GL_TEXTURE_2D = 0x0DE1
502var GL_TEXTURE_CUBE_MAP = 0x8513
503var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515
504var GL_TEXTURE0 = 0x84C0
505var GL_RGBA = 0x1908
506var GL_FLOAT = 0x1406
507var GL_UNSIGNED_BYTE = 0x1401
508var GL_FRAMEBUFFER = 0x8D40
509var GL_FRAMEBUFFER_COMPLETE = 0x8CD5
510var GL_COLOR_ATTACHMENT0 = 0x8CE0
511var GL_COLOR_BUFFER_BIT$1 = 0x4000
512
513var wrapLimits = function (gl, extensions) {
514 var maxAnisotropic = 1
515 if (extensions.ext_texture_filter_anisotropic) {
516 maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)
517 }
518
519 var maxDrawbuffers = 1
520 var maxColorAttachments = 1
521 if (extensions.webgl_draw_buffers) {
522 maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL)
523 maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL)
524 }
525
526 // detect if reading float textures is available (Safari doesn't support)
527 var readFloat = !!extensions.oes_texture_float
528 if (readFloat) {
529 var readFloatTexture = gl.createTexture()
530 gl.bindTexture(GL_TEXTURE_2D, readFloatTexture)
531 gl.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_FLOAT, null)
532
533 var fbo = gl.createFramebuffer()
534 gl.bindFramebuffer(GL_FRAMEBUFFER, fbo)
535 gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, readFloatTexture, 0)
536 gl.bindTexture(GL_TEXTURE_2D, null)
537
538 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) !== GL_FRAMEBUFFER_COMPLETE) readFloat = false
539
540 else {
541 gl.viewport(0, 0, 1, 1)
542 gl.clearColor(1.0, 0.0, 0.0, 1.0)
543 gl.clear(GL_COLOR_BUFFER_BIT$1)
544 var pixels = pool.allocType(GL_FLOAT, 4)
545 gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixels)
546
547 if (gl.getError()) readFloat = false
548 else {
549 gl.deleteFramebuffer(fbo)
550 gl.deleteTexture(readFloatTexture)
551
552 readFloat = pixels[0] === 1.0
553 }
554
555 pool.freeType(pixels)
556 }
557 }
558
559 // detect non power of two cube textures support (IE doesn't support)
560 var isIE = typeof navigator !== 'undefined' && (/MSIE/.test(navigator.userAgent) || /Trident\//.test(navigator.appVersion) || /Edge/.test(navigator.userAgent))
561
562 var npotTextureCube = true
563
564 if (!isIE) {
565 var cubeTexture = gl.createTexture()
566 var data = pool.allocType(GL_UNSIGNED_BYTE, 36)
567 gl.activeTexture(GL_TEXTURE0)
568 gl.bindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture)
569 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 3, 3, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
570 pool.freeType(data)
571 gl.bindTexture(GL_TEXTURE_CUBE_MAP, null)
572 gl.deleteTexture(cubeTexture)
573 npotTextureCube = !gl.getError()
574 }
575
576 return {
577 // drawing buffer bit depth
578 colorBits: [
579 gl.getParameter(GL_RED_BITS),
580 gl.getParameter(GL_GREEN_BITS),
581 gl.getParameter(GL_BLUE_BITS),
582 gl.getParameter(GL_ALPHA_BITS)
583 ],
584 depthBits: gl.getParameter(GL_DEPTH_BITS),
585 stencilBits: gl.getParameter(GL_STENCIL_BITS),
586 subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS),
587
588 // supported extensions
589 extensions: Object.keys(extensions).filter(function (ext) {
590 return !!extensions[ext]
591 }),
592
593 // max aniso samples
594 maxAnisotropic: maxAnisotropic,
595
596 // max draw buffers
597 maxDrawbuffers: maxDrawbuffers,
598 maxColorAttachments: maxColorAttachments,
599
600 // point and line size ranges
601 pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE),
602 lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE),
603 maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS),
604 maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS),
605 maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE),
606 maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE),
607 maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS),
608 maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE),
609 maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS),
610 maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS),
611 maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS),
612 maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS),
613 maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS),
614
615 // vendor info
616 glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION),
617 renderer: gl.getParameter(GL_RENDERER),
618 vendor: gl.getParameter(GL_VENDOR),
619 version: gl.getParameter(GL_VERSION),
620
621 // quirks
622 readFloat: readFloat,
623 npotTextureCube: npotTextureCube
624 }
625}
626
627var isTypedArray = function (x) {
628 return (
629 x instanceof Uint8Array ||
630 x instanceof Uint16Array ||
631 x instanceof Uint32Array ||
632 x instanceof Int8Array ||
633 x instanceof Int16Array ||
634 x instanceof Int32Array ||
635 x instanceof Float32Array ||
636 x instanceof Float64Array ||
637 x instanceof Uint8ClampedArray
638 )
639}
640
641function isNDArrayLike (obj) {
642 return (
643 !!obj &&
644 typeof obj === 'object' &&
645 Array.isArray(obj.shape) &&
646 Array.isArray(obj.stride) &&
647 typeof obj.offset === 'number' &&
648 obj.shape.length === obj.stride.length &&
649 (Array.isArray(obj.data) ||
650 isTypedArray(obj.data)))
651}
652
653var values = function (obj) {
654 return Object.keys(obj).map(function (key) { return obj[key] })
655}
656
657var flattenUtils = {
658 shape: arrayShape$1,
659 flatten: flattenArray
660};
661
662function flatten1D (array, nx, out) {
663 for (var i = 0; i < nx; ++i) {
664 out[i] = array[i]
665 }
666}
667
668function flatten2D (array, nx, ny, out) {
669 var ptr = 0
670 for (var i = 0; i < nx; ++i) {
671 var row = array[i]
672 for (var j = 0; j < ny; ++j) {
673 out[ptr++] = row[j]
674 }
675 }
676}
677
678function flatten3D (array, nx, ny, nz, out, ptr_) {
679 var ptr = ptr_
680 for (var i = 0; i < nx; ++i) {
681 var row = array[i]
682 for (var j = 0; j < ny; ++j) {
683 var col = row[j]
684 for (var k = 0; k < nz; ++k) {
685 out[ptr++] = col[k]
686 }
687 }
688 }
689}
690
691function flattenRec (array, shape, level, out, ptr) {
692 var stride = 1
693 for (var i = level + 1; i < shape.length; ++i) {
694 stride *= shape[i]
695 }
696 var n = shape[level]
697 if (shape.length - level === 4) {
698 var nx = shape[level + 1]
699 var ny = shape[level + 2]
700 var nz = shape[level + 3]
701 for (i = 0; i < n; ++i) {
702 flatten3D(array[i], nx, ny, nz, out, ptr)
703 ptr += stride
704 }
705 } else {
706 for (i = 0; i < n; ++i) {
707 flattenRec(array[i], shape, level + 1, out, ptr)
708 ptr += stride
709 }
710 }
711}
712
713function flattenArray (array, shape, type, out_) {
714 var sz = 1
715 if (shape.length) {
716 for (var i = 0; i < shape.length; ++i) {
717 sz *= shape[i]
718 }
719 } else {
720 sz = 0
721 }
722 var out = out_ || pool.allocType(type, sz)
723 switch (shape.length) {
724 case 0:
725 break
726 case 1:
727 flatten1D(array, shape[0], out)
728 break
729 case 2:
730 flatten2D(array, shape[0], shape[1], out)
731 break
732 case 3:
733 flatten3D(array, shape[0], shape[1], shape[2], out, 0)
734 break
735 default:
736 flattenRec(array, shape, 0, out, 0)
737 }
738 return out
739}
740
741function arrayShape$1 (array_) {
742 var shape = []
743 for (var array = array_; array.length; array = array[0]) {
744 shape.push(array.length)
745 }
746 return shape
747}
748
749var arrayTypes = {
750 "[object Int8Array]": 5120,
751 "[object Int16Array]": 5122,
752 "[object Int32Array]": 5124,
753 "[object Uint8Array]": 5121,
754 "[object Uint8ClampedArray]": 5121,
755 "[object Uint16Array]": 5123,
756 "[object Uint32Array]": 5125,
757 "[object Float32Array]": 5126,
758 "[object Float64Array]": 5121,
759 "[object ArrayBuffer]": 5121
760};
761
762var int8 = 5120;
763var int16 = 5122;
764var int32 = 5124;
765var uint8 = 5121;
766var uint16 = 5123;
767var uint32 = 5125;
768var float = 5126;
769var float32 = 5126;
770var glTypes = {
771 int8: int8,
772 int16: int16,
773 int32: int32,
774 uint8: uint8,
775 uint16: uint16,
776 uint32: uint32,
777 float: float,
778 float32: float32
779};
780
781var dynamic$1 = 35048;
782var stream = 35040;
783var usageTypes = {
784 dynamic: dynamic$1,
785 stream: stream,
786 "static": 35044
787};
788
789var arrayFlatten = flattenUtils.flatten
790var arrayShape = flattenUtils.shape
791
792var GL_STATIC_DRAW = 0x88E4
793var GL_STREAM_DRAW = 0x88E0
794
795var GL_UNSIGNED_BYTE$2 = 5121
796var GL_FLOAT$2 = 5126
797
798var DTYPES_SIZES = []
799DTYPES_SIZES[5120] = 1 // int8
800DTYPES_SIZES[5122] = 2 // int16
801DTYPES_SIZES[5124] = 4 // int32
802DTYPES_SIZES[5121] = 1 // uint8
803DTYPES_SIZES[5123] = 2 // uint16
804DTYPES_SIZES[5125] = 4 // uint32
805DTYPES_SIZES[5126] = 4 // float32
806
807function typedArrayCode (data) {
808 return arrayTypes[Object.prototype.toString.call(data)] | 0
809}
810
811function copyArray (out, inp) {
812 for (var i = 0; i < inp.length; ++i) {
813 out[i] = inp[i]
814 }
815}
816
817function transpose (
818 result, data, shapeX, shapeY, strideX, strideY, offset) {
819 var ptr = 0
820 for (var i = 0; i < shapeX; ++i) {
821 for (var j = 0; j < shapeY; ++j) {
822 result[ptr++] = data[strideX * i + strideY * j + offset]
823 }
824 }
825}
826
827function wrapBufferState (gl, stats, config, destroyBuffer) {
828 var bufferCount = 0
829 var bufferSet = {}
830
831 function REGLBuffer (type) {
832 this.id = bufferCount++
833 this.buffer = gl.createBuffer()
834 this.type = type
835 this.usage = GL_STATIC_DRAW
836 this.byteLength = 0
837 this.dimension = 1
838 this.dtype = GL_UNSIGNED_BYTE$2
839
840 this.persistentData = null
841
842 if (config.profile) {
843 this.stats = { size: 0 }
844 }
845 }
846
847 REGLBuffer.prototype.bind = function () {
848 gl.bindBuffer(this.type, this.buffer)
849 }
850
851 REGLBuffer.prototype.destroy = function () {
852 destroy(this)
853 }
854
855 var streamPool = []
856
857 function createStream (type, data) {
858 var buffer = streamPool.pop()
859 if (!buffer) {
860 buffer = new REGLBuffer(type)
861 }
862 buffer.bind()
863 initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false)
864 return buffer
865 }
866
867 function destroyStream (stream$$1) {
868 streamPool.push(stream$$1)
869 }
870
871 function initBufferFromTypedArray (buffer, data, usage) {
872 buffer.byteLength = data.byteLength
873 gl.bufferData(buffer.type, data, usage)
874 }
875
876 function initBufferFromData (buffer, data, usage, dtype, dimension, persist) {
877 var shape
878 buffer.usage = usage
879 if (Array.isArray(data)) {
880 buffer.dtype = dtype || GL_FLOAT$2
881 if (data.length > 0) {
882 var flatData
883 if (Array.isArray(data[0])) {
884 shape = arrayShape(data)
885 var dim = 1
886 for (var i = 1; i < shape.length; ++i) {
887 dim *= shape[i]
888 }
889 buffer.dimension = dim
890 flatData = arrayFlatten(data, shape, buffer.dtype)
891 initBufferFromTypedArray(buffer, flatData, usage)
892 if (persist) {
893 buffer.persistentData = flatData
894 } else {
895 pool.freeType(flatData)
896 }
897 } else if (typeof data[0] === 'number') {
898 buffer.dimension = dimension
899 var typedData = pool.allocType(buffer.dtype, data.length)
900 copyArray(typedData, data)
901 initBufferFromTypedArray(buffer, typedData, usage)
902 if (persist) {
903 buffer.persistentData = typedData
904 } else {
905 pool.freeType(typedData)
906 }
907 } else if (isTypedArray(data[0])) {
908 buffer.dimension = data[0].length
909 buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT$2
910 flatData = arrayFlatten(
911 data,
912 [data.length, data[0].length],
913 buffer.dtype)
914 initBufferFromTypedArray(buffer, flatData, usage)
915 if (persist) {
916 buffer.persistentData = flatData
917 } else {
918 pool.freeType(flatData)
919 }
920 } else {
921
922 }
923 }
924 } else if (isTypedArray(data)) {
925 buffer.dtype = dtype || typedArrayCode(data)
926 buffer.dimension = dimension
927 initBufferFromTypedArray(buffer, data, usage)
928 if (persist) {
929 buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer))
930 }
931 } else if (isNDArrayLike(data)) {
932 shape = data.shape
933 var stride = data.stride
934 var offset = data.offset
935
936 var shapeX = 0
937 var shapeY = 0
938 var strideX = 0
939 var strideY = 0
940 if (shape.length === 1) {
941 shapeX = shape[0]
942 shapeY = 1
943 strideX = stride[0]
944 strideY = 0
945 } else if (shape.length === 2) {
946 shapeX = shape[0]
947 shapeY = shape[1]
948 strideX = stride[0]
949 strideY = stride[1]
950 } else {
951
952 }
953
954 buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$2
955 buffer.dimension = shapeY
956
957 var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY)
958 transpose(transposeData,
959 data.data,
960 shapeX, shapeY,
961 strideX, strideY,
962 offset)
963 initBufferFromTypedArray(buffer, transposeData, usage)
964 if (persist) {
965 buffer.persistentData = transposeData
966 } else {
967 pool.freeType(transposeData)
968 }
969 } else if (data instanceof ArrayBuffer) {
970 buffer.dtype = GL_UNSIGNED_BYTE$2
971 buffer.dimension = dimension
972 initBufferFromTypedArray(buffer, data, usage)
973 if (persist) {
974 buffer.persistentData = new Uint8Array(new Uint8Array(data))
975 }
976 } else {
977
978 }
979 }
980
981 function destroy (buffer) {
982 stats.bufferCount--
983
984 // remove attribute link
985 destroyBuffer(buffer)
986
987 var handle = buffer.buffer
988
989 gl.deleteBuffer(handle)
990 buffer.buffer = null
991 delete bufferSet[buffer.id]
992 }
993
994 function createBuffer (options, type, deferInit, persistent) {
995 stats.bufferCount++
996
997 var buffer = new REGLBuffer(type)
998 bufferSet[buffer.id] = buffer
999
1000 function reglBuffer (options) {
1001 var usage = GL_STATIC_DRAW
1002 var data = null
1003 var byteLength = 0
1004 var dtype = 0
1005 var dimension = 1
1006 if (Array.isArray(options) ||
1007 isTypedArray(options) ||
1008 isNDArrayLike(options) ||
1009 options instanceof ArrayBuffer) {
1010 data = options
1011 } else if (typeof options === 'number') {
1012 byteLength = options | 0
1013 } else if (options) {
1014
1015
1016 if ('data' in options) {
1017
1018 data = options.data
1019 }
1020
1021 if ('usage' in options) {
1022
1023 usage = usageTypes[options.usage]
1024 }
1025
1026 if ('type' in options) {
1027
1028 dtype = glTypes[options.type]
1029 }
1030
1031 if ('dimension' in options) {
1032
1033 dimension = options.dimension | 0
1034 }
1035
1036 if ('length' in options) {
1037
1038 byteLength = options.length | 0
1039 }
1040 }
1041
1042 buffer.bind()
1043 if (!data) {
1044 // #475
1045 if (byteLength) gl.bufferData(buffer.type, byteLength, usage)
1046 buffer.dtype = dtype || GL_UNSIGNED_BYTE$2
1047 buffer.usage = usage
1048 buffer.dimension = dimension
1049 buffer.byteLength = byteLength
1050 } else {
1051 initBufferFromData(buffer, data, usage, dtype, dimension, persistent)
1052 }
1053
1054 if (config.profile) {
1055 buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype]
1056 }
1057
1058 return reglBuffer
1059 }
1060
1061 function setSubData (data, offset) {
1062
1063
1064 gl.bufferSubData(buffer.type, offset, data)
1065 }
1066
1067 function subdata (data, offset_) {
1068 var offset = (offset_ || 0) | 0
1069 var shape
1070 buffer.bind()
1071 if (isTypedArray(data) || data instanceof ArrayBuffer) {
1072 setSubData(data, offset)
1073 } else if (Array.isArray(data)) {
1074 if (data.length > 0) {
1075 if (typeof data[0] === 'number') {
1076 var converted = pool.allocType(buffer.dtype, data.length)
1077 copyArray(converted, data)
1078 setSubData(converted, offset)
1079 pool.freeType(converted)
1080 } else if (Array.isArray(data[0]) || isTypedArray(data[0])) {
1081 shape = arrayShape(data)
1082 var flatData = arrayFlatten(data, shape, buffer.dtype)
1083 setSubData(flatData, offset)
1084 pool.freeType(flatData)
1085 } else {
1086
1087 }
1088 }
1089 } else if (isNDArrayLike(data)) {
1090 shape = data.shape
1091 var stride = data.stride
1092
1093 var shapeX = 0
1094 var shapeY = 0
1095 var strideX = 0
1096 var strideY = 0
1097 if (shape.length === 1) {
1098 shapeX = shape[0]
1099 shapeY = 1
1100 strideX = stride[0]
1101 strideY = 0
1102 } else if (shape.length === 2) {
1103 shapeX = shape[0]
1104 shapeY = shape[1]
1105 strideX = stride[0]
1106 strideY = stride[1]
1107 } else {
1108
1109 }
1110 var dtype = Array.isArray(data.data)
1111 ? buffer.dtype
1112 : typedArrayCode(data.data)
1113
1114 var transposeData = pool.allocType(dtype, shapeX * shapeY)
1115 transpose(transposeData,
1116 data.data,
1117 shapeX, shapeY,
1118 strideX, strideY,
1119 data.offset)
1120 setSubData(transposeData, offset)
1121 pool.freeType(transposeData)
1122 } else {
1123
1124 }
1125 return reglBuffer
1126 }
1127
1128 if (!deferInit) {
1129 reglBuffer(options)
1130 }
1131
1132 reglBuffer._reglType = 'buffer'
1133 reglBuffer._buffer = buffer
1134 reglBuffer.subdata = subdata
1135 if (config.profile) {
1136 reglBuffer.stats = buffer.stats
1137 }
1138 reglBuffer.destroy = function () { destroy(buffer) }
1139
1140 return reglBuffer
1141 }
1142
1143 function restoreBuffers () {
1144 values(bufferSet).forEach(function (buffer) {
1145 buffer.buffer = gl.createBuffer()
1146 gl.bindBuffer(buffer.type, buffer.buffer)
1147 gl.bufferData(
1148 buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage)
1149 })
1150 }
1151
1152 if (config.profile) {
1153 stats.getTotalBufferSize = function () {
1154 var total = 0
1155 // TODO: Right now, the streams are not part of the total count.
1156 Object.keys(bufferSet).forEach(function (key) {
1157 total += bufferSet[key].stats.size
1158 })
1159 return total
1160 }
1161 }
1162
1163 return {
1164 create: createBuffer,
1165
1166 createStream: createStream,
1167 destroyStream: destroyStream,
1168
1169 clear: function () {
1170 values(bufferSet).forEach(destroy)
1171 streamPool.forEach(destroy)
1172 },
1173
1174 getBuffer: function (wrapper) {
1175 if (wrapper && wrapper._buffer instanceof REGLBuffer) {
1176 return wrapper._buffer
1177 }
1178 return null
1179 },
1180
1181 restore: restoreBuffers,
1182
1183 _initBuffer: initBufferFromData
1184 }
1185}
1186
1187var points = 0;
1188var point = 0;
1189var lines = 1;
1190var line = 1;
1191var triangles = 4;
1192var triangle = 4;
1193var primTypes = {
1194 points: points,
1195 point: point,
1196 lines: lines,
1197 line: line,
1198 triangles: triangles,
1199 triangle: triangle,
1200 "line loop": 2,
1201 "line strip": 3,
1202 "triangle strip": 5,
1203 "triangle fan": 6
1204};
1205
1206var GL_POINTS = 0
1207var GL_LINES = 1
1208var GL_TRIANGLES = 4
1209
1210var GL_BYTE$1 = 5120
1211var GL_UNSIGNED_BYTE$3 = 5121
1212var GL_SHORT$1 = 5122
1213var GL_UNSIGNED_SHORT$1 = 5123
1214var GL_INT$1 = 5124
1215var GL_UNSIGNED_INT$1 = 5125
1216
1217var GL_ELEMENT_ARRAY_BUFFER = 34963
1218
1219var GL_STREAM_DRAW$1 = 0x88E0
1220var GL_STATIC_DRAW$1 = 0x88E4
1221
1222function wrapElementsState (gl, extensions, bufferState, stats) {
1223 var elementSet = {}
1224 var elementCount = 0
1225
1226 var elementTypes = {
1227 'uint8': GL_UNSIGNED_BYTE$3,
1228 'uint16': GL_UNSIGNED_SHORT$1
1229 }
1230
1231 if (extensions.oes_element_index_uint) {
1232 elementTypes.uint32 = GL_UNSIGNED_INT$1
1233 }
1234
1235 function REGLElementBuffer (buffer) {
1236 this.id = elementCount++
1237 elementSet[this.id] = this
1238 this.buffer = buffer
1239 this.primType = GL_TRIANGLES
1240 this.vertCount = 0
1241 this.type = 0
1242 }
1243
1244 REGLElementBuffer.prototype.bind = function () {
1245 this.buffer.bind()
1246 }
1247
1248 var bufferPool = []
1249
1250 function createElementStream (data) {
1251 var result = bufferPool.pop()
1252 if (!result) {
1253 result = new REGLElementBuffer(bufferState.create(
1254 null,
1255 GL_ELEMENT_ARRAY_BUFFER,
1256 true,
1257 false)._buffer)
1258 }
1259 initElements(result, data, GL_STREAM_DRAW$1, -1, -1, 0, 0)
1260 return result
1261 }
1262
1263 function destroyElementStream (elements) {
1264 bufferPool.push(elements)
1265 }
1266
1267 function initElements (
1268 elements,
1269 data,
1270 usage,
1271 prim,
1272 count,
1273 byteLength,
1274 type) {
1275 elements.buffer.bind()
1276 var dtype
1277 if (data) {
1278 var predictedType = type
1279 if (!type && (
1280 !isTypedArray(data) ||
1281 (isNDArrayLike(data) && !isTypedArray(data.data)))) {
1282 predictedType = extensions.oes_element_index_uint
1283 ? GL_UNSIGNED_INT$1
1284 : GL_UNSIGNED_SHORT$1
1285 }
1286 bufferState._initBuffer(
1287 elements.buffer,
1288 data,
1289 usage,
1290 predictedType,
1291 3)
1292 } else {
1293 gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage)
1294 elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$3
1295 elements.buffer.usage = usage
1296 elements.buffer.dimension = 3
1297 elements.buffer.byteLength = byteLength
1298 }
1299
1300 dtype = type
1301 if (!type) {
1302 switch (elements.buffer.dtype) {
1303 case GL_UNSIGNED_BYTE$3:
1304 case GL_BYTE$1:
1305 dtype = GL_UNSIGNED_BYTE$3
1306 break
1307
1308 case GL_UNSIGNED_SHORT$1:
1309 case GL_SHORT$1:
1310 dtype = GL_UNSIGNED_SHORT$1
1311 break
1312
1313 case GL_UNSIGNED_INT$1:
1314 case GL_INT$1:
1315 dtype = GL_UNSIGNED_INT$1
1316 break
1317
1318 default:
1319
1320 }
1321 elements.buffer.dtype = dtype
1322 }
1323 elements.type = dtype
1324
1325 // Check oes_element_index_uint extension
1326
1327
1328 // try to guess default primitive type and arguments
1329 var vertCount = count
1330 if (vertCount < 0) {
1331 vertCount = elements.buffer.byteLength
1332 if (dtype === GL_UNSIGNED_SHORT$1) {
1333 vertCount >>= 1
1334 } else if (dtype === GL_UNSIGNED_INT$1) {
1335 vertCount >>= 2
1336 }
1337 }
1338 elements.vertCount = vertCount
1339
1340 // try to guess primitive type from cell dimension
1341 var primType = prim
1342 if (prim < 0) {
1343 primType = GL_TRIANGLES
1344 var dimension = elements.buffer.dimension
1345 if (dimension === 1) primType = GL_POINTS
1346 if (dimension === 2) primType = GL_LINES
1347 if (dimension === 3) primType = GL_TRIANGLES
1348 }
1349 elements.primType = primType
1350 }
1351
1352 function destroyElements (elements) {
1353 stats.elementsCount--
1354
1355
1356 delete elementSet[elements.id]
1357 elements.buffer.destroy()
1358 elements.buffer = null
1359 }
1360
1361 function createElements (options, persistent) {
1362 var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true)
1363 var elements = new REGLElementBuffer(buffer._buffer)
1364 stats.elementsCount++
1365
1366 function reglElements (options) {
1367 if (!options) {
1368 buffer()
1369 elements.primType = GL_TRIANGLES
1370 elements.vertCount = 0
1371 elements.type = GL_UNSIGNED_BYTE$3
1372 } else if (typeof options === 'number') {
1373 buffer(options)
1374 elements.primType = GL_TRIANGLES
1375 elements.vertCount = options | 0
1376 elements.type = GL_UNSIGNED_BYTE$3
1377 } else {
1378 var data = null
1379 var usage = GL_STATIC_DRAW$1
1380 var primType = -1
1381 var vertCount = -1
1382 var byteLength = 0
1383 var dtype = 0
1384 if (Array.isArray(options) ||
1385 isTypedArray(options) ||
1386 isNDArrayLike(options)) {
1387 data = options
1388 } else {
1389
1390 if ('data' in options) {
1391 data = options.data
1392
1393 }
1394 if ('usage' in options) {
1395
1396 usage = usageTypes[options.usage]
1397 }
1398 if ('primitive' in options) {
1399
1400 primType = primTypes[options.primitive]
1401 }
1402 if ('count' in options) {
1403
1404 vertCount = options.count | 0
1405 }
1406 if ('type' in options) {
1407
1408 dtype = elementTypes[options.type]
1409 }
1410 if ('length' in options) {
1411 byteLength = options.length | 0
1412 } else {
1413 byteLength = vertCount
1414 if (dtype === GL_UNSIGNED_SHORT$1 || dtype === GL_SHORT$1) {
1415 byteLength *= 2
1416 } else if (dtype === GL_UNSIGNED_INT$1 || dtype === GL_INT$1) {
1417 byteLength *= 4
1418 }
1419 }
1420 }
1421 initElements(
1422 elements,
1423 data,
1424 usage,
1425 primType,
1426 vertCount,
1427 byteLength,
1428 dtype)
1429 }
1430
1431 return reglElements
1432 }
1433
1434 reglElements(options)
1435
1436 reglElements._reglType = 'elements'
1437 reglElements._elements = elements
1438 reglElements.subdata = function (data, offset) {
1439 buffer.subdata(data, offset)
1440 return reglElements
1441 }
1442 reglElements.destroy = function () {
1443 destroyElements(elements)
1444 }
1445
1446 return reglElements
1447 }
1448
1449 return {
1450 create: createElements,
1451 createStream: createElementStream,
1452 destroyStream: destroyElementStream,
1453 getElements: function (elements) {
1454 if (typeof elements === 'function' &&
1455 elements._elements instanceof REGLElementBuffer) {
1456 return elements._elements
1457 }
1458 return null
1459 },
1460 clear: function () {
1461 values(elementSet).forEach(destroyElements)
1462 }
1463 }
1464}
1465
1466var FLOAT = new Float32Array(1)
1467var INT = new Uint32Array(FLOAT.buffer)
1468
1469var GL_UNSIGNED_SHORT$3 = 5123
1470
1471function convertToHalfFloat (array) {
1472 var ushorts = pool.allocType(GL_UNSIGNED_SHORT$3, array.length)
1473
1474 for (var i = 0; i < array.length; ++i) {
1475 if (isNaN(array[i])) {
1476 ushorts[i] = 0xffff
1477 } else if (array[i] === Infinity) {
1478 ushorts[i] = 0x7c00
1479 } else if (array[i] === -Infinity) {
1480 ushorts[i] = 0xfc00
1481 } else {
1482 FLOAT[0] = array[i]
1483 var x = INT[0]
1484
1485 var sgn = (x >>> 31) << 15
1486 var exp = ((x << 1) >>> 24) - 127
1487 var frac = (x >> 13) & ((1 << 10) - 1)
1488
1489 if (exp < -24) {
1490 // round non-representable denormals to 0
1491 ushorts[i] = sgn
1492 } else if (exp < -14) {
1493 // handle denormals
1494 var s = -14 - exp
1495 ushorts[i] = sgn + ((frac + (1 << 10)) >> s)
1496 } else if (exp > 15) {
1497 // round overflow to +/- Infinity
1498 ushorts[i] = sgn + 0x7c00
1499 } else {
1500 // otherwise convert directly
1501 ushorts[i] = sgn + ((exp + 15) << 10) + frac
1502 }
1503 }
1504 }
1505
1506 return ushorts
1507}
1508
1509function isArrayLike (s) {
1510 return Array.isArray(s) || isTypedArray(s)
1511}
1512
1513var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3
1514
1515var GL_TEXTURE_2D$1 = 0x0DE1
1516var GL_TEXTURE_CUBE_MAP$1 = 0x8513
1517var GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 = 0x8515
1518
1519var GL_RGBA$1 = 0x1908
1520var GL_ALPHA = 0x1906
1521var GL_RGB = 0x1907
1522var GL_LUMINANCE = 0x1909
1523var GL_LUMINANCE_ALPHA = 0x190A
1524
1525var GL_RGBA4 = 0x8056
1526var GL_RGB5_A1 = 0x8057
1527var GL_RGB565 = 0x8D62
1528
1529var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033
1530var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034
1531var GL_UNSIGNED_SHORT_5_6_5 = 0x8363
1532var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA
1533
1534var GL_DEPTH_COMPONENT = 0x1902
1535var GL_DEPTH_STENCIL = 0x84F9
1536
1537var GL_SRGB_EXT = 0x8C40
1538var GL_SRGB_ALPHA_EXT = 0x8C42
1539
1540var GL_HALF_FLOAT_OES = 0x8D61
1541
1542var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0
1543var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1
1544var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2
1545var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3
1546
1547var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92
1548var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93
1549var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE
1550
1551var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00
1552var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01
1553var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02
1554var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03
1555
1556var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64
1557
1558var GL_UNSIGNED_BYTE$4 = 0x1401
1559var GL_UNSIGNED_SHORT$2 = 0x1403
1560var GL_UNSIGNED_INT$2 = 0x1405
1561var GL_FLOAT$3 = 0x1406
1562
1563var GL_TEXTURE_WRAP_S = 0x2802
1564var GL_TEXTURE_WRAP_T = 0x2803
1565
1566var GL_REPEAT = 0x2901
1567var GL_CLAMP_TO_EDGE = 0x812F
1568var GL_MIRRORED_REPEAT = 0x8370
1569
1570var GL_TEXTURE_MAG_FILTER = 0x2800
1571var GL_TEXTURE_MIN_FILTER = 0x2801
1572
1573var GL_NEAREST = 0x2600
1574var GL_LINEAR = 0x2601
1575var GL_NEAREST_MIPMAP_NEAREST = 0x2700
1576var GL_LINEAR_MIPMAP_NEAREST = 0x2701
1577var GL_NEAREST_MIPMAP_LINEAR = 0x2702
1578var GL_LINEAR_MIPMAP_LINEAR = 0x2703
1579
1580var GL_GENERATE_MIPMAP_HINT = 0x8192
1581var GL_DONT_CARE = 0x1100
1582var GL_FASTEST = 0x1101
1583var GL_NICEST = 0x1102
1584
1585var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE
1586
1587var GL_UNPACK_ALIGNMENT = 0x0CF5
1588var GL_UNPACK_FLIP_Y_WEBGL = 0x9240
1589var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241
1590var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243
1591
1592var GL_BROWSER_DEFAULT_WEBGL = 0x9244
1593
1594var GL_TEXTURE0$1 = 0x84C0
1595
1596var MIPMAP_FILTERS = [
1597 GL_NEAREST_MIPMAP_NEAREST,
1598 GL_NEAREST_MIPMAP_LINEAR,
1599 GL_LINEAR_MIPMAP_NEAREST,
1600 GL_LINEAR_MIPMAP_LINEAR
1601]
1602
1603var CHANNELS_FORMAT = [
1604 0,
1605 GL_LUMINANCE,
1606 GL_LUMINANCE_ALPHA,
1607 GL_RGB,
1608 GL_RGBA$1
1609]
1610
1611var FORMAT_CHANNELS = {}
1612FORMAT_CHANNELS[GL_LUMINANCE] =
1613FORMAT_CHANNELS[GL_ALPHA] =
1614FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1
1615FORMAT_CHANNELS[GL_DEPTH_STENCIL] =
1616FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2
1617FORMAT_CHANNELS[GL_RGB] =
1618FORMAT_CHANNELS[GL_SRGB_EXT] = 3
1619FORMAT_CHANNELS[GL_RGBA$1] =
1620FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4
1621
1622function objectName (str) {
1623 return '[object ' + str + ']'
1624}
1625
1626var CANVAS_CLASS = objectName('HTMLCanvasElement')
1627var OFFSCREENCANVAS_CLASS = objectName('OffscreenCanvas')
1628var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D')
1629var BITMAP_CLASS = objectName('ImageBitmap')
1630var IMAGE_CLASS = objectName('HTMLImageElement')
1631var VIDEO_CLASS = objectName('HTMLVideoElement')
1632
1633var PIXEL_CLASSES = Object.keys(arrayTypes).concat([
1634 CANVAS_CLASS,
1635 OFFSCREENCANVAS_CLASS,
1636 CONTEXT2D_CLASS,
1637 BITMAP_CLASS,
1638 IMAGE_CLASS,
1639 VIDEO_CLASS
1640])
1641
1642// for every texture type, store
1643// the size in bytes.
1644var TYPE_SIZES = []
1645TYPE_SIZES[GL_UNSIGNED_BYTE$4] = 1
1646TYPE_SIZES[GL_FLOAT$3] = 4
1647TYPE_SIZES[GL_HALF_FLOAT_OES] = 2
1648
1649TYPE_SIZES[GL_UNSIGNED_SHORT$2] = 2
1650TYPE_SIZES[GL_UNSIGNED_INT$2] = 4
1651
1652var FORMAT_SIZES_SPECIAL = []
1653FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2
1654FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2
1655FORMAT_SIZES_SPECIAL[GL_RGB565] = 2
1656FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4
1657
1658FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5
1659FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5
1660FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1
1661FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1
1662
1663FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5
1664FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1
1665FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1
1666
1667FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5
1668FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25
1669FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5
1670FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25
1671
1672FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5
1673
1674function isNumericArray (arr) {
1675 return (
1676 Array.isArray(arr) &&
1677 (arr.length === 0 ||
1678 typeof arr[0] === 'number'))
1679}
1680
1681function isRectArray (arr) {
1682 if (!Array.isArray(arr)) {
1683 return false
1684 }
1685 var width = arr.length
1686 if (width === 0 || !isArrayLike(arr[0])) {
1687 return false
1688 }
1689 return true
1690}
1691
1692function classString (x) {
1693 return Object.prototype.toString.call(x)
1694}
1695
1696function isCanvasElement (object) {
1697 return classString(object) === CANVAS_CLASS
1698}
1699
1700function isOffscreenCanvas (object) {
1701 return classString(object) === OFFSCREENCANVAS_CLASS
1702}
1703
1704function isContext2D (object) {
1705 return classString(object) === CONTEXT2D_CLASS
1706}
1707
1708function isBitmap (object) {
1709 return classString(object) === BITMAP_CLASS
1710}
1711
1712function isImageElement (object) {
1713 return classString(object) === IMAGE_CLASS
1714}
1715
1716function isVideoElement (object) {
1717 return classString(object) === VIDEO_CLASS
1718}
1719
1720function isPixelData (object) {
1721 if (!object) {
1722 return false
1723 }
1724 var className = classString(object)
1725 if (PIXEL_CLASSES.indexOf(className) >= 0) {
1726 return true
1727 }
1728 return (
1729 isNumericArray(object) ||
1730 isRectArray(object) ||
1731 isNDArrayLike(object))
1732}
1733
1734function typedArrayCode$1 (data) {
1735 return arrayTypes[Object.prototype.toString.call(data)] | 0
1736}
1737
1738function convertData (result, data) {
1739 var n = data.length
1740 switch (result.type) {
1741 case GL_UNSIGNED_BYTE$4:
1742 case GL_UNSIGNED_SHORT$2:
1743 case GL_UNSIGNED_INT$2:
1744 case GL_FLOAT$3:
1745 var converted = pool.allocType(result.type, n)
1746 converted.set(data)
1747 result.data = converted
1748 break
1749
1750 case GL_HALF_FLOAT_OES:
1751 result.data = convertToHalfFloat(data)
1752 break
1753
1754 default:
1755
1756 }
1757}
1758
1759function preConvert (image, n) {
1760 return pool.allocType(
1761 image.type === GL_HALF_FLOAT_OES
1762 ? GL_FLOAT$3
1763 : image.type, n)
1764}
1765
1766function postConvert (image, data) {
1767 if (image.type === GL_HALF_FLOAT_OES) {
1768 image.data = convertToHalfFloat(data)
1769 pool.freeType(data)
1770 } else {
1771 image.data = data
1772 }
1773}
1774
1775function transposeData (image, array, strideX, strideY, strideC, offset) {
1776 var w = image.width
1777 var h = image.height
1778 var c = image.channels
1779 var n = w * h * c
1780 var data = preConvert(image, n)
1781
1782 var p = 0
1783 for (var i = 0; i < h; ++i) {
1784 for (var j = 0; j < w; ++j) {
1785 for (var k = 0; k < c; ++k) {
1786 data[p++] = array[strideX * j + strideY * i + strideC * k + offset]
1787 }
1788 }
1789 }
1790
1791 postConvert(image, data)
1792}
1793
1794function getTextureSize (format, type, width, height, isMipmap, isCube) {
1795 var s
1796 if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') {
1797 // we have a special array for dealing with weird color formats such as RGB5A1
1798 s = FORMAT_SIZES_SPECIAL[format]
1799 } else {
1800 s = FORMAT_CHANNELS[format] * TYPE_SIZES[type]
1801 }
1802
1803 if (isCube) {
1804 s *= 6
1805 }
1806
1807 if (isMipmap) {
1808 // compute the total size of all the mipmaps.
1809 var total = 0
1810
1811 var w = width
1812 while (w >= 1) {
1813 // we can only use mipmaps on a square image,
1814 // so we can simply use the width and ignore the height:
1815 total += s * w * w
1816 w /= 2
1817 }
1818 return total
1819 } else {
1820 return s * width * height
1821 }
1822}
1823
1824function createTextureSet (
1825 gl, extensions, limits, reglPoll, contextState, stats, config) {
1826 // -------------------------------------------------------
1827 // Initialize constants and parameter tables here
1828 // -------------------------------------------------------
1829 var mipmapHint = {
1830 "don't care": GL_DONT_CARE,
1831 'dont care': GL_DONT_CARE,
1832 'nice': GL_NICEST,
1833 'fast': GL_FASTEST
1834 }
1835
1836 var wrapModes = {
1837 'repeat': GL_REPEAT,
1838 'clamp': GL_CLAMP_TO_EDGE,
1839 'mirror': GL_MIRRORED_REPEAT
1840 }
1841
1842 var magFilters = {
1843 'nearest': GL_NEAREST,
1844 'linear': GL_LINEAR
1845 }
1846
1847 var minFilters = extend({
1848 'mipmap': GL_LINEAR_MIPMAP_LINEAR,
1849 'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST,
1850 'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST,
1851 'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR,
1852 'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR
1853 }, magFilters)
1854
1855 var colorSpace = {
1856 'none': 0,
1857 'browser': GL_BROWSER_DEFAULT_WEBGL
1858 }
1859
1860 var textureTypes = {
1861 'uint8': GL_UNSIGNED_BYTE$4,
1862 'rgba4': GL_UNSIGNED_SHORT_4_4_4_4,
1863 'rgb565': GL_UNSIGNED_SHORT_5_6_5,
1864 'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1
1865 }
1866
1867 var textureFormats = {
1868 'alpha': GL_ALPHA,
1869 'luminance': GL_LUMINANCE,
1870 'luminance alpha': GL_LUMINANCE_ALPHA,
1871 'rgb': GL_RGB,
1872 'rgba': GL_RGBA$1,
1873 'rgba4': GL_RGBA4,
1874 'rgb5 a1': GL_RGB5_A1,
1875 'rgb565': GL_RGB565
1876 }
1877
1878 var compressedTextureFormats = {}
1879
1880 if (extensions.ext_srgb) {
1881 textureFormats.srgb = GL_SRGB_EXT
1882 textureFormats.srgba = GL_SRGB_ALPHA_EXT
1883 }
1884
1885 if (extensions.oes_texture_float) {
1886 textureTypes.float32 = textureTypes.float = GL_FLOAT$3
1887 }
1888
1889 if (extensions.oes_texture_half_float) {
1890 textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES
1891 }
1892
1893 if (extensions.webgl_depth_texture) {
1894 extend(textureFormats, {
1895 'depth': GL_DEPTH_COMPONENT,
1896 'depth stencil': GL_DEPTH_STENCIL
1897 })
1898
1899 extend(textureTypes, {
1900 'uint16': GL_UNSIGNED_SHORT$2,
1901 'uint32': GL_UNSIGNED_INT$2,
1902 'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL
1903 })
1904 }
1905
1906 if (extensions.webgl_compressed_texture_s3tc) {
1907 extend(compressedTextureFormats, {
1908 'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
1909 'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
1910 'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
1911 'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
1912 })
1913 }
1914
1915 if (extensions.webgl_compressed_texture_atc) {
1916 extend(compressedTextureFormats, {
1917 'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL,
1918 'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
1919 'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
1920 })
1921 }
1922
1923 if (extensions.webgl_compressed_texture_pvrtc) {
1924 extend(compressedTextureFormats, {
1925 'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
1926 'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
1927 'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
1928 'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
1929 })
1930 }
1931
1932 if (extensions.webgl_compressed_texture_etc1) {
1933 compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL
1934 }
1935
1936 // Copy over all texture formats
1937 var supportedCompressedFormats = Array.prototype.slice.call(
1938 gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS))
1939 Object.keys(compressedTextureFormats).forEach(function (name) {
1940 var format = compressedTextureFormats[name]
1941 if (supportedCompressedFormats.indexOf(format) >= 0) {
1942 textureFormats[name] = format
1943 }
1944 })
1945
1946 var supportedFormats = Object.keys(textureFormats)
1947 limits.textureFormats = supportedFormats
1948
1949 // associate with every format string its
1950 // corresponding GL-value.
1951 var textureFormatsInvert = []
1952 Object.keys(textureFormats).forEach(function (key) {
1953 var val = textureFormats[key]
1954 textureFormatsInvert[val] = key
1955 })
1956
1957 // associate with every type string its
1958 // corresponding GL-value.
1959 var textureTypesInvert = []
1960 Object.keys(textureTypes).forEach(function (key) {
1961 var val = textureTypes[key]
1962 textureTypesInvert[val] = key
1963 })
1964
1965 var magFiltersInvert = []
1966 Object.keys(magFilters).forEach(function (key) {
1967 var val = magFilters[key]
1968 magFiltersInvert[val] = key
1969 })
1970
1971 var minFiltersInvert = []
1972 Object.keys(minFilters).forEach(function (key) {
1973 var val = minFilters[key]
1974 minFiltersInvert[val] = key
1975 })
1976
1977 var wrapModesInvert = []
1978 Object.keys(wrapModes).forEach(function (key) {
1979 var val = wrapModes[key]
1980 wrapModesInvert[val] = key
1981 })
1982
1983 // colorFormats[] gives the format (channels) associated to an
1984 // internalformat
1985 var colorFormats = supportedFormats.reduce(function (color, key) {
1986 var glenum = textureFormats[key]
1987 if (glenum === GL_LUMINANCE ||
1988 glenum === GL_ALPHA ||
1989 glenum === GL_LUMINANCE ||
1990 glenum === GL_LUMINANCE_ALPHA ||
1991 glenum === GL_DEPTH_COMPONENT ||
1992 glenum === GL_DEPTH_STENCIL ||
1993 (extensions.ext_srgb &&
1994 (glenum === GL_SRGB_EXT ||
1995 glenum === GL_SRGB_ALPHA_EXT))) {
1996 color[glenum] = glenum
1997 } else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) {
1998 color[glenum] = GL_RGBA$1
1999 } else {
2000 color[glenum] = GL_RGB
2001 }
2002 return color
2003 }, {})
2004
2005 function TexFlags () {
2006 // format info
2007 this.internalformat = GL_RGBA$1
2008 this.format = GL_RGBA$1
2009 this.type = GL_UNSIGNED_BYTE$4
2010 this.compressed = false
2011
2012 // pixel storage
2013 this.premultiplyAlpha = false
2014 this.flipY = false
2015 this.unpackAlignment = 1
2016 this.colorSpace = GL_BROWSER_DEFAULT_WEBGL
2017
2018 // shape info
2019 this.width = 0
2020 this.height = 0
2021 this.channels = 0
2022 }
2023
2024 function copyFlags (result, other) {
2025 result.internalformat = other.internalformat
2026 result.format = other.format
2027 result.type = other.type
2028 result.compressed = other.compressed
2029
2030 result.premultiplyAlpha = other.premultiplyAlpha
2031 result.flipY = other.flipY
2032 result.unpackAlignment = other.unpackAlignment
2033 result.colorSpace = other.colorSpace
2034
2035 result.width = other.width
2036 result.height = other.height
2037 result.channels = other.channels
2038 }
2039
2040 function parseFlags (flags, options) {
2041 if (typeof options !== 'object' || !options) {
2042 return
2043 }
2044
2045 if ('premultiplyAlpha' in options) {
2046
2047 flags.premultiplyAlpha = options.premultiplyAlpha
2048 }
2049
2050 if ('flipY' in options) {
2051
2052 flags.flipY = options.flipY
2053 }
2054
2055 if ('alignment' in options) {
2056
2057 flags.unpackAlignment = options.alignment
2058 }
2059
2060 if ('colorSpace' in options) {
2061
2062 flags.colorSpace = colorSpace[options.colorSpace]
2063 }
2064
2065 if ('type' in options) {
2066 var type = options.type
2067
2068
2069
2070
2071 flags.type = textureTypes[type]
2072 }
2073
2074 var w = flags.width
2075 var h = flags.height
2076 var c = flags.channels
2077 var hasChannels = false
2078 if ('shape' in options) {
2079
2080 w = options.shape[0]
2081 h = options.shape[1]
2082 if (options.shape.length === 3) {
2083 c = options.shape[2]
2084
2085 hasChannels = true
2086 }
2087
2088
2089 } else {
2090 if ('radius' in options) {
2091 w = h = options.radius
2092
2093 }
2094 if ('width' in options) {
2095 w = options.width
2096
2097 }
2098 if ('height' in options) {
2099 h = options.height
2100
2101 }
2102 if ('channels' in options) {
2103 c = options.channels
2104
2105 hasChannels = true
2106 }
2107 }
2108 flags.width = w | 0
2109 flags.height = h | 0
2110 flags.channels = c | 0
2111
2112 var hasFormat = false
2113 if ('format' in options) {
2114 var formatStr = options.format
2115
2116
2117 var internalformat = flags.internalformat = textureFormats[formatStr]
2118 flags.format = colorFormats[internalformat]
2119 if (formatStr in textureTypes) {
2120 if (!('type' in options)) {
2121 flags.type = textureTypes[formatStr]
2122 }
2123 }
2124 if (formatStr in compressedTextureFormats) {
2125 flags.compressed = true
2126 }
2127 hasFormat = true
2128 }
2129
2130 // Reconcile channels and format
2131 if (!hasChannels && hasFormat) {
2132 flags.channels = FORMAT_CHANNELS[flags.format]
2133 } else if (hasChannels && !hasFormat) {
2134 if (flags.channels !== CHANNELS_FORMAT[flags.format]) {
2135 flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels]
2136 }
2137 } else if (hasFormat && hasChannels) {
2138
2139 }
2140 }
2141
2142 function setFlags (flags) {
2143 gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY)
2144 gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha)
2145 gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace)
2146 gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment)
2147 }
2148
2149 // -------------------------------------------------------
2150 // Tex image data
2151 // -------------------------------------------------------
2152 function TexImage () {
2153 TexFlags.call(this)
2154
2155 this.xOffset = 0
2156 this.yOffset = 0
2157
2158 // data
2159 this.data = null
2160 this.needsFree = false
2161
2162 // html element
2163 this.element = null
2164
2165 // copyTexImage info
2166 this.needsCopy = false
2167 }
2168
2169 function parseImage (image, options) {
2170 var data = null
2171 if (isPixelData(options)) {
2172 data = options
2173 } else if (options) {
2174
2175 parseFlags(image, options)
2176 if ('x' in options) {
2177 image.xOffset = options.x | 0
2178 }
2179 if ('y' in options) {
2180 image.yOffset = options.y | 0
2181 }
2182 if (isPixelData(options.data)) {
2183 data = options.data
2184 }
2185 }
2186
2187
2188
2189 if (options.copy) {
2190
2191 var viewW = contextState.viewportWidth
2192 var viewH = contextState.viewportHeight
2193 image.width = image.width || (viewW - image.xOffset)
2194 image.height = image.height || (viewH - image.yOffset)
2195 image.needsCopy = true
2196
2197 } else if (!data) {
2198 image.width = image.width || 1
2199 image.height = image.height || 1
2200 image.channels = image.channels || 4
2201 } else if (isTypedArray(data)) {
2202 image.channels = image.channels || 4
2203 image.data = data
2204 if (!('type' in options) && image.type === GL_UNSIGNED_BYTE$4) {
2205 image.type = typedArrayCode$1(data)
2206 }
2207 } else if (isNumericArray(data)) {
2208 image.channels = image.channels || 4
2209 convertData(image, data)
2210 image.alignment = 1
2211 image.needsFree = true
2212 } else if (isNDArrayLike(data)) {
2213 var array = data.data
2214 if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE$4) {
2215 image.type = typedArrayCode$1(array)
2216 }
2217 var shape = data.shape
2218 var stride = data.stride
2219 var shapeX, shapeY, shapeC, strideX, strideY, strideC
2220 if (shape.length === 3) {
2221 shapeC = shape[2]
2222 strideC = stride[2]
2223 } else {
2224
2225 shapeC = 1
2226 strideC = 1
2227 }
2228 shapeX = shape[0]
2229 shapeY = shape[1]
2230 strideX = stride[0]
2231 strideY = stride[1]
2232 image.alignment = 1
2233 image.width = shapeX
2234 image.height = shapeY
2235 image.channels = shapeC
2236 image.format = image.internalformat = CHANNELS_FORMAT[shapeC]
2237 image.needsFree = true
2238 transposeData(image, array, strideX, strideY, strideC, data.offset)
2239 } else if (isCanvasElement(data) || isOffscreenCanvas(data) || isContext2D(data)) {
2240 if (isCanvasElement(data) || isOffscreenCanvas(data)) {
2241 image.element = data
2242 } else {
2243 image.element = data.canvas
2244 }
2245 image.width = image.element.width
2246 image.height = image.element.height
2247 image.channels = 4
2248 } else if (isBitmap(data)) {
2249 image.element = data
2250 image.width = data.width
2251 image.height = data.height
2252 image.channels = 4
2253 } else if (isImageElement(data)) {
2254 image.element = data
2255 image.width = data.naturalWidth
2256 image.height = data.naturalHeight
2257 image.channels = 4
2258 } else if (isVideoElement(data)) {
2259 image.element = data
2260 image.width = data.videoWidth
2261 image.height = data.videoHeight
2262 image.channels = 4
2263 } else if (isRectArray(data)) {
2264 var w = image.width || data[0].length
2265 var h = image.height || data.length
2266 var c = image.channels
2267 if (isArrayLike(data[0][0])) {
2268 c = c || data[0][0].length
2269 } else {
2270 c = c || 1
2271 }
2272 var arrayShape = flattenUtils.shape(data)
2273 var n = 1
2274 for (var dd = 0; dd < arrayShape.length; ++dd) {
2275 n *= arrayShape[dd]
2276 }
2277 var allocData = preConvert(image, n)
2278 flattenUtils.flatten(data, arrayShape, '', allocData)
2279 postConvert(image, allocData)
2280 image.alignment = 1
2281 image.width = w
2282 image.height = h
2283 image.channels = c
2284 image.format = image.internalformat = CHANNELS_FORMAT[c]
2285 image.needsFree = true
2286 }
2287
2288 if (image.type === GL_FLOAT$3) {
2289
2290 } else if (image.type === GL_HALF_FLOAT_OES) {
2291
2292 }
2293
2294 // do compressed texture validation here.
2295 }
2296
2297 function setImage (info, target, miplevel) {
2298 var element = info.element
2299 var data = info.data
2300 var internalformat = info.internalformat
2301 var format = info.format
2302 var type = info.type
2303 var width = info.width
2304 var height = info.height
2305
2306 setFlags(info)
2307
2308 if (element) {
2309 gl.texImage2D(target, miplevel, format, format, type, element)
2310 } else if (info.compressed) {
2311 gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data)
2312 } else if (info.needsCopy) {
2313 reglPoll()
2314 gl.copyTexImage2D(
2315 target, miplevel, format, info.xOffset, info.yOffset, width, height, 0)
2316 } else {
2317 gl.texImage2D(target, miplevel, format, width, height, 0, format, type, data || null)
2318 }
2319 }
2320
2321 function setSubImage (info, target, x, y, miplevel) {
2322 var element = info.element
2323 var data = info.data
2324 var internalformat = info.internalformat
2325 var format = info.format
2326 var type = info.type
2327 var width = info.width
2328 var height = info.height
2329
2330 setFlags(info)
2331
2332 if (element) {
2333 gl.texSubImage2D(
2334 target, miplevel, x, y, format, type, element)
2335 } else if (info.compressed) {
2336 gl.compressedTexSubImage2D(
2337 target, miplevel, x, y, internalformat, width, height, data)
2338 } else if (info.needsCopy) {
2339 reglPoll()
2340 gl.copyTexSubImage2D(
2341 target, miplevel, x, y, info.xOffset, info.yOffset, width, height)
2342 } else {
2343 gl.texSubImage2D(
2344 target, miplevel, x, y, width, height, format, type, data)
2345 }
2346 }
2347
2348 // texImage pool
2349 var imagePool = []
2350
2351 function allocImage () {
2352 return imagePool.pop() || new TexImage()
2353 }
2354
2355 function freeImage (image) {
2356 if (image.needsFree) {
2357 pool.freeType(image.data)
2358 }
2359 TexImage.call(image)
2360 imagePool.push(image)
2361 }
2362
2363 // -------------------------------------------------------
2364 // Mip map
2365 // -------------------------------------------------------
2366 function MipMap () {
2367 TexFlags.call(this)
2368
2369 this.genMipmaps = false
2370 this.mipmapHint = GL_DONT_CARE
2371 this.mipmask = 0
2372 this.images = Array(16)
2373 }
2374
2375 function parseMipMapFromShape (mipmap, width, height) {
2376 var img = mipmap.images[0] = allocImage()
2377 mipmap.mipmask = 1
2378 img.width = mipmap.width = width
2379 img.height = mipmap.height = height
2380 img.channels = mipmap.channels = 4
2381 }
2382
2383 function parseMipMapFromObject (mipmap, options) {
2384 var imgData = null
2385 if (isPixelData(options)) {
2386 imgData = mipmap.images[0] = allocImage()
2387 copyFlags(imgData, mipmap)
2388 parseImage(imgData, options)
2389 mipmap.mipmask = 1
2390 } else {
2391 parseFlags(mipmap, options)
2392 if (Array.isArray(options.mipmap)) {
2393 var mipData = options.mipmap
2394 for (var i = 0; i < mipData.length; ++i) {
2395 imgData = mipmap.images[i] = allocImage()
2396 copyFlags(imgData, mipmap)
2397 imgData.width >>= i
2398 imgData.height >>= i
2399 parseImage(imgData, mipData[i])
2400 mipmap.mipmask |= (1 << i)
2401 }
2402 } else {
2403 imgData = mipmap.images[0] = allocImage()
2404 copyFlags(imgData, mipmap)
2405 parseImage(imgData, options)
2406 mipmap.mipmask = 1
2407 }
2408 }
2409 copyFlags(mipmap, mipmap.images[0])
2410
2411 // For textures of the compressed format WEBGL_compressed_texture_s3tc
2412 // we must have that
2413 //
2414 // "When level equals zero width and height must be a multiple of 4.
2415 // When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. "
2416 //
2417 // but we do not yet support having multiple mipmap levels for compressed textures,
2418 // so we only test for level zero.
2419
2420 if (
2421 mipmap.compressed &&
2422 (
2423 mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
2424 mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
2425 mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
2426 mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
2427 )
2428 ) {
2429
2430 }
2431 }
2432
2433 function setMipMap (mipmap, target) {
2434 var images = mipmap.images
2435 for (var i = 0; i < images.length; ++i) {
2436 if (!images[i]) {
2437 return
2438 }
2439 setImage(images[i], target, i)
2440 }
2441 }
2442
2443 var mipPool = []
2444
2445 function allocMipMap () {
2446 var result = mipPool.pop() || new MipMap()
2447 TexFlags.call(result)
2448 result.mipmask = 0
2449 for (var i = 0; i < 16; ++i) {
2450 result.images[i] = null
2451 }
2452 return result
2453 }
2454
2455 function freeMipMap (mipmap) {
2456 var images = mipmap.images
2457 for (var i = 0; i < images.length; ++i) {
2458 if (images[i]) {
2459 freeImage(images[i])
2460 }
2461 images[i] = null
2462 }
2463 mipPool.push(mipmap)
2464 }
2465
2466 // -------------------------------------------------------
2467 // Tex info
2468 // -------------------------------------------------------
2469 function TexInfo () {
2470 this.minFilter = GL_NEAREST
2471 this.magFilter = GL_NEAREST
2472
2473 this.wrapS = GL_CLAMP_TO_EDGE
2474 this.wrapT = GL_CLAMP_TO_EDGE
2475
2476 this.anisotropic = 1
2477
2478 this.genMipmaps = false
2479 this.mipmapHint = GL_DONT_CARE
2480 }
2481
2482 function parseTexInfo (info, options) {
2483 if ('min' in options) {
2484 var minFilter = options.min
2485
2486 info.minFilter = minFilters[minFilter]
2487 if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0 && !('faces' in options)) {
2488 info.genMipmaps = true
2489 }
2490 }
2491
2492 if ('mag' in options) {
2493 var magFilter = options.mag
2494
2495 info.magFilter = magFilters[magFilter]
2496 }
2497
2498 var wrapS = info.wrapS
2499 var wrapT = info.wrapT
2500 if ('wrap' in options) {
2501 var wrap = options.wrap
2502 if (typeof wrap === 'string') {
2503
2504 wrapS = wrapT = wrapModes[wrap]
2505 } else if (Array.isArray(wrap)) {
2506
2507
2508 wrapS = wrapModes[wrap[0]]
2509 wrapT = wrapModes[wrap[1]]
2510 }
2511 } else {
2512 if ('wrapS' in options) {
2513 var optWrapS = options.wrapS
2514
2515 wrapS = wrapModes[optWrapS]
2516 }
2517 if ('wrapT' in options) {
2518 var optWrapT = options.wrapT
2519
2520 wrapT = wrapModes[optWrapT]
2521 }
2522 }
2523 info.wrapS = wrapS
2524 info.wrapT = wrapT
2525
2526 if ('anisotropic' in options) {
2527 var anisotropic = options.anisotropic
2528
2529 info.anisotropic = options.anisotropic
2530 }
2531
2532 if ('mipmap' in options) {
2533 var hasMipMap = false
2534 switch (typeof options.mipmap) {
2535 case 'string':
2536
2537 info.mipmapHint = mipmapHint[options.mipmap]
2538 info.genMipmaps = true
2539 hasMipMap = true
2540 break
2541
2542 case 'boolean':
2543 hasMipMap = info.genMipmaps = options.mipmap
2544 break
2545
2546 case 'object':
2547
2548 info.genMipmaps = false
2549 hasMipMap = true
2550 break
2551
2552 default:
2553
2554 }
2555 if (hasMipMap && !('min' in options)) {
2556 info.minFilter = GL_NEAREST_MIPMAP_NEAREST
2557 }
2558 }
2559 }
2560
2561 function setTexInfo (info, target) {
2562 gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter)
2563 gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter)
2564 gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS)
2565 gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT)
2566 if (extensions.ext_texture_filter_anisotropic) {
2567 gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic)
2568 }
2569 if (info.genMipmaps) {
2570 gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint)
2571 gl.generateMipmap(target)
2572 }
2573 }
2574
2575 // -------------------------------------------------------
2576 // Full texture object
2577 // -------------------------------------------------------
2578 var textureCount = 0
2579 var textureSet = {}
2580 var numTexUnits = limits.maxTextureUnits
2581 var textureUnits = Array(numTexUnits).map(function () {
2582 return null
2583 })
2584
2585 function REGLTexture (target) {
2586 TexFlags.call(this)
2587 this.mipmask = 0
2588 this.internalformat = GL_RGBA$1
2589
2590 this.id = textureCount++
2591
2592 this.refCount = 1
2593
2594 this.target = target
2595 this.texture = gl.createTexture()
2596
2597 this.unit = -1
2598 this.bindCount = 0
2599
2600 this.texInfo = new TexInfo()
2601
2602 if (config.profile) {
2603 this.stats = { size: 0 }
2604 }
2605 }
2606
2607 function tempBind (texture) {
2608 gl.activeTexture(GL_TEXTURE0$1)
2609 gl.bindTexture(texture.target, texture.texture)
2610 }
2611
2612 function tempRestore () {
2613 var prev = textureUnits[0]
2614 if (prev) {
2615 gl.bindTexture(prev.target, prev.texture)
2616 } else {
2617 gl.bindTexture(GL_TEXTURE_2D$1, null)
2618 }
2619 }
2620
2621 function destroy (texture) {
2622 var handle = texture.texture
2623
2624 var unit = texture.unit
2625 var target = texture.target
2626 if (unit >= 0) {
2627 gl.activeTexture(GL_TEXTURE0$1 + unit)
2628 gl.bindTexture(target, null)
2629 textureUnits[unit] = null
2630 }
2631 gl.deleteTexture(handle)
2632 texture.texture = null
2633 texture.params = null
2634 texture.pixels = null
2635 texture.refCount = 0
2636 delete textureSet[texture.id]
2637 stats.textureCount--
2638 }
2639
2640 extend(REGLTexture.prototype, {
2641 bind: function () {
2642 var texture = this
2643 texture.bindCount += 1
2644 var unit = texture.unit
2645 if (unit < 0) {
2646 for (var i = 0; i < numTexUnits; ++i) {
2647 var other = textureUnits[i]
2648 if (other) {
2649 if (other.bindCount > 0) {
2650 continue
2651 }
2652 other.unit = -1
2653 }
2654 textureUnits[i] = texture
2655 unit = i
2656 break
2657 }
2658 if (unit >= numTexUnits) {
2659
2660 }
2661 if (config.profile && stats.maxTextureUnits < (unit + 1)) {
2662 stats.maxTextureUnits = unit + 1 // +1, since the units are zero-based
2663 }
2664 texture.unit = unit
2665 gl.activeTexture(GL_TEXTURE0$1 + unit)
2666 gl.bindTexture(texture.target, texture.texture)
2667 }
2668 return unit
2669 },
2670
2671 unbind: function () {
2672 this.bindCount -= 1
2673 },
2674
2675 decRef: function () {
2676 if (--this.refCount <= 0) {
2677 destroy(this)
2678 }
2679 }
2680 })
2681
2682 function createTexture2D (a, b) {
2683 var texture = new REGLTexture(GL_TEXTURE_2D$1)
2684 textureSet[texture.id] = texture
2685 stats.textureCount++
2686
2687 function reglTexture2D (a, b) {
2688 var texInfo = texture.texInfo
2689 TexInfo.call(texInfo)
2690 var mipData = allocMipMap()
2691
2692 if (typeof a === 'number') {
2693 if (typeof b === 'number') {
2694 parseMipMapFromShape(mipData, a | 0, b | 0)
2695 } else {
2696 parseMipMapFromShape(mipData, a | 0, a | 0)
2697 }
2698 } else if (a) {
2699
2700 parseTexInfo(texInfo, a)
2701 parseMipMapFromObject(mipData, a)
2702 } else {
2703 // empty textures get assigned a default shape of 1x1
2704 parseMipMapFromShape(mipData, 1, 1)
2705 }
2706
2707 if (texInfo.genMipmaps) {
2708 mipData.mipmask = (mipData.width << 1) - 1
2709 }
2710 texture.mipmask = mipData.mipmask
2711
2712 copyFlags(texture, mipData)
2713
2714
2715 texture.internalformat = mipData.internalformat
2716
2717 reglTexture2D.width = mipData.width
2718 reglTexture2D.height = mipData.height
2719
2720 tempBind(texture)
2721 setMipMap(mipData, GL_TEXTURE_2D$1)
2722 setTexInfo(texInfo, GL_TEXTURE_2D$1)
2723 tempRestore()
2724
2725 freeMipMap(mipData)
2726
2727 if (config.profile) {
2728 texture.stats.size = getTextureSize(
2729 texture.internalformat,
2730 texture.type,
2731 mipData.width,
2732 mipData.height,
2733 texInfo.genMipmaps,
2734 false)
2735 }
2736 reglTexture2D.format = textureFormatsInvert[texture.internalformat]
2737 reglTexture2D.type = textureTypesInvert[texture.type]
2738
2739 reglTexture2D.mag = magFiltersInvert[texInfo.magFilter]
2740 reglTexture2D.min = minFiltersInvert[texInfo.minFilter]
2741
2742 reglTexture2D.wrapS = wrapModesInvert[texInfo.wrapS]
2743 reglTexture2D.wrapT = wrapModesInvert[texInfo.wrapT]
2744
2745 return reglTexture2D
2746 }
2747
2748 function subimage (image, x_, y_, level_) {
2749
2750
2751 var x = x_ | 0
2752 var y = y_ | 0
2753 var level = level_ | 0
2754
2755 var imageData = allocImage()
2756 copyFlags(imageData, texture)
2757 imageData.width = 0
2758 imageData.height = 0
2759 parseImage(imageData, image)
2760 imageData.width = imageData.width || ((texture.width >> level) - x)
2761 imageData.height = imageData.height || ((texture.height >> level) - y)
2762
2763
2764
2765
2766
2767
2768 tempBind(texture)
2769 setSubImage(imageData, GL_TEXTURE_2D$1, x, y, level)
2770 tempRestore()
2771
2772 freeImage(imageData)
2773
2774 return reglTexture2D
2775 }
2776
2777 function resize (w_, h_) {
2778 var w = w_ | 0
2779 var h = (h_ | 0) || w
2780 if (w === texture.width && h === texture.height) {
2781 return reglTexture2D
2782 }
2783
2784 reglTexture2D.width = texture.width = w
2785 reglTexture2D.height = texture.height = h
2786
2787 tempBind(texture)
2788
2789 for (var i = 0; texture.mipmask >> i; ++i) {
2790 var _w = w >> i
2791 var _h = h >> i
2792 if (!_w || !_h) break
2793 gl.texImage2D(
2794 GL_TEXTURE_2D$1,
2795 i,
2796 texture.format,
2797 _w,
2798 _h,
2799 0,
2800 texture.format,
2801 texture.type,
2802 null)
2803 }
2804 tempRestore()
2805
2806 // also, recompute the texture size.
2807 if (config.profile) {
2808 texture.stats.size = getTextureSize(
2809 texture.internalformat,
2810 texture.type,
2811 w,
2812 h,
2813 false,
2814 false)
2815 }
2816
2817 return reglTexture2D
2818 }
2819
2820 reglTexture2D(a, b)
2821
2822 reglTexture2D.subimage = subimage
2823 reglTexture2D.resize = resize
2824 reglTexture2D._reglType = 'texture2d'
2825 reglTexture2D._texture = texture
2826 if (config.profile) {
2827 reglTexture2D.stats = texture.stats
2828 }
2829 reglTexture2D.destroy = function () {
2830 texture.decRef()
2831 }
2832
2833 return reglTexture2D
2834 }
2835
2836 function createTextureCube (a0, a1, a2, a3, a4, a5) {
2837 var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP$1)
2838 textureSet[texture.id] = texture
2839 stats.cubeCount++
2840
2841 var faces = new Array(6)
2842
2843 function reglTextureCube (a0, a1, a2, a3, a4, a5) {
2844 var i
2845 var texInfo = texture.texInfo
2846 TexInfo.call(texInfo)
2847 for (i = 0; i < 6; ++i) {
2848 faces[i] = allocMipMap()
2849 }
2850
2851 if (typeof a0 === 'number' || !a0) {
2852 var s = (a0 | 0) || 1
2853 for (i = 0; i < 6; ++i) {
2854 parseMipMapFromShape(faces[i], s, s)
2855 }
2856 } else if (typeof a0 === 'object') {
2857 if (a1) {
2858 parseMipMapFromObject(faces[0], a0)
2859 parseMipMapFromObject(faces[1], a1)
2860 parseMipMapFromObject(faces[2], a2)
2861 parseMipMapFromObject(faces[3], a3)
2862 parseMipMapFromObject(faces[4], a4)
2863 parseMipMapFromObject(faces[5], a5)
2864 } else {
2865 parseTexInfo(texInfo, a0)
2866 parseFlags(texture, a0)
2867 if ('faces' in a0) {
2868 var faceInput = a0.faces
2869
2870 for (i = 0; i < 6; ++i) {
2871
2872 copyFlags(faces[i], texture)
2873 parseMipMapFromObject(faces[i], faceInput[i])
2874 }
2875 } else {
2876 for (i = 0; i < 6; ++i) {
2877 parseMipMapFromObject(faces[i], a0)
2878 }
2879 }
2880 }
2881 } else {
2882
2883 }
2884
2885 copyFlags(texture, faces[0])
2886
2887 if (!limits.npotTextureCube) {
2888
2889 }
2890
2891 if (texInfo.genMipmaps) {
2892 texture.mipmask = (faces[0].width << 1) - 1
2893 } else {
2894 texture.mipmask = faces[0].mipmask
2895 }
2896
2897
2898 texture.internalformat = faces[0].internalformat
2899
2900 reglTextureCube.width = faces[0].width
2901 reglTextureCube.height = faces[0].height
2902
2903 tempBind(texture)
2904 for (i = 0; i < 6; ++i) {
2905 setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i)
2906 }
2907 setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP$1)
2908 tempRestore()
2909
2910 if (config.profile) {
2911 texture.stats.size = getTextureSize(
2912 texture.internalformat,
2913 texture.type,
2914 reglTextureCube.width,
2915 reglTextureCube.height,
2916 texInfo.genMipmaps,
2917 true)
2918 }
2919
2920 reglTextureCube.format = textureFormatsInvert[texture.internalformat]
2921 reglTextureCube.type = textureTypesInvert[texture.type]
2922
2923 reglTextureCube.mag = magFiltersInvert[texInfo.magFilter]
2924 reglTextureCube.min = minFiltersInvert[texInfo.minFilter]
2925
2926 reglTextureCube.wrapS = wrapModesInvert[texInfo.wrapS]
2927 reglTextureCube.wrapT = wrapModesInvert[texInfo.wrapT]
2928
2929 for (i = 0; i < 6; ++i) {
2930 freeMipMap(faces[i])
2931 }
2932
2933 return reglTextureCube
2934 }
2935
2936 function subimage (face, image, x_, y_, level_) {
2937
2938
2939
2940 var x = x_ | 0
2941 var y = y_ | 0
2942 var level = level_ | 0
2943
2944 var imageData = allocImage()
2945 copyFlags(imageData, texture)
2946 imageData.width = 0
2947 imageData.height = 0
2948 parseImage(imageData, image)
2949 imageData.width = imageData.width || ((texture.width >> level) - x)
2950 imageData.height = imageData.height || ((texture.height >> level) - y)
2951
2952
2953
2954
2955
2956
2957 tempBind(texture)
2958 setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + face, x, y, level)
2959 tempRestore()
2960
2961 freeImage(imageData)
2962
2963 return reglTextureCube
2964 }
2965
2966 function resize (radius_) {
2967 var radius = radius_ | 0
2968 if (radius === texture.width) {
2969 return
2970 }
2971
2972 reglTextureCube.width = texture.width = radius
2973 reglTextureCube.height = texture.height = radius
2974
2975 tempBind(texture)
2976 for (var i = 0; i < 6; ++i) {
2977 for (var j = 0; texture.mipmask >> j; ++j) {
2978 gl.texImage2D(
2979 GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i,
2980 j,
2981 texture.format,
2982 radius >> j,
2983 radius >> j,
2984 0,
2985 texture.format,
2986 texture.type,
2987 null)
2988 }
2989 }
2990 tempRestore()
2991
2992 if (config.profile) {
2993 texture.stats.size = getTextureSize(
2994 texture.internalformat,
2995 texture.type,
2996 reglTextureCube.width,
2997 reglTextureCube.height,
2998 false,
2999 true)
3000 }
3001
3002 return reglTextureCube
3003 }
3004
3005 reglTextureCube(a0, a1, a2, a3, a4, a5)
3006
3007 reglTextureCube.subimage = subimage
3008 reglTextureCube.resize = resize
3009 reglTextureCube._reglType = 'textureCube'
3010 reglTextureCube._texture = texture
3011 if (config.profile) {
3012 reglTextureCube.stats = texture.stats
3013 }
3014 reglTextureCube.destroy = function () {
3015 texture.decRef()
3016 }
3017
3018 return reglTextureCube
3019 }
3020
3021 // Called when regl is destroyed
3022 function destroyTextures () {
3023 for (var i = 0; i < numTexUnits; ++i) {
3024 gl.activeTexture(GL_TEXTURE0$1 + i)
3025 gl.bindTexture(GL_TEXTURE_2D$1, null)
3026 textureUnits[i] = null
3027 }
3028 values(textureSet).forEach(destroy)
3029
3030 stats.cubeCount = 0
3031 stats.textureCount = 0
3032 }
3033
3034 if (config.profile) {
3035 stats.getTotalTextureSize = function () {
3036 var total = 0
3037 Object.keys(textureSet).forEach(function (key) {
3038 total += textureSet[key].stats.size
3039 })
3040 return total
3041 }
3042 }
3043
3044 function restoreTextures () {
3045 for (var i = 0; i < numTexUnits; ++i) {
3046 var tex = textureUnits[i]
3047 if (tex) {
3048 tex.bindCount = 0
3049 tex.unit = -1
3050 textureUnits[i] = null
3051 }
3052 }
3053
3054 values(textureSet).forEach(function (texture) {
3055 texture.texture = gl.createTexture()
3056 gl.bindTexture(texture.target, texture.texture)
3057 for (var i = 0; i < 32; ++i) {
3058 if ((texture.mipmask & (1 << i)) === 0) {
3059 continue
3060 }
3061 if (texture.target === GL_TEXTURE_2D$1) {
3062 gl.texImage2D(GL_TEXTURE_2D$1,
3063 i,
3064 texture.internalformat,
3065 texture.width >> i,
3066 texture.height >> i,
3067 0,
3068 texture.internalformat,
3069 texture.type,
3070 null)
3071 } else {
3072 for (var j = 0; j < 6; ++j) {
3073 gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + j,
3074 i,
3075 texture.internalformat,
3076 texture.width >> i,
3077 texture.height >> i,
3078 0,
3079 texture.internalformat,
3080 texture.type,
3081 null)
3082 }
3083 }
3084 }
3085 setTexInfo(texture.texInfo, texture.target)
3086 })
3087 }
3088
3089 return {
3090 create2D: createTexture2D,
3091 createCube: createTextureCube,
3092 clear: destroyTextures,
3093 getTexture: function (wrapper) {
3094 return null
3095 },
3096 restore: restoreTextures
3097 }
3098}
3099
3100var GL_RENDERBUFFER = 0x8D41
3101
3102var GL_RGBA4$1 = 0x8056
3103var GL_RGB5_A1$1 = 0x8057
3104var GL_RGB565$1 = 0x8D62
3105var GL_DEPTH_COMPONENT16 = 0x81A5
3106var GL_STENCIL_INDEX8 = 0x8D48
3107var GL_DEPTH_STENCIL$1 = 0x84F9
3108
3109var GL_SRGB8_ALPHA8_EXT = 0x8C43
3110
3111var GL_RGBA32F_EXT = 0x8814
3112
3113var GL_RGBA16F_EXT = 0x881A
3114var GL_RGB16F_EXT = 0x881B
3115
3116var FORMAT_SIZES = []
3117
3118FORMAT_SIZES[GL_RGBA4$1] = 2
3119FORMAT_SIZES[GL_RGB5_A1$1] = 2
3120FORMAT_SIZES[GL_RGB565$1] = 2
3121
3122FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2
3123FORMAT_SIZES[GL_STENCIL_INDEX8] = 1
3124FORMAT_SIZES[GL_DEPTH_STENCIL$1] = 4
3125
3126FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4
3127FORMAT_SIZES[GL_RGBA32F_EXT] = 16
3128FORMAT_SIZES[GL_RGBA16F_EXT] = 8
3129FORMAT_SIZES[GL_RGB16F_EXT] = 6
3130
3131function getRenderbufferSize (format, width, height) {
3132 return FORMAT_SIZES[format] * width * height
3133}
3134
3135var wrapRenderbuffers = function (gl, extensions, limits, stats, config) {
3136 var formatTypes = {
3137 'rgba4': GL_RGBA4$1,
3138 'rgb565': GL_RGB565$1,
3139 'rgb5 a1': GL_RGB5_A1$1,
3140 'depth': GL_DEPTH_COMPONENT16,
3141 'stencil': GL_STENCIL_INDEX8,
3142 'depth stencil': GL_DEPTH_STENCIL$1
3143 }
3144
3145 if (extensions.ext_srgb) {
3146 formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT
3147 }
3148
3149 if (extensions.ext_color_buffer_half_float) {
3150 formatTypes['rgba16f'] = GL_RGBA16F_EXT
3151 formatTypes['rgb16f'] = GL_RGB16F_EXT
3152 }
3153
3154 if (extensions.webgl_color_buffer_float) {
3155 formatTypes['rgba32f'] = GL_RGBA32F_EXT
3156 }
3157
3158 var formatTypesInvert = []
3159 Object.keys(formatTypes).forEach(function (key) {
3160 var val = formatTypes[key]
3161 formatTypesInvert[val] = key
3162 })
3163
3164 var renderbufferCount = 0
3165 var renderbufferSet = {}
3166
3167 function REGLRenderbuffer (renderbuffer) {
3168 this.id = renderbufferCount++
3169 this.refCount = 1
3170
3171 this.renderbuffer = renderbuffer
3172
3173 this.format = GL_RGBA4$1
3174 this.width = 0
3175 this.height = 0
3176
3177 if (config.profile) {
3178 this.stats = { size: 0 }
3179 }
3180 }
3181
3182 REGLRenderbuffer.prototype.decRef = function () {
3183 if (--this.refCount <= 0) {
3184 destroy(this)
3185 }
3186 }
3187
3188 function destroy (rb) {
3189 var handle = rb.renderbuffer
3190
3191 gl.bindRenderbuffer(GL_RENDERBUFFER, null)
3192 gl.deleteRenderbuffer(handle)
3193 rb.renderbuffer = null
3194 rb.refCount = 0
3195 delete renderbufferSet[rb.id]
3196 stats.renderbufferCount--
3197 }
3198
3199 function createRenderbuffer (a, b) {
3200 var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer())
3201 renderbufferSet[renderbuffer.id] = renderbuffer
3202 stats.renderbufferCount++
3203
3204 function reglRenderbuffer (a, b) {
3205 var w = 0
3206 var h = 0
3207 var format = GL_RGBA4$1
3208
3209 if (typeof a === 'object' && a) {
3210 var options = a
3211 if ('shape' in options) {
3212 var shape = options.shape
3213
3214 w = shape[0] | 0
3215 h = shape[1] | 0
3216 } else {
3217 if ('radius' in options) {
3218 w = h = options.radius | 0
3219 }
3220 if ('width' in options) {
3221 w = options.width | 0
3222 }
3223 if ('height' in options) {
3224 h = options.height | 0
3225 }
3226 }
3227 if ('format' in options) {
3228
3229 format = formatTypes[options.format]
3230 }
3231 } else if (typeof a === 'number') {
3232 w = a | 0
3233 if (typeof b === 'number') {
3234 h = b | 0
3235 } else {
3236 h = w
3237 }
3238 } else if (!a) {
3239 w = h = 1
3240 } else {
3241
3242 }
3243
3244 // check shape
3245
3246
3247 if (w === renderbuffer.width &&
3248 h === renderbuffer.height &&
3249 format === renderbuffer.format) {
3250 return
3251 }
3252
3253 reglRenderbuffer.width = renderbuffer.width = w
3254 reglRenderbuffer.height = renderbuffer.height = h
3255 renderbuffer.format = format
3256
3257 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer)
3258 gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h)
3259
3260
3261
3262 if (config.profile) {
3263 renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height)
3264 }
3265 reglRenderbuffer.format = formatTypesInvert[renderbuffer.format]
3266
3267 return reglRenderbuffer
3268 }
3269
3270 function resize (w_, h_) {
3271 var w = w_ | 0
3272 var h = (h_ | 0) || w
3273
3274 if (w === renderbuffer.width && h === renderbuffer.height) {
3275 return reglRenderbuffer
3276 }
3277
3278 // check shape
3279
3280
3281 reglRenderbuffer.width = renderbuffer.width = w
3282 reglRenderbuffer.height = renderbuffer.height = h
3283
3284 gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer)
3285 gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h)
3286
3287
3288
3289 // also, recompute size.
3290 if (config.profile) {
3291 renderbuffer.stats.size = getRenderbufferSize(
3292 renderbuffer.format, renderbuffer.width, renderbuffer.height)
3293 }
3294
3295 return reglRenderbuffer
3296 }
3297
3298 reglRenderbuffer(a, b)
3299
3300 reglRenderbuffer.resize = resize
3301 reglRenderbuffer._reglType = 'renderbuffer'
3302 reglRenderbuffer._renderbuffer = renderbuffer
3303 if (config.profile) {
3304 reglRenderbuffer.stats = renderbuffer.stats
3305 }
3306 reglRenderbuffer.destroy = function () {
3307 renderbuffer.decRef()
3308 }
3309
3310 return reglRenderbuffer
3311 }
3312
3313 if (config.profile) {
3314 stats.getTotalRenderbufferSize = function () {
3315 var total = 0
3316 Object.keys(renderbufferSet).forEach(function (key) {
3317 total += renderbufferSet[key].stats.size
3318 })
3319 return total
3320 }
3321 }
3322
3323 function restoreRenderbuffers () {
3324 values(renderbufferSet).forEach(function (rb) {
3325 rb.renderbuffer = gl.createRenderbuffer()
3326 gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer)
3327 gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height)
3328 })
3329 gl.bindRenderbuffer(GL_RENDERBUFFER, null)
3330 }
3331
3332 return {
3333 create: createRenderbuffer,
3334 clear: function () {
3335 values(renderbufferSet).forEach(destroy)
3336 },
3337 restore: restoreRenderbuffers
3338 }
3339}
3340
3341// We store these constants so that the minifier can inline them
3342var GL_FRAMEBUFFER$1 = 0x8D40
3343var GL_RENDERBUFFER$1 = 0x8D41
3344
3345var GL_TEXTURE_2D$2 = 0x0DE1
3346var GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 = 0x8515
3347
3348var GL_COLOR_ATTACHMENT0$1 = 0x8CE0
3349var GL_DEPTH_ATTACHMENT = 0x8D00
3350var GL_STENCIL_ATTACHMENT = 0x8D20
3351var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A
3352
3353var GL_FRAMEBUFFER_COMPLETE$1 = 0x8CD5
3354var GL_HALF_FLOAT_OES$1 = 0x8D61
3355var GL_UNSIGNED_BYTE$5 = 0x1401
3356var GL_FLOAT$4 = 0x1406
3357
3358var GL_RGB$1 = 0x1907
3359var GL_RGBA$2 = 0x1908
3360
3361// for every texture format, store
3362// the number of channels
3363var textureFormatChannels = []
3364textureFormatChannels[GL_RGBA$2] = 4
3365textureFormatChannels[GL_RGB$1] = 3
3366
3367// for every texture type, store
3368// the size in bytes.
3369var textureTypeSizes = []
3370textureTypeSizes[GL_UNSIGNED_BYTE$5] = 1
3371textureTypeSizes[GL_FLOAT$4] = 4
3372textureTypeSizes[GL_HALF_FLOAT_OES$1] = 2
3373
3374function wrapFBOState (
3375 gl,
3376 extensions,
3377 limits,
3378 textureState,
3379 renderbufferState,
3380 stats) {
3381 var framebufferState = {
3382 cur: null,
3383 next: null,
3384 dirty: false,
3385 setFBO: null
3386 }
3387
3388 var colorTextureFormats = ['rgba']
3389 var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1']
3390
3391 if (extensions.ext_srgb) {
3392 colorRenderbufferFormats.push('srgba')
3393 }
3394
3395 if (extensions.ext_color_buffer_half_float) {
3396 colorRenderbufferFormats.push('rgba16f', 'rgb16f')
3397 }
3398
3399 if (extensions.webgl_color_buffer_float) {
3400 colorRenderbufferFormats.push('rgba32f')
3401 }
3402
3403 var colorTypes = ['uint8']
3404 if (extensions.oes_texture_half_float) {
3405 colorTypes.push('half float', 'float16')
3406 }
3407 if (extensions.oes_texture_float) {
3408 colorTypes.push('float', 'float32')
3409 }
3410
3411 function FramebufferAttachment (target, texture, renderbuffer) {
3412 this.target = target
3413 this.texture = texture
3414 this.renderbuffer = renderbuffer
3415
3416 var w = 0
3417 var h = 0
3418 if (texture) {
3419 w = texture.width
3420 h = texture.height
3421 } else if (renderbuffer) {
3422 w = renderbuffer.width
3423 h = renderbuffer.height
3424 }
3425 this.width = w
3426 this.height = h
3427 }
3428
3429 function decRef (attachment) {
3430 if (attachment) {
3431 if (attachment.texture) {
3432 attachment.texture._texture.decRef()
3433 }
3434 if (attachment.renderbuffer) {
3435 attachment.renderbuffer._renderbuffer.decRef()
3436 }
3437 }
3438 }
3439
3440 function incRefAndCheckShape (attachment, width, height) {
3441 if (!attachment) {
3442 return
3443 }
3444 if (attachment.texture) {
3445 var texture = attachment.texture._texture
3446 var tw = Math.max(1, texture.width)
3447 var th = Math.max(1, texture.height)
3448
3449 texture.refCount += 1
3450 } else {
3451 var renderbuffer = attachment.renderbuffer._renderbuffer
3452
3453 renderbuffer.refCount += 1
3454 }
3455 }
3456
3457 function attach (location, attachment) {
3458 if (attachment) {
3459 if (attachment.texture) {
3460 gl.framebufferTexture2D(
3461 GL_FRAMEBUFFER$1,
3462 location,
3463 attachment.target,
3464 attachment.texture._texture.texture,
3465 0)
3466 } else {
3467 gl.framebufferRenderbuffer(
3468 GL_FRAMEBUFFER$1,
3469 location,
3470 GL_RENDERBUFFER$1,
3471 attachment.renderbuffer._renderbuffer.renderbuffer)
3472 }
3473 }
3474 }
3475
3476 function parseAttachment (attachment) {
3477 var target = GL_TEXTURE_2D$2
3478 var texture = null
3479 var renderbuffer = null
3480
3481 var data = attachment
3482 if (typeof attachment === 'object') {
3483 data = attachment.data
3484 if ('target' in attachment) {
3485 target = attachment.target | 0
3486 }
3487 }
3488
3489
3490
3491 var type = data._reglType
3492 if (type === 'texture2d') {
3493 texture = data
3494
3495 } else if (type === 'textureCube') {
3496 texture = data
3497
3498 } else if (type === 'renderbuffer') {
3499 renderbuffer = data
3500 target = GL_RENDERBUFFER$1
3501 } else {
3502
3503 }
3504
3505 return new FramebufferAttachment(target, texture, renderbuffer)
3506 }
3507
3508 function allocAttachment (
3509 width,
3510 height,
3511 isTexture,
3512 format,
3513 type) {
3514 if (isTexture) {
3515 var texture = textureState.create2D({
3516 width: width,
3517 height: height,
3518 format: format,
3519 type: type
3520 })
3521 texture._texture.refCount = 0
3522 return new FramebufferAttachment(GL_TEXTURE_2D$2, texture, null)
3523 } else {
3524 var rb = renderbufferState.create({
3525 width: width,
3526 height: height,
3527 format: format
3528 })
3529 rb._renderbuffer.refCount = 0
3530 return new FramebufferAttachment(GL_RENDERBUFFER$1, null, rb)
3531 }
3532 }
3533
3534 function unwrapAttachment (attachment) {
3535 return attachment && (attachment.texture || attachment.renderbuffer)
3536 }
3537
3538 function resizeAttachment (attachment, w, h) {
3539 if (attachment) {
3540 if (attachment.texture) {
3541 attachment.texture.resize(w, h)
3542 } else if (attachment.renderbuffer) {
3543 attachment.renderbuffer.resize(w, h)
3544 }
3545 attachment.width = w
3546 attachment.height = h
3547 }
3548 }
3549
3550 var framebufferCount = 0
3551 var framebufferSet = {}
3552
3553 function REGLFramebuffer () {
3554 this.id = framebufferCount++
3555 framebufferSet[this.id] = this
3556
3557 this.framebuffer = gl.createFramebuffer()
3558 this.width = 0
3559 this.height = 0
3560
3561 this.colorAttachments = []
3562 this.depthAttachment = null
3563 this.stencilAttachment = null
3564 this.depthStencilAttachment = null
3565 }
3566
3567 function decFBORefs (framebuffer) {
3568 framebuffer.colorAttachments.forEach(decRef)
3569 decRef(framebuffer.depthAttachment)
3570 decRef(framebuffer.stencilAttachment)
3571 decRef(framebuffer.depthStencilAttachment)
3572 }
3573
3574 function destroy (framebuffer) {
3575 var handle = framebuffer.framebuffer
3576
3577 gl.deleteFramebuffer(handle)
3578 framebuffer.framebuffer = null
3579 stats.framebufferCount--
3580 delete framebufferSet[framebuffer.id]
3581 }
3582
3583 function updateFramebuffer (framebuffer) {
3584 var i
3585
3586 gl.bindFramebuffer(GL_FRAMEBUFFER$1, framebuffer.framebuffer)
3587 var colorAttachments = framebuffer.colorAttachments
3588 for (i = 0; i < colorAttachments.length; ++i) {
3589 attach(GL_COLOR_ATTACHMENT0$1 + i, colorAttachments[i])
3590 }
3591 for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) {
3592 gl.framebufferTexture2D(
3593 GL_FRAMEBUFFER$1,
3594 GL_COLOR_ATTACHMENT0$1 + i,
3595 GL_TEXTURE_2D$2,
3596 null,
3597 0)
3598 }
3599
3600 gl.framebufferTexture2D(
3601 GL_FRAMEBUFFER$1,
3602 GL_DEPTH_STENCIL_ATTACHMENT,
3603 GL_TEXTURE_2D$2,
3604 null,
3605 0)
3606 gl.framebufferTexture2D(
3607 GL_FRAMEBUFFER$1,
3608 GL_DEPTH_ATTACHMENT,
3609 GL_TEXTURE_2D$2,
3610 null,
3611 0)
3612 gl.framebufferTexture2D(
3613 GL_FRAMEBUFFER$1,
3614 GL_STENCIL_ATTACHMENT,
3615 GL_TEXTURE_2D$2,
3616 null,
3617 0)
3618
3619 attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment)
3620 attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment)
3621 attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment)
3622
3623 // Check status code
3624 var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER$1)
3625 if (!gl.isContextLost() && status !== GL_FRAMEBUFFER_COMPLETE$1) {
3626
3627 }
3628
3629 gl.bindFramebuffer(GL_FRAMEBUFFER$1, framebufferState.next ? framebufferState.next.framebuffer : null)
3630 framebufferState.cur = framebufferState.next
3631
3632 // FIXME: Clear error code here. This is a work around for a bug in
3633 // headless-gl
3634 gl.getError()
3635 }
3636
3637 function createFBO (a0, a1) {
3638 var framebuffer = new REGLFramebuffer()
3639 stats.framebufferCount++
3640
3641 function reglFramebuffer (a, b) {
3642 var i
3643
3644
3645
3646 var width = 0
3647 var height = 0
3648
3649 var needsDepth = true
3650 var needsStencil = true
3651
3652 var colorBuffer = null
3653 var colorTexture = true
3654 var colorFormat = 'rgba'
3655 var colorType = 'uint8'
3656 var colorCount = 1
3657
3658 var depthBuffer = null
3659 var stencilBuffer = null
3660 var depthStencilBuffer = null
3661 var depthStencilTexture = false
3662
3663 if (typeof a === 'number') {
3664 width = a | 0
3665 height = (b | 0) || width
3666 } else if (!a) {
3667 width = height = 1
3668 } else {
3669
3670 var options = a
3671
3672 if ('shape' in options) {
3673 var shape = options.shape
3674
3675 width = shape[0]
3676 height = shape[1]
3677 } else {
3678 if ('radius' in options) {
3679 width = height = options.radius
3680 }
3681 if ('width' in options) {
3682 width = options.width
3683 }
3684 if ('height' in options) {
3685 height = options.height
3686 }
3687 }
3688
3689 if ('color' in options ||
3690 'colors' in options) {
3691 colorBuffer =
3692 options.color ||
3693 options.colors
3694 if (Array.isArray(colorBuffer)) {
3695
3696 }
3697 }
3698
3699 if (!colorBuffer) {
3700 if ('colorCount' in options) {
3701 colorCount = options.colorCount | 0
3702
3703 }
3704
3705 if ('colorTexture' in options) {
3706 colorTexture = !!options.colorTexture
3707 colorFormat = 'rgba4'
3708 }
3709
3710 if ('colorType' in options) {
3711 colorType = options.colorType
3712 if (!colorTexture) {
3713 if (colorType === 'half float' || colorType === 'float16') {
3714
3715 colorFormat = 'rgba16f'
3716 } else if (colorType === 'float' || colorType === 'float32') {
3717
3718 colorFormat = 'rgba32f'
3719 }
3720 } else {
3721
3722
3723 }
3724
3725 }
3726
3727 if ('colorFormat' in options) {
3728 colorFormat = options.colorFormat
3729 if (colorTextureFormats.indexOf(colorFormat) >= 0) {
3730 colorTexture = true
3731 } else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) {
3732 colorTexture = false
3733 } else {
3734 if (colorTexture) {
3735
3736 } else {
3737
3738 }
3739 }
3740 }
3741 }
3742
3743 if ('depthTexture' in options || 'depthStencilTexture' in options) {
3744 depthStencilTexture = !!(options.depthTexture ||
3745 options.depthStencilTexture)
3746
3747 }
3748
3749 if ('depth' in options) {
3750 if (typeof options.depth === 'boolean') {
3751 needsDepth = options.depth
3752 } else {
3753 depthBuffer = options.depth
3754 needsStencil = false
3755 }
3756 }
3757
3758 if ('stencil' in options) {
3759 if (typeof options.stencil === 'boolean') {
3760 needsStencil = options.stencil
3761 } else {
3762 stencilBuffer = options.stencil
3763 needsDepth = false
3764 }
3765 }
3766
3767 if ('depthStencil' in options) {
3768 if (typeof options.depthStencil === 'boolean') {
3769 needsDepth = needsStencil = options.depthStencil
3770 } else {
3771 depthStencilBuffer = options.depthStencil
3772 needsDepth = false
3773 needsStencil = false
3774 }
3775 }
3776 }
3777
3778 // parse attachments
3779 var colorAttachments = null
3780 var depthAttachment = null
3781 var stencilAttachment = null
3782 var depthStencilAttachment = null
3783
3784 // Set up color attachments
3785 if (Array.isArray(colorBuffer)) {
3786 colorAttachments = colorBuffer.map(parseAttachment)
3787 } else if (colorBuffer) {
3788 colorAttachments = [parseAttachment(colorBuffer)]
3789 } else {
3790 colorAttachments = new Array(colorCount)
3791 for (i = 0; i < colorCount; ++i) {
3792 colorAttachments[i] = allocAttachment(
3793 width,
3794 height,
3795 colorTexture,
3796 colorFormat,
3797 colorType)
3798 }
3799 }
3800
3801
3802
3803
3804 width = width || colorAttachments[0].width
3805 height = height || colorAttachments[0].height
3806
3807 if (depthBuffer) {
3808 depthAttachment = parseAttachment(depthBuffer)
3809 } else if (needsDepth && !needsStencil) {
3810 depthAttachment = allocAttachment(
3811 width,
3812 height,
3813 depthStencilTexture,
3814 'depth',
3815 'uint32')
3816 }
3817
3818 if (stencilBuffer) {
3819 stencilAttachment = parseAttachment(stencilBuffer)
3820 } else if (needsStencil && !needsDepth) {
3821 stencilAttachment = allocAttachment(
3822 width,
3823 height,
3824 false,
3825 'stencil',
3826 'uint8')
3827 }
3828
3829 if (depthStencilBuffer) {
3830 depthStencilAttachment = parseAttachment(depthStencilBuffer)
3831 } else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) {
3832 depthStencilAttachment = allocAttachment(
3833 width,
3834 height,
3835 depthStencilTexture,
3836 'depth stencil',
3837 'depth stencil')
3838 }
3839
3840
3841
3842 var commonColorAttachmentSize = null
3843
3844 for (i = 0; i < colorAttachments.length; ++i) {
3845 incRefAndCheckShape(colorAttachments[i], width, height)
3846
3847
3848 if (colorAttachments[i] && colorAttachments[i].texture) {
3849 var colorAttachmentSize =
3850 textureFormatChannels[colorAttachments[i].texture._texture.format] *
3851 textureTypeSizes[colorAttachments[i].texture._texture.type]
3852
3853 if (commonColorAttachmentSize === null) {
3854 commonColorAttachmentSize = colorAttachmentSize
3855 } else {
3856 // We need to make sure that all color attachments have the same number of bitplanes
3857 // (that is, the same numer of bits per pixel)
3858 // This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document.
3859
3860 }
3861 }
3862 }
3863 incRefAndCheckShape(depthAttachment, width, height)
3864
3865 incRefAndCheckShape(stencilAttachment, width, height)
3866
3867 incRefAndCheckShape(depthStencilAttachment, width, height)
3868
3869
3870 // decrement references
3871 decFBORefs(framebuffer)
3872
3873 framebuffer.width = width
3874 framebuffer.height = height
3875
3876 framebuffer.colorAttachments = colorAttachments
3877 framebuffer.depthAttachment = depthAttachment
3878 framebuffer.stencilAttachment = stencilAttachment
3879 framebuffer.depthStencilAttachment = depthStencilAttachment
3880
3881 reglFramebuffer.color = colorAttachments.map(unwrapAttachment)
3882 reglFramebuffer.depth = unwrapAttachment(depthAttachment)
3883 reglFramebuffer.stencil = unwrapAttachment(stencilAttachment)
3884 reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment)
3885
3886 reglFramebuffer.width = framebuffer.width
3887 reglFramebuffer.height = framebuffer.height
3888
3889 updateFramebuffer(framebuffer)
3890
3891 return reglFramebuffer
3892 }
3893
3894 function resize (w_, h_) {
3895
3896
3897 var w = Math.max(w_ | 0, 1)
3898 var h = Math.max((h_ | 0) || w, 1)
3899 if (w === framebuffer.width && h === framebuffer.height) {
3900 return reglFramebuffer
3901 }
3902
3903 // resize all buffers
3904 var colorAttachments = framebuffer.colorAttachments
3905 for (var i = 0; i < colorAttachments.length; ++i) {
3906 resizeAttachment(colorAttachments[i], w, h)
3907 }
3908 resizeAttachment(framebuffer.depthAttachment, w, h)
3909 resizeAttachment(framebuffer.stencilAttachment, w, h)
3910 resizeAttachment(framebuffer.depthStencilAttachment, w, h)
3911
3912 framebuffer.width = reglFramebuffer.width = w
3913 framebuffer.height = reglFramebuffer.height = h
3914
3915 updateFramebuffer(framebuffer)
3916
3917 return reglFramebuffer
3918 }
3919
3920 reglFramebuffer(a0, a1)
3921
3922 return extend(reglFramebuffer, {
3923 resize: resize,
3924 _reglType: 'framebuffer',
3925 _framebuffer: framebuffer,
3926 destroy: function () {
3927 destroy(framebuffer)
3928 decFBORefs(framebuffer)
3929 },
3930 use: function (block) {
3931 framebufferState.setFBO({
3932 framebuffer: reglFramebuffer
3933 }, block)
3934 }
3935 })
3936 }
3937
3938 function createCubeFBO (options) {
3939 var faces = Array(6)
3940
3941 function reglFramebufferCube (a) {
3942 var i
3943
3944
3945
3946 var params = {
3947 color: null
3948 }
3949
3950 var radius = 0
3951
3952 var colorBuffer = null
3953 var colorFormat = 'rgba'
3954 var colorType = 'uint8'
3955 var colorCount = 1
3956
3957 if (typeof a === 'number') {
3958 radius = a | 0
3959 } else if (!a) {
3960 radius = 1
3961 } else {
3962
3963 var options = a
3964
3965 if ('shape' in options) {
3966 var shape = options.shape
3967
3968
3969 radius = shape[0]
3970 } else {
3971 if ('radius' in options) {
3972 radius = options.radius | 0
3973 }
3974 if ('width' in options) {
3975 radius = options.width | 0
3976 if ('height' in options) {
3977
3978 }
3979 } else if ('height' in options) {
3980 radius = options.height | 0
3981 }
3982 }
3983
3984 if ('color' in options ||
3985 'colors' in options) {
3986 colorBuffer =
3987 options.color ||
3988 options.colors
3989 if (Array.isArray(colorBuffer)) {
3990
3991 }
3992 }
3993
3994 if (!colorBuffer) {
3995 if ('colorCount' in options) {
3996 colorCount = options.colorCount | 0
3997
3998 }
3999
4000 if ('colorType' in options) {
4001
4002 colorType = options.colorType
4003 }
4004
4005 if ('colorFormat' in options) {
4006 colorFormat = options.colorFormat
4007
4008 }
4009 }
4010
4011 if ('depth' in options) {
4012 params.depth = options.depth
4013 }
4014
4015 if ('stencil' in options) {
4016 params.stencil = options.stencil
4017 }
4018
4019 if ('depthStencil' in options) {
4020 params.depthStencil = options.depthStencil
4021 }
4022 }
4023
4024 var colorCubes
4025 if (colorBuffer) {
4026 if (Array.isArray(colorBuffer)) {
4027 colorCubes = []
4028 for (i = 0; i < colorBuffer.length; ++i) {
4029 colorCubes[i] = colorBuffer[i]
4030 }
4031 } else {
4032 colorCubes = [ colorBuffer ]
4033 }
4034 } else {
4035 colorCubes = Array(colorCount)
4036 var cubeMapParams = {
4037 radius: radius,
4038 format: colorFormat,
4039 type: colorType
4040 }
4041 for (i = 0; i < colorCount; ++i) {
4042 colorCubes[i] = textureState.createCube(cubeMapParams)
4043 }
4044 }
4045
4046 // Check color cubes
4047 params.color = Array(colorCubes.length)
4048 for (i = 0; i < colorCubes.length; ++i) {
4049 var cube = colorCubes[i]
4050
4051 radius = radius || cube.width
4052
4053 params.color[i] = {
4054 target: GL_TEXTURE_CUBE_MAP_POSITIVE_X$2,
4055 data: colorCubes[i]
4056 }
4057 }
4058
4059 for (i = 0; i < 6; ++i) {
4060 for (var j = 0; j < colorCubes.length; ++j) {
4061 params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X$2 + i
4062 }
4063 // reuse depth-stencil attachments across all cube maps
4064 if (i > 0) {
4065 params.depth = faces[0].depth
4066 params.stencil = faces[0].stencil
4067 params.depthStencil = faces[0].depthStencil
4068 }
4069 if (faces[i]) {
4070 (faces[i])(params)
4071 } else {
4072 faces[i] = createFBO(params)
4073 }
4074 }
4075
4076 return extend(reglFramebufferCube, {
4077 width: radius,
4078 height: radius,
4079 color: colorCubes
4080 })
4081 }
4082
4083 function resize (radius_) {
4084 var i
4085 var radius = radius_ | 0
4086
4087
4088 if (radius === reglFramebufferCube.width) {
4089 return reglFramebufferCube
4090 }
4091
4092 var colors = reglFramebufferCube.color
4093 for (i = 0; i < colors.length; ++i) {
4094 colors[i].resize(radius)
4095 }
4096
4097 for (i = 0; i < 6; ++i) {
4098 faces[i].resize(radius)
4099 }
4100
4101 reglFramebufferCube.width = reglFramebufferCube.height = radius
4102
4103 return reglFramebufferCube
4104 }
4105
4106 reglFramebufferCube(options)
4107
4108 return extend(reglFramebufferCube, {
4109 faces: faces,
4110 resize: resize,
4111 _reglType: 'framebufferCube',
4112 destroy: function () {
4113 faces.forEach(function (f) {
4114 f.destroy()
4115 })
4116 }
4117 })
4118 }
4119
4120 function restoreFramebuffers () {
4121 framebufferState.cur = null
4122 framebufferState.next = null
4123 framebufferState.dirty = true
4124 values(framebufferSet).forEach(function (fb) {
4125 fb.framebuffer = gl.createFramebuffer()
4126 updateFramebuffer(fb)
4127 })
4128 }
4129
4130 return extend(framebufferState, {
4131 getFramebuffer: function (object) {
4132 if (typeof object === 'function' && object._reglType === 'framebuffer') {
4133 var fbo = object._framebuffer
4134 if (fbo instanceof REGLFramebuffer) {
4135 return fbo
4136 }
4137 }
4138 return null
4139 },
4140 create: createFBO,
4141 createCube: createCubeFBO,
4142 clear: function () {
4143 values(framebufferSet).forEach(destroy)
4144 },
4145 restore: restoreFramebuffers
4146 })
4147}
4148
4149var GL_FLOAT$5 = 5126
4150var GL_ARRAY_BUFFER$1 = 34962
4151
4152function AttributeRecord () {
4153 this.state = 0
4154
4155 this.x = 0.0
4156 this.y = 0.0
4157 this.z = 0.0
4158 this.w = 0.0
4159
4160 this.buffer = null
4161 this.size = 0
4162 this.normalized = false
4163 this.type = GL_FLOAT$5
4164 this.offset = 0
4165 this.stride = 0
4166 this.divisor = 0
4167}
4168
4169function wrapAttributeState (
4170 gl,
4171 extensions,
4172 limits,
4173 stats,
4174 bufferState) {
4175 var NUM_ATTRIBUTES = limits.maxAttributes
4176 var attributeBindings = new Array(NUM_ATTRIBUTES)
4177 for (var i = 0; i < NUM_ATTRIBUTES; ++i) {
4178 attributeBindings[i] = new AttributeRecord()
4179 }
4180 var vaoCount = 0
4181 var vaoSet = {}
4182
4183 var state = {
4184 Record: AttributeRecord,
4185 scope: {},
4186 state: attributeBindings,
4187 currentVAO: null,
4188 targetVAO: null,
4189 restore: extVAO() ? restoreVAO : function () {},
4190 createVAO: createVAO,
4191 getVAO: getVAO,
4192 destroyBuffer: destroyBuffer,
4193 setVAO: extVAO() ? setVAOEXT : setVAOEmulated,
4194 clear: extVAO() ? destroyVAOEXT : function () {}
4195 }
4196
4197 function destroyBuffer (buffer) {
4198 for (var i = 0; i < attributeBindings.length; ++i) {
4199 var record = attributeBindings[i]
4200 if (record.buffer === buffer) {
4201 gl.disableVertexAttribArray(i)
4202 record.buffer = null
4203 }
4204 }
4205 }
4206
4207 function extVAO () {
4208 return extensions.oes_vertex_array_object
4209 }
4210
4211 function extInstanced () {
4212 return extensions.angle_instanced_arrays
4213 }
4214
4215 function getVAO (vao) {
4216 if (typeof vao === 'function' && vao._vao) {
4217 return vao._vao
4218 }
4219 return null
4220 }
4221
4222 function setVAOEXT (vao) {
4223 if (vao === state.currentVAO) {
4224 return
4225 }
4226 var ext = extVAO()
4227 if (vao) {
4228 ext.bindVertexArrayOES(vao.vao)
4229 } else {
4230 ext.bindVertexArrayOES(null)
4231 }
4232 state.currentVAO = vao
4233 }
4234
4235 function setVAOEmulated (vao) {
4236 if (vao === state.currentVAO) {
4237 return
4238 }
4239 if (vao) {
4240 vao.bindAttrs()
4241 } else {
4242 var exti = extInstanced()
4243 for (let i = 0; i < attributeBindings.length; ++i) {
4244 var binding = attributeBindings[i]
4245 if (binding.buffer) {
4246 gl.enableVertexAttribArray(i)
4247 gl.vertexAttribPointer(i, binding.size, binding.type, binding.normalized, binding.stride, binding.offfset)
4248 if (exti) {
4249 exti.vertexAttribDivisorANGLE(i, binding.divisor)
4250 }
4251 } else {
4252 gl.disableVertexAttribArray(i)
4253 gl.vertexAttrib4f(i, binding.x, binding.y, binding.z, binding.w)
4254 }
4255 }
4256 }
4257 state.currentVAO = vao
4258 }
4259
4260 function destroyVAOEXT (vao) {
4261 values(vaoSet).forEach((vao) => {
4262 vao.destroy()
4263 })
4264 }
4265
4266 function REGLVAO () {
4267 this.id = ++vaoCount
4268 this.attributes = []
4269 var extension = extVAO()
4270 if (extension) {
4271 this.vao = extension.createVertexArrayOES()
4272 } else {
4273 this.vao = null
4274 }
4275 vaoSet[this.id] = this
4276 this.buffers = []
4277 }
4278
4279 REGLVAO.prototype.bindAttrs = function () {
4280 var exti = extInstanced()
4281 var attributes = this.attributes
4282 for (var i = 0; i < attributes.length; ++i) {
4283 var attr = attributes[i]
4284 if (attr.buffer) {
4285 gl.enableVertexAttribArray(i)
4286 gl.bindBuffer(GL_ARRAY_BUFFER$1, attr.buffer.buffer)
4287 gl.vertexAttribPointer(i, attr.size, attr.type, attr.normalized, attr.stride, attr.offset)
4288 if (exti) {
4289 exti.vertexAttribDivisorANGLE(i, attr.divisor)
4290 }
4291 } else {
4292 gl.disableVertexAttribArray(i)
4293 gl.vertexAttrib4f(i, attr.x, attr.y, attr.z, attr.w)
4294 }
4295 }
4296 for (var j = attributes.length; j < NUM_ATTRIBUTES; ++j) {
4297 gl.disableVertexAttribArray(j)
4298 }
4299 }
4300
4301 REGLVAO.prototype.refresh = function () {
4302 var ext = extVAO()
4303 if (ext) {
4304 ext.bindVertexArrayOES(this.vao)
4305 this.bindAttrs()
4306 state.currentVAO = this
4307 }
4308 }
4309
4310 REGLVAO.prototype.destroy = function () {
4311 if (this.vao) {
4312 var extension = extVAO()
4313 if (this === state.currentVAO) {
4314 state.currentVAO = null
4315 extension.bindVertexArrayOES(null)
4316 }
4317 extension.deleteVertexArrayOES(this.vao)
4318 this.vao = null
4319 }
4320 if (vaoSet[this.id]) {
4321 delete vaoSet[this.id]
4322 stats.vaoCount -= 1
4323 }
4324 }
4325
4326 function restoreVAO () {
4327 var ext = extVAO()
4328 if (ext) {
4329 values(vaoSet).forEach(function (vao) {
4330 vao.refresh()
4331 })
4332 }
4333 }
4334
4335 function createVAO (_attr) {
4336 var vao = new REGLVAO()
4337 stats.vaoCount += 1
4338
4339 function updateVAO (attributes) {
4340
4341
4342
4343
4344 for (var j = 0; j < vao.buffers.length; ++j) {
4345 vao.buffers[j].destroy()
4346 }
4347 vao.buffers.length = 0
4348
4349 var nattributes = vao.attributes
4350 nattributes.length = attributes.length
4351 for (var i = 0; i < attributes.length; ++i) {
4352 var spec = attributes[i]
4353 var rec = nattributes[i] = new AttributeRecord()
4354 if (Array.isArray(spec) || isTypedArray(spec) || isNDArrayLike(spec)) {
4355 var buf = bufferState.create(spec, GL_ARRAY_BUFFER$1, false, true)
4356 rec.buffer = bufferState.getBuffer(buf)
4357 rec.size = rec.buffer.dimension | 0
4358 rec.normalized = false
4359 rec.type = rec.buffer.dtype
4360 rec.offset = 0
4361 rec.stride = 0
4362 rec.divisor = 0
4363 rec.state = 1
4364 vao.buffers.push(buf)
4365 } else if (bufferState.getBuffer(spec)) {
4366 rec.buffer = bufferState.getBuffer(spec)
4367 rec.size = rec.buffer.dimension | 0
4368 rec.normalized = false
4369 rec.type = rec.buffer.dtype
4370 rec.offset = 0
4371 rec.stride = 0
4372 rec.divisor = 0
4373 rec.state = 1
4374 } else if (bufferState.getBuffer(spec.buffer)) {
4375 rec.buffer = bufferState.getBuffer(spec.buffer)
4376 rec.size = ((+spec.size) || rec.buffer.dimension) | 0
4377 rec.normalized = !!spec.normalized || false
4378 if ('type' in spec) {
4379
4380 rec.type = glTypes[spec.type]
4381 } else {
4382 rec.type = rec.buffer.dtype
4383 }
4384 rec.offset = (spec.offset || 0) | 0
4385 rec.stride = (spec.stride || 0) | 0
4386 rec.divisor = (spec.divisor || 0) | 0
4387 rec.state = 1
4388
4389
4390
4391
4392
4393
4394 } else if ('x' in spec) {
4395
4396 rec.x = +spec.x || 0
4397 rec.y = +spec.y || 0
4398 rec.z = +spec.z || 0
4399 rec.w = +spec.w || 0
4400 rec.state = 2
4401 } else {
4402
4403 }
4404 }
4405
4406 vao.refresh()
4407 return updateVAO
4408 }
4409
4410 updateVAO.destroy = function () {
4411 vao.destroy()
4412 }
4413
4414 updateVAO._vao = vao
4415 updateVAO._reglType = 'vao'
4416
4417 return updateVAO(_attr)
4418 }
4419
4420 return state
4421}
4422
4423var GL_FRAGMENT_SHADER = 35632
4424var GL_VERTEX_SHADER = 35633
4425
4426var GL_ACTIVE_UNIFORMS = 0x8B86
4427var GL_ACTIVE_ATTRIBUTES = 0x8B89
4428
4429function wrapShaderState (gl, stringStore, stats, config) {
4430 // ===================================================
4431 // glsl compilation and linking
4432 // ===================================================
4433 var fragShaders = {}
4434 var vertShaders = {}
4435
4436 function ActiveInfo (name, id, location, info) {
4437 this.name = name
4438 this.id = id
4439 this.location = location
4440 this.info = info
4441 }
4442
4443 function insertActiveInfo (list, info) {
4444 for (var i = 0; i < list.length; ++i) {
4445 if (list[i].id === info.id) {
4446 list[i].location = info.location
4447 return
4448 }
4449 }
4450 list.push(info)
4451 }
4452
4453 function getShader (type, id, command) {
4454 var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders
4455 var shader = cache[id]
4456
4457 if (!shader) {
4458 var source = stringStore.str(id)
4459 shader = gl.createShader(type)
4460 gl.shaderSource(shader, source)
4461 gl.compileShader(shader)
4462
4463 cache[id] = shader
4464 }
4465
4466 return shader
4467 }
4468
4469 // ===================================================
4470 // program linking
4471 // ===================================================
4472 var programCache = {}
4473 var programList = []
4474
4475 var PROGRAM_COUNTER = 0
4476
4477 function REGLProgram (fragId, vertId) {
4478 this.id = PROGRAM_COUNTER++
4479 this.fragId = fragId
4480 this.vertId = vertId
4481 this.program = null
4482 this.uniforms = []
4483 this.attributes = []
4484
4485 if (config.profile) {
4486 this.stats = {
4487 uniformsCount: 0,
4488 attributesCount: 0
4489 }
4490 }
4491 }
4492
4493 function linkProgram (desc, command, attributeLocations) {
4494 var i, info
4495
4496 // -------------------------------
4497 // compile & link
4498 // -------------------------------
4499 var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId)
4500 var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId)
4501
4502 var program = desc.program = gl.createProgram()
4503 gl.attachShader(program, fragShader)
4504 gl.attachShader(program, vertShader)
4505 if (attributeLocations) {
4506 for (let i = 0; i < attributeLocations.length; ++i) {
4507 var binding = attributeLocations[i]
4508 gl.bindAttribLocation(program, binding[0], binding[1])
4509 }
4510 }
4511
4512 gl.linkProgram(program)
4513
4514
4515 // -------------------------------
4516 // grab uniforms
4517 // -------------------------------
4518 var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS)
4519 if (config.profile) {
4520 desc.stats.uniformsCount = numUniforms
4521 }
4522 var uniforms = desc.uniforms
4523 for (i = 0; i < numUniforms; ++i) {
4524 info = gl.getActiveUniform(program, i)
4525 if (info) {
4526 if (info.size > 1) {
4527 for (var j = 0; j < info.size; ++j) {
4528 var name = info.name.replace('[0]', '[' + j + ']')
4529 insertActiveInfo(uniforms, new ActiveInfo(
4530 name,
4531 stringStore.id(name),
4532 gl.getUniformLocation(program, name),
4533 info))
4534 }
4535 } else {
4536 insertActiveInfo(uniforms, new ActiveInfo(
4537 info.name,
4538 stringStore.id(info.name),
4539 gl.getUniformLocation(program, info.name),
4540 info))
4541 }
4542 }
4543 }
4544
4545 // -------------------------------
4546 // grab attributes
4547 // -------------------------------
4548 var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES)
4549 if (config.profile) {
4550 desc.stats.attributesCount = numAttributes
4551 }
4552
4553 var attributes = desc.attributes
4554 for (i = 0; i < numAttributes; ++i) {
4555 info = gl.getActiveAttrib(program, i)
4556 if (info) {
4557 insertActiveInfo(attributes, new ActiveInfo(
4558 info.name,
4559 stringStore.id(info.name),
4560 gl.getAttribLocation(program, info.name),
4561 info))
4562 }
4563 }
4564 }
4565
4566 if (config.profile) {
4567 stats.getMaxUniformsCount = function () {
4568 var m = 0
4569 programList.forEach(function (desc) {
4570 if (desc.stats.uniformsCount > m) {
4571 m = desc.stats.uniformsCount
4572 }
4573 })
4574 return m
4575 }
4576
4577 stats.getMaxAttributesCount = function () {
4578 var m = 0
4579 programList.forEach(function (desc) {
4580 if (desc.stats.attributesCount > m) {
4581 m = desc.stats.attributesCount
4582 }
4583 })
4584 return m
4585 }
4586 }
4587
4588 function restoreShaders () {
4589 fragShaders = {}
4590 vertShaders = {}
4591 for (var i = 0; i < programList.length; ++i) {
4592 linkProgram(programList[i], null, programList[i].attributes.map(function (info) {
4593 return [info.location, info.name]
4594 }))
4595 }
4596 }
4597
4598 return {
4599 clear: function () {
4600 var deleteShader = gl.deleteShader.bind(gl)
4601 values(fragShaders).forEach(deleteShader)
4602 fragShaders = {}
4603 values(vertShaders).forEach(deleteShader)
4604 vertShaders = {}
4605
4606 programList.forEach(function (desc) {
4607 gl.deleteProgram(desc.program)
4608 })
4609 programList.length = 0
4610 programCache = {}
4611
4612 stats.shaderCount = 0
4613 },
4614
4615 program: function (vertId, fragId, command, attribLocations) {
4616
4617
4618
4619 var cache = programCache[fragId]
4620 if (!cache) {
4621 cache = programCache[fragId] = {}
4622 }
4623 var prevProgram = cache[vertId]
4624 if (prevProgram && !attribLocations) {
4625 return prevProgram
4626 }
4627 var program = new REGLProgram(fragId, vertId)
4628 stats.shaderCount++
4629 linkProgram(program, command, attribLocations)
4630 if (!prevProgram) {
4631 cache[vertId] = program
4632 }
4633 programList.push(program)
4634 return program
4635 },
4636
4637 restore: restoreShaders,
4638
4639 shader: getShader,
4640
4641 frag: -1,
4642 vert: -1
4643 }
4644}
4645
4646var GL_RGBA$3 = 6408
4647var GL_UNSIGNED_BYTE$6 = 5121
4648var GL_PACK_ALIGNMENT = 0x0D05
4649var GL_FLOAT$6 = 0x1406 // 5126
4650
4651function wrapReadPixels (
4652 gl,
4653 framebufferState,
4654 reglPoll,
4655 context,
4656 glAttributes,
4657 extensions,
4658 limits) {
4659 function readPixelsImpl (input) {
4660 var type
4661 if (framebufferState.next === null) {
4662
4663 type = GL_UNSIGNED_BYTE$6
4664 } else {
4665
4666 type = framebufferState.next.colorAttachments[0].texture._texture.type
4667
4668 if (extensions.oes_texture_float) {
4669
4670
4671 if (type === GL_FLOAT$6) {
4672
4673 }
4674 } else {
4675
4676 }
4677 }
4678
4679 var x = 0
4680 var y = 0
4681 var width = context.framebufferWidth
4682 var height = context.framebufferHeight
4683 var data = null
4684
4685 if (isTypedArray(input)) {
4686 data = input
4687 } else if (input) {
4688
4689 x = input.x | 0
4690 y = input.y | 0
4691
4692
4693 width = (input.width || (context.framebufferWidth - x)) | 0
4694 height = (input.height || (context.framebufferHeight - y)) | 0
4695 data = input.data || null
4696 }
4697
4698 // sanity check input.data
4699 if (data) {
4700 if (type === GL_UNSIGNED_BYTE$6) {
4701
4702 } else if (type === GL_FLOAT$6) {
4703
4704 }
4705 }
4706
4707
4708
4709
4710 // Update WebGL state
4711 reglPoll()
4712
4713 // Compute size
4714 var size = width * height * 4
4715
4716 // Allocate data
4717 if (!data) {
4718 if (type === GL_UNSIGNED_BYTE$6) {
4719 data = new Uint8Array(size)
4720 } else if (type === GL_FLOAT$6) {
4721 data = data || new Float32Array(size)
4722 }
4723 }
4724
4725 // Type check
4726
4727
4728
4729 // Run read pixels
4730 gl.pixelStorei(GL_PACK_ALIGNMENT, 4)
4731 gl.readPixels(x, y, width, height, GL_RGBA$3,
4732 type,
4733 data)
4734
4735 return data
4736 }
4737
4738 function readPixelsFBO (options) {
4739 var result
4740 framebufferState.setFBO({
4741 framebuffer: options.framebuffer
4742 }, function () {
4743 result = readPixelsImpl(options)
4744 })
4745 return result
4746 }
4747
4748 function readPixels (options) {
4749 if (!options || !('framebuffer' in options)) {
4750 return readPixelsImpl(options)
4751 } else {
4752 return readPixelsFBO(options)
4753 }
4754 }
4755
4756 return readPixels
4757}
4758
4759function slice (x) {
4760 return Array.prototype.slice.call(x)
4761}
4762
4763function join (x) {
4764 return slice(x).join('')
4765}
4766
4767function createEnvironment () {
4768 // Unique variable id counter
4769 var varCounter = 0
4770
4771 // Linked values are passed from this scope into the generated code block
4772 // Calling link() passes a value into the generated scope and returns
4773 // the variable name which it is bound to
4774 var linkedNames = []
4775 var linkedValues = []
4776 function link (value) {
4777 for (var i = 0; i < linkedValues.length; ++i) {
4778 if (linkedValues[i] === value) {
4779 return linkedNames[i]
4780 }
4781 }
4782
4783 var name = 'g' + (varCounter++)
4784 linkedNames.push(name)
4785 linkedValues.push(value)
4786 return name
4787 }
4788
4789 // create a code block
4790 function block () {
4791 var code = []
4792 function push () {
4793 code.push.apply(code, slice(arguments))
4794 }
4795
4796 var vars = []
4797 function def () {
4798 var name = 'v' + (varCounter++)
4799 vars.push(name)
4800
4801 if (arguments.length > 0) {
4802 code.push(name, '=')
4803 code.push.apply(code, slice(arguments))
4804 code.push(';')
4805 }
4806
4807 return name
4808 }
4809
4810 return extend(push, {
4811 def: def,
4812 toString: function () {
4813 return join([
4814 (vars.length > 0 ? 'var ' + vars.join(',') + ';' : ''),
4815 join(code)
4816 ])
4817 }
4818 })
4819 }
4820
4821 function scope () {
4822 var entry = block()
4823 var exit = block()
4824
4825 var entryToString = entry.toString
4826 var exitToString = exit.toString
4827
4828 function save (object, prop) {
4829 exit(object, prop, '=', entry.def(object, prop), ';')
4830 }
4831
4832 return extend(function () {
4833 entry.apply(entry, slice(arguments))
4834 }, {
4835 def: entry.def,
4836 entry: entry,
4837 exit: exit,
4838 save: save,
4839 set: function (object, prop, value) {
4840 save(object, prop)
4841 entry(object, prop, '=', value, ';')
4842 },
4843 toString: function () {
4844 return entryToString() + exitToString()
4845 }
4846 })
4847 }
4848
4849 function conditional () {
4850 var pred = join(arguments)
4851 var thenBlock = scope()
4852 var elseBlock = scope()
4853
4854 var thenToString = thenBlock.toString
4855 var elseToString = elseBlock.toString
4856
4857 return extend(thenBlock, {
4858 then: function () {
4859 thenBlock.apply(thenBlock, slice(arguments))
4860 return this
4861 },
4862 else: function () {
4863 elseBlock.apply(elseBlock, slice(arguments))
4864 return this
4865 },
4866 toString: function () {
4867 var elseClause = elseToString()
4868 if (elseClause) {
4869 elseClause = 'else{' + elseClause + '}'
4870 }
4871 return join([
4872 'if(', pred, '){',
4873 thenToString(),
4874 '}', elseClause
4875 ])
4876 }
4877 })
4878 }
4879
4880 // procedure list
4881 var globalBlock = block()
4882 var procedures = {}
4883 function proc (name, count) {
4884 var args = []
4885 function arg () {
4886 var name = 'a' + args.length
4887 args.push(name)
4888 return name
4889 }
4890
4891 count = count || 0
4892 for (var i = 0; i < count; ++i) {
4893 arg()
4894 }
4895
4896 var body = scope()
4897 var bodyToString = body.toString
4898
4899 var result = procedures[name] = extend(body, {
4900 arg: arg,
4901 toString: function () {
4902 return join([
4903 'function(', args.join(), '){',
4904 bodyToString(),
4905 '}'
4906 ])
4907 }
4908 })
4909
4910 return result
4911 }
4912
4913 function compile () {
4914 var code = ['"use strict";',
4915 globalBlock,
4916 'return {']
4917 Object.keys(procedures).forEach(function (name) {
4918 code.push('"', name, '":', procedures[name].toString(), ',')
4919 })
4920 code.push('}')
4921 var src = join(code)
4922 .replace(/;/g, ';\n')
4923 .replace(/}/g, '}\n')
4924 .replace(/{/g, '{\n')
4925 var proc = Function.apply(null, linkedNames.concat(src))
4926 return proc.apply(null, linkedValues)
4927 }
4928
4929 return {
4930 global: globalBlock,
4931 link: link,
4932 block: block,
4933 proc: proc,
4934 scope: scope,
4935 cond: conditional,
4936 compile: compile
4937 }
4938}
4939
4940// "cute" names for vector components
4941var CUTE_COMPONENTS = 'xyzw'.split('')
4942
4943var GL_UNSIGNED_BYTE$7 = 5121
4944
4945var ATTRIB_STATE_POINTER = 1
4946var ATTRIB_STATE_CONSTANT = 2
4947
4948var DYN_FUNC$1 = 0
4949var DYN_PROP$1 = 1
4950var DYN_CONTEXT$1 = 2
4951var DYN_STATE$1 = 3
4952var DYN_THUNK = 4
4953
4954var S_DITHER = 'dither'
4955var S_BLEND_ENABLE = 'blend.enable'
4956var S_BLEND_COLOR = 'blend.color'
4957var S_BLEND_EQUATION = 'blend.equation'
4958var S_BLEND_FUNC = 'blend.func'
4959var S_DEPTH_ENABLE = 'depth.enable'
4960var S_DEPTH_FUNC = 'depth.func'
4961var S_DEPTH_RANGE = 'depth.range'
4962var S_DEPTH_MASK = 'depth.mask'
4963var S_COLOR_MASK = 'colorMask'
4964var S_CULL_ENABLE = 'cull.enable'
4965var S_CULL_FACE = 'cull.face'
4966var S_FRONT_FACE = 'frontFace'
4967var S_LINE_WIDTH = 'lineWidth'
4968var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable'
4969var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset'
4970var S_SAMPLE_ALPHA = 'sample.alpha'
4971var S_SAMPLE_ENABLE = 'sample.enable'
4972var S_SAMPLE_COVERAGE = 'sample.coverage'
4973var S_STENCIL_ENABLE = 'stencil.enable'
4974var S_STENCIL_MASK = 'stencil.mask'
4975var S_STENCIL_FUNC = 'stencil.func'
4976var S_STENCIL_OPFRONT = 'stencil.opFront'
4977var S_STENCIL_OPBACK = 'stencil.opBack'
4978var S_SCISSOR_ENABLE = 'scissor.enable'
4979var S_SCISSOR_BOX = 'scissor.box'
4980var S_VIEWPORT = 'viewport'
4981
4982var S_PROFILE = 'profile'
4983
4984var S_FRAMEBUFFER = 'framebuffer'
4985var S_VERT = 'vert'
4986var S_FRAG = 'frag'
4987var S_ELEMENTS = 'elements'
4988var S_PRIMITIVE = 'primitive'
4989var S_COUNT = 'count'
4990var S_OFFSET = 'offset'
4991var S_INSTANCES = 'instances'
4992var S_VAO = 'vao'
4993
4994var SUFFIX_WIDTH = 'Width'
4995var SUFFIX_HEIGHT = 'Height'
4996
4997var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH
4998var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT
4999var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH
5000var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT
5001var S_DRAWINGBUFFER = 'drawingBuffer'
5002var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH
5003var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT
5004
5005var NESTED_OPTIONS = [
5006 S_BLEND_FUNC,
5007 S_BLEND_EQUATION,
5008 S_STENCIL_FUNC,
5009 S_STENCIL_OPFRONT,
5010 S_STENCIL_OPBACK,
5011 S_SAMPLE_COVERAGE,
5012 S_VIEWPORT,
5013 S_SCISSOR_BOX,
5014 S_POLYGON_OFFSET_OFFSET
5015]
5016
5017var GL_ARRAY_BUFFER$2 = 34962
5018var GL_ELEMENT_ARRAY_BUFFER$1 = 34963
5019
5020var GL_CULL_FACE = 0x0B44
5021var GL_BLEND = 0x0BE2
5022var GL_DITHER = 0x0BD0
5023var GL_STENCIL_TEST = 0x0B90
5024var GL_DEPTH_TEST = 0x0B71
5025var GL_SCISSOR_TEST = 0x0C11
5026var GL_POLYGON_OFFSET_FILL = 0x8037
5027var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E
5028var GL_SAMPLE_COVERAGE = 0x80A0
5029
5030var GL_FLOAT$7 = 5126
5031var GL_FLOAT_VEC2 = 35664
5032var GL_FLOAT_VEC3 = 35665
5033var GL_FLOAT_VEC4 = 35666
5034var GL_INT$2 = 5124
5035var GL_INT_VEC2 = 35667
5036var GL_INT_VEC3 = 35668
5037var GL_INT_VEC4 = 35669
5038var GL_BOOL = 35670
5039var GL_BOOL_VEC2 = 35671
5040var GL_BOOL_VEC3 = 35672
5041var GL_BOOL_VEC4 = 35673
5042var GL_FLOAT_MAT2 = 35674
5043var GL_FLOAT_MAT3 = 35675
5044var GL_FLOAT_MAT4 = 35676
5045var GL_SAMPLER_2D = 35678
5046var GL_SAMPLER_CUBE = 35680
5047
5048var GL_TRIANGLES$1 = 4
5049
5050var GL_FRONT = 1028
5051var GL_BACK = 1029
5052var GL_CW = 0x0900
5053var GL_CCW = 0x0901
5054var GL_MIN_EXT = 0x8007
5055var GL_MAX_EXT = 0x8008
5056var GL_ALWAYS = 519
5057var GL_KEEP = 7680
5058var GL_ZERO = 0
5059var GL_ONE = 1
5060var GL_FUNC_ADD = 0x8006
5061var GL_LESS = 513
5062
5063var GL_FRAMEBUFFER$2 = 0x8D40
5064var GL_COLOR_ATTACHMENT0$2 = 0x8CE0
5065
5066var blendFuncs = {
5067 '0': 0,
5068 '1': 1,
5069 'zero': 0,
5070 'one': 1,
5071 'src color': 768,
5072 'one minus src color': 769,
5073 'src alpha': 770,
5074 'one minus src alpha': 771,
5075 'dst color': 774,
5076 'one minus dst color': 775,
5077 'dst alpha': 772,
5078 'one minus dst alpha': 773,
5079 'constant color': 32769,
5080 'one minus constant color': 32770,
5081 'constant alpha': 32771,
5082 'one minus constant alpha': 32772,
5083 'src alpha saturate': 776
5084}
5085
5086var compareFuncs = {
5087 'never': 512,
5088 'less': 513,
5089 '<': 513,
5090 'equal': 514,
5091 '=': 514,
5092 '==': 514,
5093 '===': 514,
5094 'lequal': 515,
5095 '<=': 515,
5096 'greater': 516,
5097 '>': 516,
5098 'notequal': 517,
5099 '!=': 517,
5100 '!==': 517,
5101 'gequal': 518,
5102 '>=': 518,
5103 'always': 519
5104}
5105
5106var stencilOps = {
5107 '0': 0,
5108 'zero': 0,
5109 'keep': 7680,
5110 'replace': 7681,
5111 'increment': 7682,
5112 'decrement': 7683,
5113 'increment wrap': 34055,
5114 'decrement wrap': 34056,
5115 'invert': 5386
5116}
5117
5118var orientationType = {
5119 'cw': GL_CW,
5120 'ccw': GL_CCW
5121}
5122
5123function isBufferArgs (x) {
5124 return Array.isArray(x) ||
5125 isTypedArray(x) ||
5126 isNDArrayLike(x)
5127}
5128
5129// Make sure viewport is processed first
5130function sortState (state) {
5131 return state.sort(function (a, b) {
5132 if (a === S_VIEWPORT) {
5133 return -1
5134 } else if (b === S_VIEWPORT) {
5135 return 1
5136 }
5137 return (a < b) ? -1 : 1
5138 })
5139}
5140
5141function Declaration (thisDep, contextDep, propDep, append) {
5142 this.thisDep = thisDep
5143 this.contextDep = contextDep
5144 this.propDep = propDep
5145 this.append = append
5146}
5147
5148function isStatic (decl) {
5149 return decl && !(decl.thisDep || decl.contextDep || decl.propDep)
5150}
5151
5152function createStaticDecl (append) {
5153 return new Declaration(false, false, false, append)
5154}
5155
5156function createDynamicDecl (dyn, append) {
5157 var type = dyn.type
5158 if (type === DYN_FUNC$1) {
5159 var numArgs = dyn.data.length
5160 return new Declaration(
5161 true,
5162 numArgs >= 1,
5163 numArgs >= 2,
5164 append)
5165 } else if (type === DYN_THUNK) {
5166 var data = dyn.data
5167 return new Declaration(
5168 data.thisDep,
5169 data.contextDep,
5170 data.propDep,
5171 append)
5172 } else {
5173 return new Declaration(
5174 type === DYN_STATE$1,
5175 type === DYN_CONTEXT$1,
5176 type === DYN_PROP$1,
5177 append)
5178 }
5179}
5180
5181var SCOPE_DECL = new Declaration(false, false, false, function () {})
5182
5183function reglCore (
5184 gl,
5185 stringStore,
5186 extensions,
5187 limits,
5188 bufferState,
5189 elementState,
5190 textureState,
5191 framebufferState,
5192 uniformState,
5193 attributeState,
5194 shaderState,
5195 drawState,
5196 contextState,
5197 timer,
5198 config) {
5199 var AttributeRecord = attributeState.Record
5200
5201 var blendEquations = {
5202 'add': 32774,
5203 'subtract': 32778,
5204 'reverse subtract': 32779
5205 }
5206 if (extensions.ext_blend_minmax) {
5207 blendEquations.min = GL_MIN_EXT
5208 blendEquations.max = GL_MAX_EXT
5209 }
5210
5211 var extInstancing = extensions.angle_instanced_arrays
5212 var extDrawBuffers = extensions.webgl_draw_buffers
5213
5214 // ===================================================
5215 // ===================================================
5216 // WEBGL STATE
5217 // ===================================================
5218 // ===================================================
5219 var currentState = {
5220 dirty: true,
5221 profile: config.profile
5222 }
5223 var nextState = {}
5224 var GL_STATE_NAMES = []
5225 var GL_FLAGS = {}
5226 var GL_VARIABLES = {}
5227
5228 function propName (name) {
5229 return name.replace('.', '_')
5230 }
5231
5232 function stateFlag (sname, cap, init) {
5233 var name = propName(sname)
5234 GL_STATE_NAMES.push(sname)
5235 nextState[name] = currentState[name] = !!init
5236 GL_FLAGS[name] = cap
5237 }
5238
5239 function stateVariable (sname, func, init) {
5240 var name = propName(sname)
5241 GL_STATE_NAMES.push(sname)
5242 if (Array.isArray(init)) {
5243 currentState[name] = init.slice()
5244 nextState[name] = init.slice()
5245 } else {
5246 currentState[name] = nextState[name] = init
5247 }
5248 GL_VARIABLES[name] = func
5249 }
5250
5251 // Dithering
5252 stateFlag(S_DITHER, GL_DITHER)
5253
5254 // Blending
5255 stateFlag(S_BLEND_ENABLE, GL_BLEND)
5256 stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0])
5257 stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate',
5258 [GL_FUNC_ADD, GL_FUNC_ADD])
5259 stateVariable(S_BLEND_FUNC, 'blendFuncSeparate',
5260 [GL_ONE, GL_ZERO, GL_ONE, GL_ZERO])
5261
5262 // Depth
5263 stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true)
5264 stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS)
5265 stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1])
5266 stateVariable(S_DEPTH_MASK, 'depthMask', true)
5267
5268 // Color mask
5269 stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true])
5270
5271 // Face culling
5272 stateFlag(S_CULL_ENABLE, GL_CULL_FACE)
5273 stateVariable(S_CULL_FACE, 'cullFace', GL_BACK)
5274
5275 // Front face orientation
5276 stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW)
5277
5278 // Line width
5279 stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1)
5280
5281 // Polygon offset
5282 stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL)
5283 stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0])
5284
5285 // Sample coverage
5286 stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE)
5287 stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE)
5288 stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false])
5289
5290 // Stencil
5291 stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST)
5292 stateVariable(S_STENCIL_MASK, 'stencilMask', -1)
5293 stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1])
5294 stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate',
5295 [GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP])
5296 stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate',
5297 [GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP])
5298
5299 // Scissor
5300 stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST)
5301 stateVariable(S_SCISSOR_BOX, 'scissor',
5302 [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight])
5303
5304 // Viewport
5305 stateVariable(S_VIEWPORT, S_VIEWPORT,
5306 [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight])
5307
5308 // ===================================================
5309 // ===================================================
5310 // ENVIRONMENT
5311 // ===================================================
5312 // ===================================================
5313 var sharedState = {
5314 gl: gl,
5315 context: contextState,
5316 strings: stringStore,
5317 next: nextState,
5318 current: currentState,
5319 draw: drawState,
5320 elements: elementState,
5321 buffer: bufferState,
5322 shader: shaderState,
5323 attributes: attributeState.state,
5324 vao: attributeState,
5325 uniforms: uniformState,
5326 framebuffer: framebufferState,
5327 extensions: extensions,
5328
5329 timer: timer,
5330 isBufferArgs: isBufferArgs
5331 }
5332
5333 var sharedConstants = {
5334 primTypes: primTypes,
5335 compareFuncs: compareFuncs,
5336 blendFuncs: blendFuncs,
5337 blendEquations: blendEquations,
5338 stencilOps: stencilOps,
5339 glTypes: glTypes,
5340 orientationType: orientationType
5341 }
5342
5343
5344
5345 if (extDrawBuffers) {
5346 sharedConstants.backBuffer = [GL_BACK]
5347 sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) {
5348 if (i === 0) {
5349 return [0]
5350 }
5351 return loop(i, function (j) {
5352 return GL_COLOR_ATTACHMENT0$2 + j
5353 })
5354 })
5355 }
5356
5357 var drawCallCounter = 0
5358 function createREGLEnvironment () {
5359 var env = createEnvironment()
5360 var link = env.link
5361 var global = env.global
5362 env.id = drawCallCounter++
5363
5364 env.batchId = '0'
5365
5366 // link shared state
5367 var SHARED = link(sharedState)
5368 var shared = env.shared = {
5369 props: 'a0'
5370 }
5371 Object.keys(sharedState).forEach(function (prop) {
5372 shared[prop] = global.def(SHARED, '.', prop)
5373 })
5374
5375 // Inject runtime assertion stuff for debug builds
5376
5377
5378 // Copy GL state variables over
5379 var nextVars = env.next = {}
5380 var currentVars = env.current = {}
5381 Object.keys(GL_VARIABLES).forEach(function (variable) {
5382 if (Array.isArray(currentState[variable])) {
5383 nextVars[variable] = global.def(shared.next, '.', variable)
5384 currentVars[variable] = global.def(shared.current, '.', variable)
5385 }
5386 })
5387
5388 // Initialize shared constants
5389 var constants = env.constants = {}
5390 Object.keys(sharedConstants).forEach(function (name) {
5391 constants[name] = global.def(JSON.stringify(sharedConstants[name]))
5392 })
5393
5394 // Helper function for calling a block
5395 env.invoke = function (block, x) {
5396 switch (x.type) {
5397 case DYN_FUNC$1:
5398 var argList = [
5399 'this',
5400 shared.context,
5401 shared.props,
5402 env.batchId
5403 ]
5404 return block.def(
5405 link(x.data), '.call(',
5406 argList.slice(0, Math.max(x.data.length + 1, 4)),
5407 ')')
5408 case DYN_PROP$1:
5409 return block.def(shared.props, x.data)
5410 case DYN_CONTEXT$1:
5411 return block.def(shared.context, x.data)
5412 case DYN_STATE$1:
5413 return block.def('this', x.data)
5414 case DYN_THUNK:
5415 x.data.append(env, block)
5416 return x.data.ref
5417 }
5418 }
5419
5420 env.attribCache = {}
5421
5422 var scopeAttribs = {}
5423 env.scopeAttrib = function (name) {
5424 var id = stringStore.id(name)
5425 if (id in scopeAttribs) {
5426 return scopeAttribs[id]
5427 }
5428 var binding = attributeState.scope[id]
5429 if (!binding) {
5430 binding = attributeState.scope[id] = new AttributeRecord()
5431 }
5432 var result = scopeAttribs[id] = link(binding)
5433 return result
5434 }
5435
5436 return env
5437 }
5438
5439 // ===================================================
5440 // ===================================================
5441 // PARSING
5442 // ===================================================
5443 // ===================================================
5444 function parseProfile (options) {
5445 var staticOptions = options.static
5446 var dynamicOptions = options.dynamic
5447
5448 var profileEnable
5449 if (S_PROFILE in staticOptions) {
5450 var value = !!staticOptions[S_PROFILE]
5451 profileEnable = createStaticDecl(function (env, scope) {
5452 return value
5453 })
5454 profileEnable.enable = value
5455 } else if (S_PROFILE in dynamicOptions) {
5456 var dyn = dynamicOptions[S_PROFILE]
5457 profileEnable = createDynamicDecl(dyn, function (env, scope) {
5458 return env.invoke(scope, dyn)
5459 })
5460 }
5461
5462 return profileEnable
5463 }
5464
5465 function parseFramebuffer (options, env) {
5466 var staticOptions = options.static
5467 var dynamicOptions = options.dynamic
5468
5469 if (S_FRAMEBUFFER in staticOptions) {
5470 var framebuffer = staticOptions[S_FRAMEBUFFER]
5471 if (framebuffer) {
5472 framebuffer = framebufferState.getFramebuffer(framebuffer)
5473
5474 return createStaticDecl(function (env, block) {
5475 var FRAMEBUFFER = env.link(framebuffer)
5476 var shared = env.shared
5477 block.set(
5478 shared.framebuffer,
5479 '.next',
5480 FRAMEBUFFER)
5481 var CONTEXT = shared.context
5482 block.set(
5483 CONTEXT,
5484 '.' + S_FRAMEBUFFER_WIDTH,
5485 FRAMEBUFFER + '.width')
5486 block.set(
5487 CONTEXT,
5488 '.' + S_FRAMEBUFFER_HEIGHT,
5489 FRAMEBUFFER + '.height')
5490 return FRAMEBUFFER
5491 })
5492 } else {
5493 return createStaticDecl(function (env, scope) {
5494 var shared = env.shared
5495 scope.set(
5496 shared.framebuffer,
5497 '.next',
5498 'null')
5499 var CONTEXT = shared.context
5500 scope.set(
5501 CONTEXT,
5502 '.' + S_FRAMEBUFFER_WIDTH,
5503 CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH)
5504 scope.set(
5505 CONTEXT,
5506 '.' + S_FRAMEBUFFER_HEIGHT,
5507 CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT)
5508 return 'null'
5509 })
5510 }
5511 } else if (S_FRAMEBUFFER in dynamicOptions) {
5512 var dyn = dynamicOptions[S_FRAMEBUFFER]
5513 return createDynamicDecl(dyn, function (env, scope) {
5514 var FRAMEBUFFER_FUNC = env.invoke(scope, dyn)
5515 var shared = env.shared
5516 var FRAMEBUFFER_STATE = shared.framebuffer
5517 var FRAMEBUFFER = scope.def(
5518 FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')')
5519
5520
5521
5522 scope.set(
5523 FRAMEBUFFER_STATE,
5524 '.next',
5525 FRAMEBUFFER)
5526 var CONTEXT = shared.context
5527 scope.set(
5528 CONTEXT,
5529 '.' + S_FRAMEBUFFER_WIDTH,
5530 FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' +
5531 CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH)
5532 scope.set(
5533 CONTEXT,
5534 '.' + S_FRAMEBUFFER_HEIGHT,
5535 FRAMEBUFFER +
5536 '?' + FRAMEBUFFER + '.height:' +
5537 CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT)
5538 return FRAMEBUFFER
5539 })
5540 } else {
5541 return null
5542 }
5543 }
5544
5545 function parseViewportScissor (options, framebuffer, env) {
5546 var staticOptions = options.static
5547 var dynamicOptions = options.dynamic
5548
5549 function parseBox (param) {
5550 if (param in staticOptions) {
5551 var box = staticOptions[param]
5552
5553
5554 var isStatic = true
5555 var x = box.x | 0
5556 var y = box.y | 0
5557 var w, h
5558 if ('width' in box) {
5559 w = box.width | 0
5560
5561 } else {
5562 isStatic = false
5563 }
5564 if ('height' in box) {
5565 h = box.height | 0
5566
5567 } else {
5568 isStatic = false
5569 }
5570
5571 return new Declaration(
5572 !isStatic && framebuffer && framebuffer.thisDep,
5573 !isStatic && framebuffer && framebuffer.contextDep,
5574 !isStatic && framebuffer && framebuffer.propDep,
5575 function (env, scope) {
5576 var CONTEXT = env.shared.context
5577 var BOX_W = w
5578 if (!('width' in box)) {
5579 BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x)
5580 }
5581 var BOX_H = h
5582 if (!('height' in box)) {
5583 BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y)
5584 }
5585 return [x, y, BOX_W, BOX_H]
5586 })
5587 } else if (param in dynamicOptions) {
5588 var dynBox = dynamicOptions[param]
5589 var result = createDynamicDecl(dynBox, function (env, scope) {
5590 var BOX = env.invoke(scope, dynBox)
5591
5592
5593
5594 var CONTEXT = env.shared.context
5595 var BOX_X = scope.def(BOX, '.x|0')
5596 var BOX_Y = scope.def(BOX, '.y|0')
5597 var BOX_W = scope.def(
5598 '"width" in ', BOX, '?', BOX, '.width|0:',
5599 '(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')')
5600 var BOX_H = scope.def(
5601 '"height" in ', BOX, '?', BOX, '.height|0:',
5602 '(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')')
5603
5604
5605
5606 return [BOX_X, BOX_Y, BOX_W, BOX_H]
5607 })
5608 if (framebuffer) {
5609 result.thisDep = result.thisDep || framebuffer.thisDep
5610 result.contextDep = result.contextDep || framebuffer.contextDep
5611 result.propDep = result.propDep || framebuffer.propDep
5612 }
5613 return result
5614 } else if (framebuffer) {
5615 return new Declaration(
5616 framebuffer.thisDep,
5617 framebuffer.contextDep,
5618 framebuffer.propDep,
5619 function (env, scope) {
5620 var CONTEXT = env.shared.context
5621 return [
5622 0, 0,
5623 scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH),
5624 scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)]
5625 })
5626 } else {
5627 return null
5628 }
5629 }
5630
5631 var viewport = parseBox(S_VIEWPORT)
5632
5633 if (viewport) {
5634 var prevViewport = viewport
5635 viewport = new Declaration(
5636 viewport.thisDep,
5637 viewport.contextDep,
5638 viewport.propDep,
5639 function (env, scope) {
5640 var VIEWPORT = prevViewport.append(env, scope)
5641 var CONTEXT = env.shared.context
5642 scope.set(
5643 CONTEXT,
5644 '.' + S_VIEWPORT_WIDTH,
5645 VIEWPORT[2])
5646 scope.set(
5647 CONTEXT,
5648 '.' + S_VIEWPORT_HEIGHT,
5649 VIEWPORT[3])
5650 return VIEWPORT
5651 })
5652 }
5653
5654 return {
5655 viewport: viewport,
5656 scissor_box: parseBox(S_SCISSOR_BOX)
5657 }
5658 }
5659
5660 function parseAttribLocations (options, attributes) {
5661 var staticOptions = options.static
5662 var staticProgram =
5663 typeof staticOptions[S_FRAG] === 'string' &&
5664 typeof staticOptions[S_VERT] === 'string'
5665 if (staticProgram) {
5666 if (Object.keys(attributes.dynamic).length > 0) {
5667 return null
5668 }
5669 var staticAttributes = attributes.static
5670 var sAttributes = Object.keys(staticAttributes)
5671 if (sAttributes.length > 0 && typeof staticAttributes[sAttributes[0]] === 'number') {
5672 var bindings = []
5673 for (var i = 0; i < sAttributes.length; ++i) {
5674
5675 bindings.push([staticAttributes[sAttributes[i]] | 0, sAttributes[i]])
5676 }
5677 return bindings
5678 }
5679 }
5680 return null
5681 }
5682
5683 function parseProgram (options, env, attribLocations) {
5684 var staticOptions = options.static
5685 var dynamicOptions = options.dynamic
5686
5687 function parseShader (name) {
5688 if (name in staticOptions) {
5689 var id = stringStore.id(staticOptions[name])
5690
5691 var result = createStaticDecl(function () {
5692 return id
5693 })
5694 result.id = id
5695 return result
5696 } else if (name in dynamicOptions) {
5697 var dyn = dynamicOptions[name]
5698 return createDynamicDecl(dyn, function (env, scope) {
5699 var str = env.invoke(scope, dyn)
5700 var id = scope.def(env.shared.strings, '.id(', str, ')')
5701
5702 return id
5703 })
5704 }
5705 return null
5706 }
5707
5708 var frag = parseShader(S_FRAG)
5709 var vert = parseShader(S_VERT)
5710
5711 var program = null
5712 var progVar
5713 if (isStatic(frag) && isStatic(vert)) {
5714 program = shaderState.program(vert.id, frag.id, null, attribLocations)
5715 progVar = createStaticDecl(function (env, scope) {
5716 return env.link(program)
5717 })
5718 } else {
5719 progVar = new Declaration(
5720 (frag && frag.thisDep) || (vert && vert.thisDep),
5721 (frag && frag.contextDep) || (vert && vert.contextDep),
5722 (frag && frag.propDep) || (vert && vert.propDep),
5723 function (env, scope) {
5724 var SHADER_STATE = env.shared.shader
5725 var fragId
5726 if (frag) {
5727 fragId = frag.append(env, scope)
5728 } else {
5729 fragId = scope.def(SHADER_STATE, '.', S_FRAG)
5730 }
5731 var vertId
5732 if (vert) {
5733 vertId = vert.append(env, scope)
5734 } else {
5735 vertId = scope.def(SHADER_STATE, '.', S_VERT)
5736 }
5737 var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId
5738
5739 return scope.def(progDef + ')')
5740 })
5741 }
5742
5743 return {
5744 frag: frag,
5745 vert: vert,
5746 progVar: progVar,
5747 program: program
5748 }
5749 }
5750
5751 function parseDraw (options, env) {
5752 var staticOptions = options.static
5753 var dynamicOptions = options.dynamic
5754
5755 function parseElements () {
5756 if (S_ELEMENTS in staticOptions) {
5757 var elements = staticOptions[S_ELEMENTS]
5758 if (isBufferArgs(elements)) {
5759 elements = elementState.getElements(elementState.create(elements, true))
5760 } else if (elements) {
5761 elements = elementState.getElements(elements)
5762
5763 }
5764 var result = createStaticDecl(function (env, scope) {
5765 if (elements) {
5766 var result = env.link(elements)
5767 env.ELEMENTS = result
5768 return result
5769 }
5770 env.ELEMENTS = null
5771 return null
5772 })
5773 result.value = elements
5774 return result
5775 } else if (S_ELEMENTS in dynamicOptions) {
5776 var dyn = dynamicOptions[S_ELEMENTS]
5777 return createDynamicDecl(dyn, function (env, scope) {
5778 var shared = env.shared
5779
5780 var IS_BUFFER_ARGS = shared.isBufferArgs
5781 var ELEMENT_STATE = shared.elements
5782
5783 var elementDefn = env.invoke(scope, dyn)
5784 var elements = scope.def('null')
5785 var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')')
5786
5787 var ifte = env.cond(elementStream)
5788 .then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');')
5789 .else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');')
5790
5791
5792
5793 scope.entry(ifte)
5794 scope.exit(
5795 env.cond(elementStream)
5796 .then(ELEMENT_STATE, '.destroyStream(', elements, ');'))
5797
5798 env.ELEMENTS = elements
5799
5800 return elements
5801 })
5802 }
5803
5804 return null
5805 }
5806
5807 var elements = parseElements()
5808
5809 function parsePrimitive () {
5810 if (S_PRIMITIVE in staticOptions) {
5811 var primitive = staticOptions[S_PRIMITIVE]
5812
5813 return createStaticDecl(function (env, scope) {
5814 return primTypes[primitive]
5815 })
5816 } else if (S_PRIMITIVE in dynamicOptions) {
5817 var dynPrimitive = dynamicOptions[S_PRIMITIVE]
5818 return createDynamicDecl(dynPrimitive, function (env, scope) {
5819 var PRIM_TYPES = env.constants.primTypes
5820 var prim = env.invoke(scope, dynPrimitive)
5821
5822 return scope.def(PRIM_TYPES, '[', prim, ']')
5823 })
5824 } else if (elements) {
5825 if (isStatic(elements)) {
5826 if (elements.value) {
5827 return createStaticDecl(function (env, scope) {
5828 return scope.def(env.ELEMENTS, '.primType')
5829 })
5830 } else {
5831 return createStaticDecl(function () {
5832 return GL_TRIANGLES$1
5833 })
5834 }
5835 } else {
5836 return new Declaration(
5837 elements.thisDep,
5838 elements.contextDep,
5839 elements.propDep,
5840 function (env, scope) {
5841 var elements = env.ELEMENTS
5842 return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES$1)
5843 })
5844 }
5845 }
5846 return null
5847 }
5848
5849 function parseParam (param, isOffset) {
5850 if (param in staticOptions) {
5851 var value = staticOptions[param] | 0
5852
5853 return createStaticDecl(function (env, scope) {
5854 if (isOffset) {
5855 env.OFFSET = value
5856 }
5857 return value
5858 })
5859 } else if (param in dynamicOptions) {
5860 var dynValue = dynamicOptions[param]
5861 return createDynamicDecl(dynValue, function (env, scope) {
5862 var result = env.invoke(scope, dynValue)
5863 if (isOffset) {
5864 env.OFFSET = result
5865
5866 }
5867 return result
5868 })
5869 } else if (isOffset && elements) {
5870 return createStaticDecl(function (env, scope) {
5871 env.OFFSET = '0'
5872 return 0
5873 })
5874 }
5875 return null
5876 }
5877
5878 var OFFSET = parseParam(S_OFFSET, true)
5879
5880 function parseVertCount () {
5881 if (S_COUNT in staticOptions) {
5882 var count = staticOptions[S_COUNT] | 0
5883
5884 return createStaticDecl(function () {
5885 return count
5886 })
5887 } else if (S_COUNT in dynamicOptions) {
5888 var dynCount = dynamicOptions[S_COUNT]
5889 return createDynamicDecl(dynCount, function (env, scope) {
5890 var result = env.invoke(scope, dynCount)
5891
5892 return result
5893 })
5894 } else if (elements) {
5895 if (isStatic(elements)) {
5896 if (elements) {
5897 if (OFFSET) {
5898 return new Declaration(
5899 OFFSET.thisDep,
5900 OFFSET.contextDep,
5901 OFFSET.propDep,
5902 function (env, scope) {
5903 var result = scope.def(
5904 env.ELEMENTS, '.vertCount-', env.OFFSET)
5905
5906
5907
5908 return result
5909 })
5910 } else {
5911 return createStaticDecl(function (env, scope) {
5912 return scope.def(env.ELEMENTS, '.vertCount')
5913 })
5914 }
5915 } else {
5916 var result = createStaticDecl(function () {
5917 return -1
5918 })
5919
5920 return result
5921 }
5922 } else {
5923 var variable = new Declaration(
5924 elements.thisDep || OFFSET.thisDep,
5925 elements.contextDep || OFFSET.contextDep,
5926 elements.propDep || OFFSET.propDep,
5927 function (env, scope) {
5928 var elements = env.ELEMENTS
5929 if (env.OFFSET) {
5930 return scope.def(elements, '?', elements, '.vertCount-',
5931 env.OFFSET, ':-1')
5932 }
5933 return scope.def(elements, '?', elements, '.vertCount:-1')
5934 })
5935
5936 return variable
5937 }
5938 }
5939 return null
5940 }
5941
5942 return {
5943 elements: elements,
5944 primitive: parsePrimitive(),
5945 count: parseVertCount(),
5946 instances: parseParam(S_INSTANCES, false),
5947 offset: OFFSET
5948 }
5949 }
5950
5951 function parseGLState (options, env) {
5952 var staticOptions = options.static
5953 var dynamicOptions = options.dynamic
5954
5955 var STATE = {}
5956
5957 GL_STATE_NAMES.forEach(function (prop) {
5958 var param = propName(prop)
5959
5960 function parseParam (parseStatic, parseDynamic) {
5961 if (prop in staticOptions) {
5962 var value = parseStatic(staticOptions[prop])
5963 STATE[param] = createStaticDecl(function () {
5964 return value
5965 })
5966 } else if (prop in dynamicOptions) {
5967 var dyn = dynamicOptions[prop]
5968 STATE[param] = createDynamicDecl(dyn, function (env, scope) {
5969 return parseDynamic(env, scope, env.invoke(scope, dyn))
5970 })
5971 }
5972 }
5973
5974 switch (prop) {
5975 case S_CULL_ENABLE:
5976 case S_BLEND_ENABLE:
5977 case S_DITHER:
5978 case S_STENCIL_ENABLE:
5979 case S_DEPTH_ENABLE:
5980 case S_SCISSOR_ENABLE:
5981 case S_POLYGON_OFFSET_ENABLE:
5982 case S_SAMPLE_ALPHA:
5983 case S_SAMPLE_ENABLE:
5984 case S_DEPTH_MASK:
5985 return parseParam(
5986 function (value) {
5987
5988 return value
5989 },
5990 function (env, scope, value) {
5991
5992 return value
5993 })
5994
5995 case S_DEPTH_FUNC:
5996 return parseParam(
5997 function (value) {
5998
5999 return compareFuncs[value]
6000 },
6001 function (env, scope, value) {
6002 var COMPARE_FUNCS = env.constants.compareFuncs
6003
6004 return scope.def(COMPARE_FUNCS, '[', value, ']')
6005 })
6006
6007 case S_DEPTH_RANGE:
6008 return parseParam(
6009 function (value) {
6010
6011 return value
6012 },
6013 function (env, scope, value) {
6014
6015
6016 var Z_NEAR = scope.def('+', value, '[0]')
6017 var Z_FAR = scope.def('+', value, '[1]')
6018 return [Z_NEAR, Z_FAR]
6019 })
6020
6021 case S_BLEND_FUNC:
6022 return parseParam(
6023 function (value) {
6024
6025 var srcRGB = ('srcRGB' in value ? value.srcRGB : value.src)
6026 var srcAlpha = ('srcAlpha' in value ? value.srcAlpha : value.src)
6027 var dstRGB = ('dstRGB' in value ? value.dstRGB : value.dst)
6028 var dstAlpha = ('dstAlpha' in value ? value.dstAlpha : value.dst)
6029
6030
6031
6032
6033
6034
6035
6036 return [
6037 blendFuncs[srcRGB],
6038 blendFuncs[dstRGB],
6039 blendFuncs[srcAlpha],
6040 blendFuncs[dstAlpha]
6041 ]
6042 },
6043 function (env, scope, value) {
6044 var BLEND_FUNCS = env.constants.blendFuncs
6045
6046
6047
6048 function read (prefix, suffix) {
6049 var func = scope.def(
6050 '"', prefix, suffix, '" in ', value,
6051 '?', value, '.', prefix, suffix,
6052 ':', value, '.', prefix)
6053
6054
6055
6056 return func
6057 }
6058
6059 var srcRGB = read('src', 'RGB')
6060 var dstRGB = read('dst', 'RGB')
6061
6062
6063
6064 var SRC_RGB = scope.def(BLEND_FUNCS, '[', srcRGB, ']')
6065 var SRC_ALPHA = scope.def(BLEND_FUNCS, '[', read('src', 'Alpha'), ']')
6066 var DST_RGB = scope.def(BLEND_FUNCS, '[', dstRGB, ']')
6067 var DST_ALPHA = scope.def(BLEND_FUNCS, '[', read('dst', 'Alpha'), ']')
6068
6069 return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA]
6070 })
6071
6072 case S_BLEND_EQUATION:
6073 return parseParam(
6074 function (value) {
6075 if (typeof value === 'string') {
6076
6077 return [
6078 blendEquations[value],
6079 blendEquations[value]
6080 ]
6081 } else if (typeof value === 'object') {
6082
6083
6084 return [
6085 blendEquations[value.rgb],
6086 blendEquations[value.alpha]
6087 ]
6088 } else {
6089
6090 }
6091 },
6092 function (env, scope, value) {
6093 var BLEND_EQUATIONS = env.constants.blendEquations
6094
6095 var RGB = scope.def()
6096 var ALPHA = scope.def()
6097
6098 var ifte = env.cond('typeof ', value, '==="string"')
6099
6100
6101
6102 ifte.then(
6103 RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];')
6104 ifte.else(
6105 RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];',
6106 ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];')
6107
6108 scope(ifte)
6109
6110 return [RGB, ALPHA]
6111 })
6112
6113 case S_BLEND_COLOR:
6114 return parseParam(
6115 function (value) {
6116
6117 return loop(4, function (i) {
6118 return +value[i]
6119 })
6120 },
6121 function (env, scope, value) {
6122
6123 return loop(4, function (i) {
6124 return scope.def('+', value, '[', i, ']')
6125 })
6126 })
6127
6128 case S_STENCIL_MASK:
6129 return parseParam(
6130 function (value) {
6131
6132 return value | 0
6133 },
6134 function (env, scope, value) {
6135
6136 return scope.def(value, '|0')
6137 })
6138
6139 case S_STENCIL_FUNC:
6140 return parseParam(
6141 function (value) {
6142
6143 var cmp = value.cmp || 'keep'
6144 var ref = value.ref || 0
6145 var mask = 'mask' in value ? value.mask : -1
6146
6147
6148
6149 return [
6150 compareFuncs[cmp],
6151 ref,
6152 mask
6153 ]
6154 },
6155 function (env, scope, value) {
6156 var COMPARE_FUNCS = env.constants.compareFuncs
6157
6158 var cmp = scope.def(
6159 '"cmp" in ', value,
6160 '?', COMPARE_FUNCS, '[', value, '.cmp]',
6161 ':', GL_KEEP)
6162 var ref = scope.def(value, '.ref|0')
6163 var mask = scope.def(
6164 '"mask" in ', value,
6165 '?', value, '.mask|0:-1')
6166 return [cmp, ref, mask]
6167 })
6168
6169 case S_STENCIL_OPFRONT:
6170 case S_STENCIL_OPBACK:
6171 return parseParam(
6172 function (value) {
6173
6174 var fail = value.fail || 'keep'
6175 var zfail = value.zfail || 'keep'
6176 var zpass = value.zpass || 'keep'
6177
6178
6179
6180 return [
6181 prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT,
6182 stencilOps[fail],
6183 stencilOps[zfail],
6184 stencilOps[zpass]
6185 ]
6186 },
6187 function (env, scope, value) {
6188 var STENCIL_OPS = env.constants.stencilOps
6189
6190
6191
6192 function read (name) {
6193
6194
6195 return scope.def(
6196 '"', name, '" in ', value,
6197 '?', STENCIL_OPS, '[', value, '.', name, ']:',
6198 GL_KEEP)
6199 }
6200
6201 return [
6202 prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT,
6203 read('fail'),
6204 read('zfail'),
6205 read('zpass')
6206 ]
6207 })
6208
6209 case S_POLYGON_OFFSET_OFFSET:
6210 return parseParam(
6211 function (value) {
6212
6213 var factor = value.factor | 0
6214 var units = value.units | 0
6215
6216
6217 return [factor, units]
6218 },
6219 function (env, scope, value) {
6220
6221
6222 var FACTOR = scope.def(value, '.factor|0')
6223 var UNITS = scope.def(value, '.units|0')
6224
6225 return [FACTOR, UNITS]
6226 })
6227
6228 case S_CULL_FACE:
6229 return parseParam(
6230 function (value) {
6231 var face = 0
6232 if (value === 'front') {
6233 face = GL_FRONT
6234 } else if (value === 'back') {
6235 face = GL_BACK
6236 }
6237
6238 return face
6239 },
6240 function (env, scope, value) {
6241
6242 return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK)
6243 })
6244
6245 case S_LINE_WIDTH:
6246 return parseParam(
6247 function (value) {
6248
6249 return value
6250 },
6251 function (env, scope, value) {
6252
6253
6254 return value
6255 })
6256
6257 case S_FRONT_FACE:
6258 return parseParam(
6259 function (value) {
6260
6261 return orientationType[value]
6262 },
6263 function (env, scope, value) {
6264
6265 return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW)
6266 })
6267
6268 case S_COLOR_MASK:
6269 return parseParam(
6270 function (value) {
6271
6272 return value.map(function (v) { return !!v })
6273 },
6274 function (env, scope, value) {
6275
6276 return loop(4, function (i) {
6277 return '!!' + value + '[' + i + ']'
6278 })
6279 })
6280
6281 case S_SAMPLE_COVERAGE:
6282 return parseParam(
6283 function (value) {
6284
6285 var sampleValue = 'value' in value ? value.value : 1
6286 var sampleInvert = !!value.invert
6287
6288 return [sampleValue, sampleInvert]
6289 },
6290 function (env, scope, value) {
6291
6292 var VALUE = scope.def(
6293 '"value" in ', value, '?+', value, '.value:1')
6294 var INVERT = scope.def('!!', value, '.invert')
6295 return [VALUE, INVERT]
6296 })
6297 }
6298 })
6299
6300 return STATE
6301 }
6302
6303 function parseUniforms (uniforms, env) {
6304 var staticUniforms = uniforms.static
6305 var dynamicUniforms = uniforms.dynamic
6306
6307 var UNIFORMS = {}
6308
6309 Object.keys(staticUniforms).forEach(function (name) {
6310 var value = staticUniforms[name]
6311 var result
6312 if (typeof value === 'number' ||
6313 typeof value === 'boolean') {
6314 result = createStaticDecl(function () {
6315 return value
6316 })
6317 } else if (typeof value === 'function') {
6318 var reglType = value._reglType
6319 if (reglType === 'texture2d' ||
6320 reglType === 'textureCube') {
6321 result = createStaticDecl(function (env) {
6322 return env.link(value)
6323 })
6324 } else if (reglType === 'framebuffer' ||
6325 reglType === 'framebufferCube') {
6326
6327 result = createStaticDecl(function (env) {
6328 return env.link(value.color[0])
6329 })
6330 } else {
6331
6332 }
6333 } else if (isArrayLike(value)) {
6334 result = createStaticDecl(function (env) {
6335 var ITEM = env.global.def('[',
6336 loop(value.length, function (i) {
6337
6338 return value[i]
6339 }), ']')
6340 return ITEM
6341 })
6342 } else {
6343
6344 }
6345 result.value = value
6346 UNIFORMS[name] = result
6347 })
6348
6349 Object.keys(dynamicUniforms).forEach(function (key) {
6350 var dyn = dynamicUniforms[key]
6351 UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) {
6352 return env.invoke(scope, dyn)
6353 })
6354 })
6355
6356 return UNIFORMS
6357 }
6358
6359 function parseAttributes (attributes, env) {
6360 var staticAttributes = attributes.static
6361 var dynamicAttributes = attributes.dynamic
6362
6363 var attributeDefs = {}
6364
6365 Object.keys(staticAttributes).forEach(function (attribute) {
6366 var value = staticAttributes[attribute]
6367 var id = stringStore.id(attribute)
6368
6369 var record = new AttributeRecord()
6370 if (isBufferArgs(value)) {
6371 record.state = ATTRIB_STATE_POINTER
6372 record.buffer = bufferState.getBuffer(
6373 bufferState.create(value, GL_ARRAY_BUFFER$2, false, true))
6374 record.type = 0
6375 } else {
6376 var buffer = bufferState.getBuffer(value)
6377 if (buffer) {
6378 record.state = ATTRIB_STATE_POINTER
6379 record.buffer = buffer
6380 record.type = 0
6381 } else {
6382
6383 if ('constant' in value) {
6384 var constant = value.constant
6385 record.buffer = 'null'
6386 record.state = ATTRIB_STATE_CONSTANT
6387 if (typeof constant === 'number') {
6388 record.x = constant
6389 } else {
6390
6391 CUTE_COMPONENTS.forEach(function (c, i) {
6392 if (i < constant.length) {
6393 record[c] = constant[i]
6394 }
6395 })
6396 }
6397 } else {
6398 if (isBufferArgs(value.buffer)) {
6399 buffer = bufferState.getBuffer(
6400 bufferState.create(value.buffer, GL_ARRAY_BUFFER$2, false, true))
6401 } else {
6402 buffer = bufferState.getBuffer(value.buffer)
6403 }
6404
6405
6406 var offset = value.offset | 0
6407
6408
6409 var stride = value.stride | 0
6410
6411
6412 var size = value.size | 0
6413
6414
6415 var normalized = !!value.normalized
6416
6417 var type = 0
6418 if ('type' in value) {
6419
6420 type = glTypes[value.type]
6421 }
6422
6423 var divisor = value.divisor | 0
6424 if ('divisor' in value) {
6425
6426
6427 }
6428
6429
6430
6431 record.buffer = buffer
6432 record.state = ATTRIB_STATE_POINTER
6433 record.size = size
6434 record.normalized = normalized
6435 record.type = type || buffer.dtype
6436 record.offset = offset
6437 record.stride = stride
6438 record.divisor = divisor
6439 }
6440 }
6441 }
6442
6443 attributeDefs[attribute] = createStaticDecl(function (env, scope) {
6444 var cache = env.attribCache
6445 if (id in cache) {
6446 return cache[id]
6447 }
6448 var result = {
6449 isStream: false
6450 }
6451 Object.keys(record).forEach(function (key) {
6452 result[key] = record[key]
6453 })
6454 if (record.buffer) {
6455 result.buffer = env.link(record.buffer)
6456 result.type = result.type || (result.buffer + '.dtype')
6457 }
6458 cache[id] = result
6459 return result
6460 })
6461 })
6462
6463 Object.keys(dynamicAttributes).forEach(function (attribute) {
6464 var dyn = dynamicAttributes[attribute]
6465
6466 function appendAttributeCode (env, block) {
6467 var VALUE = env.invoke(block, dyn)
6468
6469 var shared = env.shared
6470 var constants = env.constants
6471
6472 var IS_BUFFER_ARGS = shared.isBufferArgs
6473 var BUFFER_STATE = shared.buffer
6474
6475 // Perform validation on attribute
6476
6477
6478 // allocate names for result
6479 var result = {
6480 isStream: block.def(false)
6481 }
6482 var defaultRecord = new AttributeRecord()
6483 defaultRecord.state = ATTRIB_STATE_POINTER
6484 Object.keys(defaultRecord).forEach(function (key) {
6485 result[key] = block.def('' + defaultRecord[key])
6486 })
6487
6488 var BUFFER = result.buffer
6489 var TYPE = result.type
6490 block(
6491 'if(', IS_BUFFER_ARGS, '(', VALUE, ')){',
6492 result.isStream, '=true;',
6493 BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$2, ',', VALUE, ');',
6494 TYPE, '=', BUFFER, '.dtype;',
6495 '}else{',
6496 BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');',
6497 'if(', BUFFER, '){',
6498 TYPE, '=', BUFFER, '.dtype;',
6499 '}else if("constant" in ', VALUE, '){',
6500 result.state, '=', ATTRIB_STATE_CONSTANT, ';',
6501 'if(typeof ' + VALUE + '.constant === "number"){',
6502 result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;',
6503 CUTE_COMPONENTS.slice(1).map(function (n) {
6504 return result[n]
6505 }).join('='), '=0;',
6506 '}else{',
6507 CUTE_COMPONENTS.map(function (name, i) {
6508 return (
6509 result[name] + '=' + VALUE + '.constant.length>' + i +
6510 '?' + VALUE + '.constant[' + i + ']:0;'
6511 )
6512 }).join(''),
6513 '}}else{',
6514 'if(', IS_BUFFER_ARGS, '(', VALUE, '.buffer)){',
6515 BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$2, ',', VALUE, '.buffer);',
6516 '}else{',
6517 BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);',
6518 '}',
6519 TYPE, '="type" in ', VALUE, '?',
6520 constants.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;',
6521 result.normalized, '=!!', VALUE, '.normalized;')
6522 function emitReadRecord (name) {
6523 block(result[name], '=', VALUE, '.', name, '|0;')
6524 }
6525 emitReadRecord('size')
6526 emitReadRecord('offset')
6527 emitReadRecord('stride')
6528 emitReadRecord('divisor')
6529
6530 block('}}')
6531
6532 block.exit(
6533 'if(', result.isStream, '){',
6534 BUFFER_STATE, '.destroyStream(', BUFFER, ');',
6535 '}')
6536
6537 return result
6538 }
6539
6540 attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode)
6541 })
6542
6543 return attributeDefs
6544 }
6545
6546 function parseVAO (options, env) {
6547 var staticOptions = options.static
6548 var dynamicOptions = options.dynamic
6549 if (S_VAO in staticOptions) {
6550 var vao = staticOptions[S_VAO]
6551 if (vao !== null && attributeState.getVAO(vao) === null) {
6552 vao = attributeState.createVAO(vao)
6553 }
6554 return createStaticDecl(function (env) {
6555 return env.link(attributeState.getVAO(vao))
6556 })
6557 } else if (S_VAO in dynamicOptions) {
6558 var dyn = dynamicOptions[S_VAO]
6559 return createDynamicDecl(dyn, function (env, scope) {
6560 var vaoRef = env.invoke(scope, dyn)
6561 return scope.def(env.shared.vao + '.getVAO(' + vaoRef + ')')
6562 })
6563 }
6564 return null
6565 }
6566
6567 function parseContext (context) {
6568 var staticContext = context.static
6569 var dynamicContext = context.dynamic
6570 var result = {}
6571
6572 Object.keys(staticContext).forEach(function (name) {
6573 var value = staticContext[name]
6574 result[name] = createStaticDecl(function (env, scope) {
6575 if (typeof value === 'number' || typeof value === 'boolean') {
6576 return '' + value
6577 } else {
6578 return env.link(value)
6579 }
6580 })
6581 })
6582
6583 Object.keys(dynamicContext).forEach(function (name) {
6584 var dyn = dynamicContext[name]
6585 result[name] = createDynamicDecl(dyn, function (env, scope) {
6586 return env.invoke(scope, dyn)
6587 })
6588 })
6589
6590 return result
6591 }
6592
6593 function parseArguments (options, attributes, uniforms, context, env) {
6594 var staticOptions = options.static
6595 var dynamicOptions = options.dynamic
6596
6597
6598
6599 var attribLocations = parseAttribLocations(options, attributes)
6600
6601 var framebuffer = parseFramebuffer(options, env)
6602 var viewportAndScissor = parseViewportScissor(options, framebuffer, env)
6603 var draw = parseDraw(options, env)
6604 var state = parseGLState(options, env)
6605 var shader = parseProgram(options, env, attribLocations)
6606
6607 function copyBox (name) {
6608 var defn = viewportAndScissor[name]
6609 if (defn) {
6610 state[name] = defn
6611 }
6612 }
6613 copyBox(S_VIEWPORT)
6614 copyBox(propName(S_SCISSOR_BOX))
6615
6616 var dirty = Object.keys(state).length > 0
6617
6618 var result = {
6619 framebuffer: framebuffer,
6620 draw: draw,
6621 shader: shader,
6622 state: state,
6623 dirty: dirty,
6624 scopeVAO: null,
6625 drawVAO: null,
6626 useVAO: false,
6627 attributes: {}
6628 }
6629
6630 result.profile = parseProfile(options, env)
6631 result.uniforms = parseUniforms(uniforms, env)
6632 result.drawVAO = result.scopeVAO = parseVAO(options, env)
6633 // special case: check if we can statically allocate a vertex array object for this program
6634 if (!result.drawVAO && shader.program && !attribLocations && extensions.angle_instanced_arrays) {
6635 var useVAO = true
6636 var staticBindings = shader.program.attributes.map(function (attr) {
6637 var binding = attributes.static[attr]
6638 useVAO = useVAO && !!binding
6639 return binding
6640 })
6641 if (useVAO && staticBindings.length > 0) {
6642 var vao = attributeState.getVAO(attributeState.createVAO(staticBindings))
6643 result.drawVAO = new Declaration(null, null, null, function (env, scope) {
6644 return env.link(vao)
6645 })
6646 result.useVAO = true
6647 }
6648 }
6649 if (attribLocations) {
6650 result.useVAO = true
6651 } else {
6652 result.attributes = parseAttributes(attributes, env)
6653 }
6654 result.context = parseContext(context, env)
6655 return result
6656 }
6657
6658 // ===================================================
6659 // ===================================================
6660 // COMMON UPDATE FUNCTIONS
6661 // ===================================================
6662 // ===================================================
6663 function emitContext (env, scope, context) {
6664 var shared = env.shared
6665 var CONTEXT = shared.context
6666
6667 var contextEnter = env.scope()
6668
6669 Object.keys(context).forEach(function (name) {
6670 scope.save(CONTEXT, '.' + name)
6671 var defn = context[name]
6672 contextEnter(CONTEXT, '.', name, '=', defn.append(env, scope), ';')
6673 })
6674
6675 scope(contextEnter)
6676 }
6677
6678 // ===================================================
6679 // ===================================================
6680 // COMMON DRAWING FUNCTIONS
6681 // ===================================================
6682 // ===================================================
6683 function emitPollFramebuffer (env, scope, framebuffer, skipCheck) {
6684 var shared = env.shared
6685
6686 var GL = shared.gl
6687 var FRAMEBUFFER_STATE = shared.framebuffer
6688 var EXT_DRAW_BUFFERS
6689 if (extDrawBuffers) {
6690 EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers')
6691 }
6692
6693 var constants = env.constants
6694
6695 var DRAW_BUFFERS = constants.drawBuffer
6696 var BACK_BUFFER = constants.backBuffer
6697
6698 var NEXT
6699 if (framebuffer) {
6700 NEXT = framebuffer.append(env, scope)
6701 } else {
6702 NEXT = scope.def(FRAMEBUFFER_STATE, '.next')
6703 }
6704
6705 if (!skipCheck) {
6706 scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){')
6707 }
6708 scope(
6709 'if(', NEXT, '){',
6710 GL, '.bindFramebuffer(', GL_FRAMEBUFFER$2, ',', NEXT, '.framebuffer);')
6711 if (extDrawBuffers) {
6712 scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(',
6713 DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);')
6714 }
6715 scope('}else{',
6716 GL, '.bindFramebuffer(', GL_FRAMEBUFFER$2, ',null);')
6717 if (extDrawBuffers) {
6718 scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');')
6719 }
6720 scope(
6721 '}',
6722 FRAMEBUFFER_STATE, '.cur=', NEXT, ';')
6723 if (!skipCheck) {
6724 scope('}')
6725 }
6726 }
6727
6728 function emitPollState (env, scope, args) {
6729 var shared = env.shared
6730
6731 var GL = shared.gl
6732
6733 var CURRENT_VARS = env.current
6734 var NEXT_VARS = env.next
6735 var CURRENT_STATE = shared.current
6736 var NEXT_STATE = shared.next
6737
6738 var block = env.cond(CURRENT_STATE, '.dirty')
6739
6740 GL_STATE_NAMES.forEach(function (prop) {
6741 var param = propName(prop)
6742 if (param in args.state) {
6743 return
6744 }
6745
6746 var NEXT, CURRENT
6747 if (param in NEXT_VARS) {
6748 NEXT = NEXT_VARS[param]
6749 CURRENT = CURRENT_VARS[param]
6750 var parts = loop(currentState[param].length, function (i) {
6751 return block.def(NEXT, '[', i, ']')
6752 })
6753 block(env.cond(parts.map(function (p, i) {
6754 return p + '!==' + CURRENT + '[' + i + ']'
6755 }).join('||'))
6756 .then(
6757 GL, '.', GL_VARIABLES[param], '(', parts, ');',
6758 parts.map(function (p, i) {
6759 return CURRENT + '[' + i + ']=' + p
6760 }).join(';'), ';'))
6761 } else {
6762 NEXT = block.def(NEXT_STATE, '.', param)
6763 var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param)
6764 block(ifte)
6765 if (param in GL_FLAGS) {
6766 ifte(
6767 env.cond(NEXT)
6768 .then(GL, '.enable(', GL_FLAGS[param], ');')
6769 .else(GL, '.disable(', GL_FLAGS[param], ');'),
6770 CURRENT_STATE, '.', param, '=', NEXT, ';')
6771 } else {
6772 ifte(
6773 GL, '.', GL_VARIABLES[param], '(', NEXT, ');',
6774 CURRENT_STATE, '.', param, '=', NEXT, ';')
6775 }
6776 }
6777 })
6778 if (Object.keys(args.state).length === 0) {
6779 block(CURRENT_STATE, '.dirty=false;')
6780 }
6781 scope(block)
6782 }
6783
6784 function emitSetOptions (env, scope, options, filter) {
6785 var shared = env.shared
6786 var CURRENT_VARS = env.current
6787 var CURRENT_STATE = shared.current
6788 var GL = shared.gl
6789 sortState(Object.keys(options)).forEach(function (param) {
6790 var defn = options[param]
6791 if (filter && !filter(defn)) {
6792 return
6793 }
6794 var variable = defn.append(env, scope)
6795 if (GL_FLAGS[param]) {
6796 var flag = GL_FLAGS[param]
6797 if (isStatic(defn)) {
6798 if (variable) {
6799 scope(GL, '.enable(', flag, ');')
6800 } else {
6801 scope(GL, '.disable(', flag, ');')
6802 }
6803 } else {
6804 scope(env.cond(variable)
6805 .then(GL, '.enable(', flag, ');')
6806 .else(GL, '.disable(', flag, ');'))
6807 }
6808 scope(CURRENT_STATE, '.', param, '=', variable, ';')
6809 } else if (isArrayLike(variable)) {
6810 var CURRENT = CURRENT_VARS[param]
6811 scope(
6812 GL, '.', GL_VARIABLES[param], '(', variable, ');',
6813 variable.map(function (v, i) {
6814 return CURRENT + '[' + i + ']=' + v
6815 }).join(';'), ';')
6816 } else {
6817 scope(
6818 GL, '.', GL_VARIABLES[param], '(', variable, ');',
6819 CURRENT_STATE, '.', param, '=', variable, ';')
6820 }
6821 })
6822 }
6823
6824 function injectExtensions (env, scope) {
6825 if (extInstancing) {
6826 env.instancing = scope.def(
6827 env.shared.extensions, '.angle_instanced_arrays')
6828 }
6829 }
6830
6831 function emitProfile (env, scope, args, useScope, incrementCounter) {
6832 var shared = env.shared
6833 var STATS = env.stats
6834 var CURRENT_STATE = shared.current
6835 var TIMER = shared.timer
6836 var profileArg = args.profile
6837
6838 function perfCounter () {
6839 if (typeof performance === 'undefined') {
6840 return 'Date.now()'
6841 } else {
6842 return 'performance.now()'
6843 }
6844 }
6845
6846 var CPU_START, QUERY_COUNTER
6847 function emitProfileStart (block) {
6848 CPU_START = scope.def()
6849 block(CPU_START, '=', perfCounter(), ';')
6850 if (typeof incrementCounter === 'string') {
6851 block(STATS, '.count+=', incrementCounter, ';')
6852 } else {
6853 block(STATS, '.count++;')
6854 }
6855 if (timer) {
6856 if (useScope) {
6857 QUERY_COUNTER = scope.def()
6858 block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();')
6859 } else {
6860 block(TIMER, '.beginQuery(', STATS, ');')
6861 }
6862 }
6863 }
6864
6865 function emitProfileEnd (block) {
6866 block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';')
6867 if (timer) {
6868 if (useScope) {
6869 block(TIMER, '.pushScopeStats(',
6870 QUERY_COUNTER, ',',
6871 TIMER, '.getNumPendingQueries(),',
6872 STATS, ');')
6873 } else {
6874 block(TIMER, '.endQuery();')
6875 }
6876 }
6877 }
6878
6879 function scopeProfile (value) {
6880 var prev = scope.def(CURRENT_STATE, '.profile')
6881 scope(CURRENT_STATE, '.profile=', value, ';')
6882 scope.exit(CURRENT_STATE, '.profile=', prev, ';')
6883 }
6884
6885 var USE_PROFILE
6886 if (profileArg) {
6887 if (isStatic(profileArg)) {
6888 if (profileArg.enable) {
6889 emitProfileStart(scope)
6890 emitProfileEnd(scope.exit)
6891 scopeProfile('true')
6892 } else {
6893 scopeProfile('false')
6894 }
6895 return
6896 }
6897 USE_PROFILE = profileArg.append(env, scope)
6898 scopeProfile(USE_PROFILE)
6899 } else {
6900 USE_PROFILE = scope.def(CURRENT_STATE, '.profile')
6901 }
6902
6903 var start = env.block()
6904 emitProfileStart(start)
6905 scope('if(', USE_PROFILE, '){', start, '}')
6906 var end = env.block()
6907 emitProfileEnd(end)
6908 scope.exit('if(', USE_PROFILE, '){', end, '}')
6909 }
6910
6911 function emitAttributes (env, scope, args, attributes, filter) {
6912 var shared = env.shared
6913
6914 function typeLength (x) {
6915 switch (x) {
6916 case GL_FLOAT_VEC2:
6917 case GL_INT_VEC2:
6918 case GL_BOOL_VEC2:
6919 return 2
6920 case GL_FLOAT_VEC3:
6921 case GL_INT_VEC3:
6922 case GL_BOOL_VEC3:
6923 return 3
6924 case GL_FLOAT_VEC4:
6925 case GL_INT_VEC4:
6926 case GL_BOOL_VEC4:
6927 return 4
6928 default:
6929 return 1
6930 }
6931 }
6932
6933 function emitBindAttribute (ATTRIBUTE, size, record) {
6934 var GL = shared.gl
6935
6936 var LOCATION = scope.def(ATTRIBUTE, '.location')
6937 var BINDING = scope.def(shared.attributes, '[', LOCATION, ']')
6938
6939 var STATE = record.state
6940 var BUFFER = record.buffer
6941 var CONST_COMPONENTS = [
6942 record.x,
6943 record.y,
6944 record.z,
6945 record.w
6946 ]
6947
6948 var COMMON_KEYS = [
6949 'buffer',
6950 'normalized',
6951 'offset',
6952 'stride'
6953 ]
6954
6955 function emitBuffer () {
6956 scope(
6957 'if(!', BINDING, '.buffer){',
6958 GL, '.enableVertexAttribArray(', LOCATION, ');}')
6959
6960 var TYPE = record.type
6961 var SIZE
6962 if (!record.size) {
6963 SIZE = size
6964 } else {
6965 SIZE = scope.def(record.size, '||', size)
6966 }
6967
6968 scope('if(',
6969 BINDING, '.type!==', TYPE, '||',
6970 BINDING, '.size!==', SIZE, '||',
6971 COMMON_KEYS.map(function (key) {
6972 return BINDING + '.' + key + '!==' + record[key]
6973 }).join('||'),
6974 '){',
6975 GL, '.bindBuffer(', GL_ARRAY_BUFFER$2, ',', BUFFER, '.buffer);',
6976 GL, '.vertexAttribPointer(', [
6977 LOCATION,
6978 SIZE,
6979 TYPE,
6980 record.normalized,
6981 record.stride,
6982 record.offset
6983 ], ');',
6984 BINDING, '.type=', TYPE, ';',
6985 BINDING, '.size=', SIZE, ';',
6986 COMMON_KEYS.map(function (key) {
6987 return BINDING + '.' + key + '=' + record[key] + ';'
6988 }).join(''),
6989 '}')
6990
6991 if (extInstancing) {
6992 var DIVISOR = record.divisor
6993 scope(
6994 'if(', BINDING, '.divisor!==', DIVISOR, '){',
6995 env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');',
6996 BINDING, '.divisor=', DIVISOR, ';}')
6997 }
6998 }
6999
7000 function emitConstant () {
7001 scope(
7002 'if(', BINDING, '.buffer){',
7003 GL, '.disableVertexAttribArray(', LOCATION, ');',
7004 BINDING, '.buffer=null;',
7005 '}if(', CUTE_COMPONENTS.map(function (c, i) {
7006 return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i]
7007 }).join('||'), '){',
7008 GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');',
7009 CUTE_COMPONENTS.map(function (c, i) {
7010 return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';'
7011 }).join(''),
7012 '}')
7013 }
7014
7015 if (STATE === ATTRIB_STATE_POINTER) {
7016 emitBuffer()
7017 } else if (STATE === ATTRIB_STATE_CONSTANT) {
7018 emitConstant()
7019 } else {
7020 scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){')
7021 emitBuffer()
7022 scope('}else{')
7023 emitConstant()
7024 scope('}')
7025 }
7026 }
7027
7028 attributes.forEach(function (attribute) {
7029 var name = attribute.name
7030 var arg = args.attributes[name]
7031 var record
7032 if (arg) {
7033 if (!filter(arg)) {
7034 return
7035 }
7036 record = arg.append(env, scope)
7037 } else {
7038 if (!filter(SCOPE_DECL)) {
7039 return
7040 }
7041 var scopeAttrib = env.scopeAttrib(name)
7042
7043 record = {}
7044 Object.keys(new AttributeRecord()).forEach(function (key) {
7045 record[key] = scope.def(scopeAttrib, '.', key)
7046 })
7047 }
7048 emitBindAttribute(
7049 env.link(attribute), typeLength(attribute.info.type), record)
7050 })
7051 }
7052
7053 function emitUniforms (env, scope, args, uniforms, filter) {
7054 var shared = env.shared
7055 var GL = shared.gl
7056
7057 var infix
7058 for (var i = 0; i < uniforms.length; ++i) {
7059 var uniform = uniforms[i]
7060 var name = uniform.name
7061 var type = uniform.info.type
7062 var arg = args.uniforms[name]
7063 var UNIFORM = env.link(uniform)
7064 var LOCATION = UNIFORM + '.location'
7065
7066 var VALUE
7067 if (arg) {
7068 if (!filter(arg)) {
7069 continue
7070 }
7071 if (isStatic(arg)) {
7072 var value = arg.value
7073
7074 if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) {
7075
7076 var TEX_VALUE = env.link(value._texture || value.color[0]._texture)
7077 scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());')
7078 scope.exit(TEX_VALUE, '.unbind();')
7079 } else if (
7080 type === GL_FLOAT_MAT2 ||
7081 type === GL_FLOAT_MAT3 ||
7082 type === GL_FLOAT_MAT4) {
7083
7084 var MAT_VALUE = env.global.def('new Float32Array([' +
7085 Array.prototype.slice.call(value) + '])')
7086 var dim = 2
7087 if (type === GL_FLOAT_MAT3) {
7088 dim = 3
7089 } else if (type === GL_FLOAT_MAT4) {
7090 dim = 4
7091 }
7092 scope(
7093 GL, '.uniformMatrix', dim, 'fv(',
7094 LOCATION, ',false,', MAT_VALUE, ');')
7095 } else {
7096 switch (type) {
7097 case GL_FLOAT$7:
7098
7099 infix = '1f'
7100 break
7101 case GL_FLOAT_VEC2:
7102
7103 infix = '2f'
7104 break
7105 case GL_FLOAT_VEC3:
7106
7107 infix = '3f'
7108 break
7109 case GL_FLOAT_VEC4:
7110
7111 infix = '4f'
7112 break
7113 case GL_BOOL:
7114
7115 infix = '1i'
7116 break
7117 case GL_INT$2:
7118
7119 infix = '1i'
7120 break
7121 case GL_BOOL_VEC2:
7122
7123 infix = '2i'
7124 break
7125 case GL_INT_VEC2:
7126
7127 infix = '2i'
7128 break
7129 case GL_BOOL_VEC3:
7130
7131 infix = '3i'
7132 break
7133 case GL_INT_VEC3:
7134
7135 infix = '3i'
7136 break
7137 case GL_BOOL_VEC4:
7138
7139 infix = '4i'
7140 break
7141 case GL_INT_VEC4:
7142
7143 infix = '4i'
7144 break
7145 }
7146 scope(GL, '.uniform', infix, '(', LOCATION, ',',
7147 isArrayLike(value) ? Array.prototype.slice.call(value) : value,
7148 ');')
7149 }
7150 continue
7151 } else {
7152 VALUE = arg.append(env, scope)
7153 }
7154 } else {
7155 if (!filter(SCOPE_DECL)) {
7156 continue
7157 }
7158 VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']')
7159 }
7160
7161 if (type === GL_SAMPLER_2D) {
7162 scope(
7163 'if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){',
7164 VALUE, '=', VALUE, '.color[0];',
7165 '}')
7166 } else if (type === GL_SAMPLER_CUBE) {
7167 scope(
7168 'if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){',
7169 VALUE, '=', VALUE, '.color[0];',
7170 '}')
7171 }
7172
7173 // perform type validation
7174
7175
7176 var unroll = 1
7177 switch (type) {
7178 case GL_SAMPLER_2D:
7179 case GL_SAMPLER_CUBE:
7180 var TEX = scope.def(VALUE, '._texture')
7181 scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());')
7182 scope.exit(TEX, '.unbind();')
7183 continue
7184
7185 case GL_INT$2:
7186 case GL_BOOL:
7187 infix = '1i'
7188 break
7189
7190 case GL_INT_VEC2:
7191 case GL_BOOL_VEC2:
7192 infix = '2i'
7193 unroll = 2
7194 break
7195
7196 case GL_INT_VEC3:
7197 case GL_BOOL_VEC3:
7198 infix = '3i'
7199 unroll = 3
7200 break
7201
7202 case GL_INT_VEC4:
7203 case GL_BOOL_VEC4:
7204 infix = '4i'
7205 unroll = 4
7206 break
7207
7208 case GL_FLOAT$7:
7209 infix = '1f'
7210 break
7211
7212 case GL_FLOAT_VEC2:
7213 infix = '2f'
7214 unroll = 2
7215 break
7216
7217 case GL_FLOAT_VEC3:
7218 infix = '3f'
7219 unroll = 3
7220 break
7221
7222 case GL_FLOAT_VEC4:
7223 infix = '4f'
7224 unroll = 4
7225 break
7226
7227 case GL_FLOAT_MAT2:
7228 infix = 'Matrix2fv'
7229 break
7230
7231 case GL_FLOAT_MAT3:
7232 infix = 'Matrix3fv'
7233 break
7234
7235 case GL_FLOAT_MAT4:
7236 infix = 'Matrix4fv'
7237 break
7238 }
7239
7240 scope(GL, '.uniform', infix, '(', LOCATION, ',')
7241 if (infix.charAt(0) === 'M') {
7242 var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2)
7243 var STORAGE = env.global.def('new Float32Array(', matSize, ')')
7244 scope(
7245 'false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(',
7246 loop(matSize, function (i) {
7247 return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']'
7248 }), ',', STORAGE, ')')
7249 } else if (unroll > 1) {
7250 scope(loop(unroll, function (i) {
7251 return VALUE + '[' + i + ']'
7252 }))
7253 } else {
7254 scope(VALUE)
7255 }
7256 scope(');')
7257 }
7258 }
7259
7260 function emitDraw (env, outer, inner, args) {
7261 var shared = env.shared
7262 var GL = shared.gl
7263 var DRAW_STATE = shared.draw
7264
7265 var drawOptions = args.draw
7266
7267 function emitElements () {
7268 var defn = drawOptions.elements
7269 var ELEMENTS
7270 var scope = outer
7271 if (defn) {
7272 if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
7273 scope = inner
7274 }
7275 ELEMENTS = defn.append(env, scope)
7276 } else {
7277 ELEMENTS = scope.def(DRAW_STATE, '.', S_ELEMENTS)
7278 }
7279 if (ELEMENTS) {
7280 scope(
7281 'if(' + ELEMENTS + ')' +
7282 GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$1 + ',' + ELEMENTS + '.buffer.buffer);')
7283 }
7284 return ELEMENTS
7285 }
7286
7287 function emitCount () {
7288 var defn = drawOptions.count
7289 var COUNT
7290 var scope = outer
7291 if (defn) {
7292 if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
7293 scope = inner
7294 }
7295 COUNT = defn.append(env, scope)
7296
7297 } else {
7298 COUNT = scope.def(DRAW_STATE, '.', S_COUNT)
7299
7300 }
7301 return COUNT
7302 }
7303
7304 var ELEMENTS = emitElements()
7305 function emitValue (name) {
7306 var defn = drawOptions[name]
7307 if (defn) {
7308 if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
7309 return defn.append(env, inner)
7310 } else {
7311 return defn.append(env, outer)
7312 }
7313 } else {
7314 return outer.def(DRAW_STATE, '.', name)
7315 }
7316 }
7317
7318 var PRIMITIVE = emitValue(S_PRIMITIVE)
7319 var OFFSET = emitValue(S_OFFSET)
7320
7321 var COUNT = emitCount()
7322 if (typeof COUNT === 'number') {
7323 if (COUNT === 0) {
7324 return
7325 }
7326 } else {
7327 inner('if(', COUNT, '){')
7328 inner.exit('}')
7329 }
7330
7331 var INSTANCES, EXT_INSTANCING
7332 if (extInstancing) {
7333 INSTANCES = emitValue(S_INSTANCES)
7334 EXT_INSTANCING = env.instancing
7335 }
7336
7337 var ELEMENT_TYPE = ELEMENTS + '.type'
7338
7339 var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements)
7340
7341 function emitInstancing () {
7342 function drawElements () {
7343 inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [
7344 PRIMITIVE,
7345 COUNT,
7346 ELEMENT_TYPE,
7347 OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)',
7348 INSTANCES
7349 ], ');')
7350 }
7351
7352 function drawArrays () {
7353 inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(',
7354 [PRIMITIVE, OFFSET, COUNT, INSTANCES], ');')
7355 }
7356
7357 if (ELEMENTS) {
7358 if (!elementsStatic) {
7359 inner('if(', ELEMENTS, '){')
7360 drawElements()
7361 inner('}else{')
7362 drawArrays()
7363 inner('}')
7364 } else {
7365 drawElements()
7366 }
7367 } else {
7368 drawArrays()
7369 }
7370 }
7371
7372 function emitRegular () {
7373 function drawElements () {
7374 inner(GL + '.drawElements(' + [
7375 PRIMITIVE,
7376 COUNT,
7377 ELEMENT_TYPE,
7378 OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)'
7379 ] + ');')
7380 }
7381
7382 function drawArrays () {
7383 inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');')
7384 }
7385
7386 if (ELEMENTS) {
7387 if (!elementsStatic) {
7388 inner('if(', ELEMENTS, '){')
7389 drawElements()
7390 inner('}else{')
7391 drawArrays()
7392 inner('}')
7393 } else {
7394 drawElements()
7395 }
7396 } else {
7397 drawArrays()
7398 }
7399 }
7400
7401 if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) {
7402 if (typeof INSTANCES === 'string') {
7403 inner('if(', INSTANCES, '>0){')
7404 emitInstancing()
7405 inner('}else if(', INSTANCES, '<0){')
7406 emitRegular()
7407 inner('}')
7408 } else {
7409 emitInstancing()
7410 }
7411 } else {
7412 emitRegular()
7413 }
7414 }
7415
7416 function createBody (emitBody, parentEnv, args, program, count) {
7417 var env = createREGLEnvironment()
7418 var scope = env.proc('body', count)
7419
7420 if (extInstancing) {
7421 env.instancing = scope.def(
7422 env.shared.extensions, '.angle_instanced_arrays')
7423 }
7424 emitBody(env, scope, args, program)
7425 return env.compile().body
7426 }
7427
7428 // ===================================================
7429 // ===================================================
7430 // DRAW PROC
7431 // ===================================================
7432 // ===================================================
7433 function emitDrawBody (env, draw, args, program) {
7434 injectExtensions(env, draw)
7435 if (args.useVAO) {
7436 if (args.drawVAO) {
7437 draw(env.shared.vao, '.setVAO(', args.drawVAO.append(env, draw), ');')
7438 } else {
7439 draw(env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);')
7440 }
7441 } else {
7442 draw(env.shared.vao, '.setVAO(null);')
7443 emitAttributes(env, draw, args, program.attributes, function () {
7444 return true
7445 })
7446 }
7447 emitUniforms(env, draw, args, program.uniforms, function () {
7448 return true
7449 })
7450 emitDraw(env, draw, draw, args)
7451 }
7452
7453 function emitDrawProc (env, args) {
7454 var draw = env.proc('draw', 1)
7455
7456 injectExtensions(env, draw)
7457
7458 emitContext(env, draw, args.context)
7459 emitPollFramebuffer(env, draw, args.framebuffer)
7460
7461 emitPollState(env, draw, args)
7462 emitSetOptions(env, draw, args.state)
7463
7464 emitProfile(env, draw, args, false, true)
7465
7466 var program = args.shader.progVar.append(env, draw)
7467 draw(env.shared.gl, '.useProgram(', program, '.program);')
7468
7469 if (args.shader.program) {
7470 emitDrawBody(env, draw, args, args.shader.program)
7471 } else {
7472 draw(env.shared.vao, '.setVAO(null);')
7473 var drawCache = env.global.def('{}')
7474 var PROG_ID = draw.def(program, '.id')
7475 var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']')
7476 draw(
7477 env.cond(CACHED_PROC)
7478 .then(CACHED_PROC, '.call(this,a0);')
7479 .else(
7480 CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=',
7481 env.link(function (program) {
7482 return createBody(emitDrawBody, env, args, program, 1)
7483 }), '(', program, ');',
7484 CACHED_PROC, '.call(this,a0);'))
7485 }
7486
7487 if (Object.keys(args.state).length > 0) {
7488 draw(env.shared.current, '.dirty=true;')
7489 }
7490 }
7491
7492 // ===================================================
7493 // ===================================================
7494 // BATCH PROC
7495 // ===================================================
7496 // ===================================================
7497
7498 function emitBatchDynamicShaderBody (env, scope, args, program) {
7499 env.batchId = 'a1'
7500
7501 injectExtensions(env, scope)
7502
7503 function all () {
7504 return true
7505 }
7506
7507 emitAttributes(env, scope, args, program.attributes, all)
7508 emitUniforms(env, scope, args, program.uniforms, all)
7509 emitDraw(env, scope, scope, args)
7510 }
7511
7512 function emitBatchBody (env, scope, args, program) {
7513 injectExtensions(env, scope)
7514
7515 var contextDynamic = args.contextDep
7516
7517 var BATCH_ID = scope.def()
7518 var PROP_LIST = 'a0'
7519 var NUM_PROPS = 'a1'
7520 var PROPS = scope.def()
7521 env.shared.props = PROPS
7522 env.batchId = BATCH_ID
7523
7524 var outer = env.scope()
7525 var inner = env.scope()
7526
7527 scope(
7528 outer.entry,
7529 'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){',
7530 PROPS, '=', PROP_LIST, '[', BATCH_ID, '];',
7531 inner,
7532 '}',
7533 outer.exit)
7534
7535 function isInnerDefn (defn) {
7536 return ((defn.contextDep && contextDynamic) || defn.propDep)
7537 }
7538
7539 function isOuterDefn (defn) {
7540 return !isInnerDefn(defn)
7541 }
7542
7543 if (args.needsContext) {
7544 emitContext(env, inner, args.context)
7545 }
7546 if (args.needsFramebuffer) {
7547 emitPollFramebuffer(env, inner, args.framebuffer)
7548 }
7549 emitSetOptions(env, inner, args.state, isInnerDefn)
7550
7551 if (args.profile && isInnerDefn(args.profile)) {
7552 emitProfile(env, inner, args, false, true)
7553 }
7554
7555 if (!program) {
7556 var progCache = env.global.def('{}')
7557 var PROGRAM = args.shader.progVar.append(env, inner)
7558 var PROG_ID = inner.def(PROGRAM, '.id')
7559 var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']')
7560 inner(
7561 env.shared.gl, '.useProgram(', PROGRAM, '.program);',
7562 'if(!', CACHED_PROC, '){',
7563 CACHED_PROC, '=', progCache, '[', PROG_ID, ']=',
7564 env.link(function (program) {
7565 return createBody(
7566 emitBatchDynamicShaderBody, env, args, program, 2)
7567 }), '(', PROGRAM, ');}',
7568 CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');')
7569 } else {
7570 if (args.useVAO) {
7571 if (args.drawVAO) {
7572 if (isInnerDefn(args.drawVAO)) {
7573 // vao is a prop
7574 inner(env.shared.vao, '.setVAO(', args.drawVAO.append(env, inner), ');')
7575 } else {
7576 // vao is invariant
7577 outer(env.shared.vao, '.setVAO(', args.drawVAO.append(env, outer), ');')
7578 }
7579 } else {
7580 // scoped vao binding
7581 outer(env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);')
7582 }
7583 } else {
7584 outer(env.shared.vao, '.setVAO(null);')
7585 emitAttributes(env, outer, args, program.attributes, isOuterDefn)
7586 emitAttributes(env, inner, args, program.attributes, isInnerDefn)
7587 }
7588 emitUniforms(env, outer, args, program.uniforms, isOuterDefn)
7589 emitUniforms(env, inner, args, program.uniforms, isInnerDefn)
7590 emitDraw(env, outer, inner, args)
7591 }
7592 }
7593
7594 function emitBatchProc (env, args) {
7595 var batch = env.proc('batch', 2)
7596 env.batchId = '0'
7597
7598 injectExtensions(env, batch)
7599
7600 // Check if any context variables depend on props
7601 var contextDynamic = false
7602 var needsContext = true
7603 Object.keys(args.context).forEach(function (name) {
7604 contextDynamic = contextDynamic || args.context[name].propDep
7605 })
7606 if (!contextDynamic) {
7607 emitContext(env, batch, args.context)
7608 needsContext = false
7609 }
7610
7611 // framebuffer state affects framebufferWidth/height context vars
7612 var framebuffer = args.framebuffer
7613 var needsFramebuffer = false
7614 if (framebuffer) {
7615 if (framebuffer.propDep) {
7616 contextDynamic = needsFramebuffer = true
7617 } else if (framebuffer.contextDep && contextDynamic) {
7618 needsFramebuffer = true
7619 }
7620 if (!needsFramebuffer) {
7621 emitPollFramebuffer(env, batch, framebuffer)
7622 }
7623 } else {
7624 emitPollFramebuffer(env, batch, null)
7625 }
7626
7627 // viewport is weird because it can affect context vars
7628 if (args.state.viewport && args.state.viewport.propDep) {
7629 contextDynamic = true
7630 }
7631
7632 function isInnerDefn (defn) {
7633 return (defn.contextDep && contextDynamic) || defn.propDep
7634 }
7635
7636 // set webgl options
7637 emitPollState(env, batch, args)
7638 emitSetOptions(env, batch, args.state, function (defn) {
7639 return !isInnerDefn(defn)
7640 })
7641
7642 if (!args.profile || !isInnerDefn(args.profile)) {
7643 emitProfile(env, batch, args, false, 'a1')
7644 }
7645
7646 // Save these values to args so that the batch body routine can use them
7647 args.contextDep = contextDynamic
7648 args.needsContext = needsContext
7649 args.needsFramebuffer = needsFramebuffer
7650
7651 // determine if shader is dynamic
7652 var progDefn = args.shader.progVar
7653 if ((progDefn.contextDep && contextDynamic) || progDefn.propDep) {
7654 emitBatchBody(
7655 env,
7656 batch,
7657 args,
7658 null)
7659 } else {
7660 var PROGRAM = progDefn.append(env, batch)
7661 batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);')
7662 if (args.shader.program) {
7663 emitBatchBody(
7664 env,
7665 batch,
7666 args,
7667 args.shader.program)
7668 } else {
7669 batch(env.shared.vao, '.setVAO(null);')
7670 var batchCache = env.global.def('{}')
7671 var PROG_ID = batch.def(PROGRAM, '.id')
7672 var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']')
7673 batch(
7674 env.cond(CACHED_PROC)
7675 .then(CACHED_PROC, '.call(this,a0,a1);')
7676 .else(
7677 CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=',
7678 env.link(function (program) {
7679 return createBody(emitBatchBody, env, args, program, 2)
7680 }), '(', PROGRAM, ');',
7681 CACHED_PROC, '.call(this,a0,a1);'))
7682 }
7683 }
7684
7685 if (Object.keys(args.state).length > 0) {
7686 batch(env.shared.current, '.dirty=true;')
7687 }
7688 }
7689
7690 // ===================================================
7691 // ===================================================
7692 // SCOPE COMMAND
7693 // ===================================================
7694 // ===================================================
7695 function emitScopeProc (env, args) {
7696 var scope = env.proc('scope', 3)
7697 env.batchId = 'a2'
7698
7699 var shared = env.shared
7700 var CURRENT_STATE = shared.current
7701
7702 emitContext(env, scope, args.context)
7703
7704 if (args.framebuffer) {
7705 args.framebuffer.append(env, scope)
7706 }
7707
7708 sortState(Object.keys(args.state)).forEach(function (name) {
7709 var defn = args.state[name]
7710 var value = defn.append(env, scope)
7711 if (isArrayLike(value)) {
7712 value.forEach(function (v, i) {
7713 scope.set(env.next[name], '[' + i + ']', v)
7714 })
7715 } else {
7716 scope.set(shared.next, '.' + name, value)
7717 }
7718 })
7719
7720 emitProfile(env, scope, args, true, true)
7721
7722 ;[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach(
7723 function (opt) {
7724 var variable = args.draw[opt]
7725 if (!variable) {
7726 return
7727 }
7728 scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope))
7729 })
7730
7731 Object.keys(args.uniforms).forEach(function (opt) {
7732 scope.set(
7733 shared.uniforms,
7734 '[' + stringStore.id(opt) + ']',
7735 args.uniforms[opt].append(env, scope))
7736 })
7737
7738 Object.keys(args.attributes).forEach(function (name) {
7739 var record = args.attributes[name].append(env, scope)
7740 var scopeAttrib = env.scopeAttrib(name)
7741 Object.keys(new AttributeRecord()).forEach(function (prop) {
7742 scope.set(scopeAttrib, '.' + prop, record[prop])
7743 })
7744 })
7745
7746 if (args.scopeVAO) {
7747 scope.set(shared.vao, '.targetVAO', args.scopeVAO.append(env, scope))
7748 }
7749
7750 function saveShader (name) {
7751 var shader = args.shader[name]
7752 if (shader) {
7753 scope.set(shared.shader, '.' + name, shader.append(env, scope))
7754 }
7755 }
7756 saveShader(S_VERT)
7757 saveShader(S_FRAG)
7758
7759 if (Object.keys(args.state).length > 0) {
7760 scope(CURRENT_STATE, '.dirty=true;')
7761 scope.exit(CURRENT_STATE, '.dirty=true;')
7762 }
7763
7764 scope('a1(', env.shared.context, ',a0,', env.batchId, ');')
7765 }
7766
7767 function isDynamicObject (object) {
7768 if (typeof object !== 'object' || isArrayLike(object)) {
7769 return
7770 }
7771 var props = Object.keys(object)
7772 for (var i = 0; i < props.length; ++i) {
7773 if (dynamic.isDynamic(object[props[i]])) {
7774 return true
7775 }
7776 }
7777 return false
7778 }
7779
7780 function splatObject (env, options, name) {
7781 var object = options.static[name]
7782 if (!object || !isDynamicObject(object)) {
7783 return
7784 }
7785
7786 var globals = env.global
7787 var keys = Object.keys(object)
7788 var thisDep = false
7789 var contextDep = false
7790 var propDep = false
7791 var objectRef = env.global.def('{}')
7792 keys.forEach(function (key) {
7793 var value = object[key]
7794 if (dynamic.isDynamic(value)) {
7795 if (typeof value === 'function') {
7796 value = object[key] = dynamic.unbox(value)
7797 }
7798 var deps = createDynamicDecl(value, null)
7799 thisDep = thisDep || deps.thisDep
7800 propDep = propDep || deps.propDep
7801 contextDep = contextDep || deps.contextDep
7802 } else {
7803 globals(objectRef, '.', key, '=')
7804 switch (typeof value) {
7805 case 'number':
7806 globals(value)
7807 break
7808 case 'string':
7809 globals('"', value, '"')
7810 break
7811 case 'object':
7812 if (Array.isArray(value)) {
7813 globals('[', value.join(), ']')
7814 }
7815 break
7816 default:
7817 globals(env.link(value))
7818 break
7819 }
7820 globals(';')
7821 }
7822 })
7823
7824 function appendBlock (env, block) {
7825 keys.forEach(function (key) {
7826 var value = object[key]
7827 if (!dynamic.isDynamic(value)) {
7828 return
7829 }
7830 var ref = env.invoke(block, value)
7831 block(objectRef, '.', key, '=', ref, ';')
7832 })
7833 }
7834
7835 options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, {
7836 thisDep: thisDep,
7837 contextDep: contextDep,
7838 propDep: propDep,
7839 ref: objectRef,
7840 append: appendBlock
7841 })
7842 delete options.static[name]
7843 }
7844
7845 // ===========================================================================
7846 // ===========================================================================
7847 // MAIN DRAW COMMAND
7848 // ===========================================================================
7849 // ===========================================================================
7850 function compileCommand (options, attributes, uniforms, context, stats) {
7851 var env = createREGLEnvironment()
7852
7853 // link stats, so that we can easily access it in the program.
7854 env.stats = env.link(stats)
7855
7856 // splat options and attributes to allow for dynamic nested properties
7857 Object.keys(attributes.static).forEach(function (key) {
7858 splatObject(env, attributes, key)
7859 })
7860 NESTED_OPTIONS.forEach(function (name) {
7861 splatObject(env, options, name)
7862 })
7863
7864 var args = parseArguments(options, attributes, uniforms, context, env)
7865
7866 emitDrawProc(env, args)
7867 emitScopeProc(env, args)
7868 emitBatchProc(env, args)
7869
7870 return env.compile()
7871 }
7872
7873 // ===========================================================================
7874 // ===========================================================================
7875 // POLL / REFRESH
7876 // ===========================================================================
7877 // ===========================================================================
7878 return {
7879 next: nextState,
7880 current: currentState,
7881 procs: (function () {
7882 var env = createREGLEnvironment()
7883 var poll = env.proc('poll')
7884 var refresh = env.proc('refresh')
7885 var common = env.block()
7886 poll(common)
7887 refresh(common)
7888
7889 var shared = env.shared
7890 var GL = shared.gl
7891 var NEXT_STATE = shared.next
7892 var CURRENT_STATE = shared.current
7893
7894 common(CURRENT_STATE, '.dirty=false;')
7895
7896 emitPollFramebuffer(env, poll)
7897 emitPollFramebuffer(env, refresh, null, true)
7898
7899 // Refresh updates all attribute state changes
7900 var INSTANCING
7901 if (extInstancing) {
7902 INSTANCING = env.link(extInstancing)
7903 }
7904
7905 // update vertex array bindings
7906 if (extensions.oes_vertex_array_object) {
7907 refresh(env.link(extensions.oes_vertex_array_object), '.bindVertexArrayOES(null);')
7908 }
7909 for (var i = 0; i < limits.maxAttributes; ++i) {
7910 var BINDING = refresh.def(shared.attributes, '[', i, ']')
7911 var ifte = env.cond(BINDING, '.buffer')
7912 ifte.then(
7913 GL, '.enableVertexAttribArray(', i, ');',
7914 GL, '.bindBuffer(',
7915 GL_ARRAY_BUFFER$2, ',',
7916 BINDING, '.buffer.buffer);',
7917 GL, '.vertexAttribPointer(',
7918 i, ',',
7919 BINDING, '.size,',
7920 BINDING, '.type,',
7921 BINDING, '.normalized,',
7922 BINDING, '.stride,',
7923 BINDING, '.offset);'
7924 ).else(
7925 GL, '.disableVertexAttribArray(', i, ');',
7926 GL, '.vertexAttrib4f(',
7927 i, ',',
7928 BINDING, '.x,',
7929 BINDING, '.y,',
7930 BINDING, '.z,',
7931 BINDING, '.w);',
7932 BINDING, '.buffer=null;')
7933 refresh(ifte)
7934 if (extInstancing) {
7935 refresh(
7936 INSTANCING, '.vertexAttribDivisorANGLE(',
7937 i, ',',
7938 BINDING, '.divisor);')
7939 }
7940 }
7941 refresh(
7942 env.shared.vao, '.currentVAO=null;',
7943 env.shared.vao, '.setVAO(', env.shared.vao, '.targetVAO);')
7944
7945 Object.keys(GL_FLAGS).forEach(function (flag) {
7946 var cap = GL_FLAGS[flag]
7947 var NEXT = common.def(NEXT_STATE, '.', flag)
7948 var block = env.block()
7949 block('if(', NEXT, '){',
7950 GL, '.enable(', cap, ')}else{',
7951 GL, '.disable(', cap, ')}',
7952 CURRENT_STATE, '.', flag, '=', NEXT, ';')
7953 refresh(block)
7954 poll(
7955 'if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){',
7956 block,
7957 '}')
7958 })
7959
7960 Object.keys(GL_VARIABLES).forEach(function (name) {
7961 var func = GL_VARIABLES[name]
7962 var init = currentState[name]
7963 var NEXT, CURRENT
7964 var block = env.block()
7965 block(GL, '.', func, '(')
7966 if (isArrayLike(init)) {
7967 var n = init.length
7968 NEXT = env.global.def(NEXT_STATE, '.', name)
7969 CURRENT = env.global.def(CURRENT_STATE, '.', name)
7970 block(
7971 loop(n, function (i) {
7972 return NEXT + '[' + i + ']'
7973 }), ');',
7974 loop(n, function (i) {
7975 return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];'
7976 }).join(''))
7977 poll(
7978 'if(', loop(n, function (i) {
7979 return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']'
7980 }).join('||'), '){',
7981 block,
7982 '}')
7983 } else {
7984 NEXT = common.def(NEXT_STATE, '.', name)
7985 CURRENT = common.def(CURRENT_STATE, '.', name)
7986 block(
7987 NEXT, ');',
7988 CURRENT_STATE, '.', name, '=', NEXT, ';')
7989 poll(
7990 'if(', NEXT, '!==', CURRENT, '){',
7991 block,
7992 '}')
7993 }
7994 refresh(block)
7995 })
7996
7997 return env.compile()
7998 })(),
7999 compile: compileCommand
8000 }
8001}
8002
8003function stats () {
8004 return {
8005 vaoCount: 0,
8006 bufferCount: 0,
8007 elementsCount: 0,
8008 framebufferCount: 0,
8009 shaderCount: 0,
8010 textureCount: 0,
8011 cubeCount: 0,
8012 renderbufferCount: 0,
8013 maxTextureUnits: 0
8014 }
8015}
8016
8017var GL_QUERY_RESULT_EXT = 0x8866
8018var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867
8019var GL_TIME_ELAPSED_EXT = 0x88BF
8020
8021var createTimer = function (gl, extensions) {
8022 if (!extensions.ext_disjoint_timer_query) {
8023 return null
8024 }
8025
8026 // QUERY POOL BEGIN
8027 var queryPool = []
8028 function allocQuery () {
8029 return queryPool.pop() || extensions.ext_disjoint_timer_query.createQueryEXT()
8030 }
8031 function freeQuery (query) {
8032 queryPool.push(query)
8033 }
8034 // QUERY POOL END
8035
8036 var pendingQueries = []
8037 function beginQuery (stats) {
8038 var query = allocQuery()
8039 extensions.ext_disjoint_timer_query.beginQueryEXT(GL_TIME_ELAPSED_EXT, query)
8040 pendingQueries.push(query)
8041 pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats)
8042 }
8043
8044 function endQuery () {
8045 extensions.ext_disjoint_timer_query.endQueryEXT(GL_TIME_ELAPSED_EXT)
8046 }
8047
8048 //
8049 // Pending stats pool.
8050 //
8051 function PendingStats () {
8052 this.startQueryIndex = -1
8053 this.endQueryIndex = -1
8054 this.sum = 0
8055 this.stats = null
8056 }
8057 var pendingStatsPool = []
8058 function allocPendingStats () {
8059 return pendingStatsPool.pop() || new PendingStats()
8060 }
8061 function freePendingStats (pendingStats) {
8062 pendingStatsPool.push(pendingStats)
8063 }
8064 // Pending stats pool end
8065
8066 var pendingStats = []
8067 function pushScopeStats (start, end, stats) {
8068 var ps = allocPendingStats()
8069 ps.startQueryIndex = start
8070 ps.endQueryIndex = end
8071 ps.sum = 0
8072 ps.stats = stats
8073 pendingStats.push(ps)
8074 }
8075
8076 // we should call this at the beginning of the frame,
8077 // in order to update gpuTime
8078 var timeSum = []
8079 var queryPtr = []
8080 function update () {
8081 var ptr, i
8082
8083 var n = pendingQueries.length
8084 if (n === 0) {
8085 return
8086 }
8087
8088 // Reserve space
8089 queryPtr.length = Math.max(queryPtr.length, n + 1)
8090 timeSum.length = Math.max(timeSum.length, n + 1)
8091 timeSum[0] = 0
8092 queryPtr[0] = 0
8093
8094 // Update all pending timer queries
8095 var queryTime = 0
8096 ptr = 0
8097 for (i = 0; i < pendingQueries.length; ++i) {
8098 var query = pendingQueries[i]
8099 if (extensions.ext_disjoint_timer_query.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) {
8100 queryTime += extensions.ext_disjoint_timer_query.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT)
8101 freeQuery(query)
8102 } else {
8103 pendingQueries[ptr++] = query
8104 }
8105 timeSum[i + 1] = queryTime
8106 queryPtr[i + 1] = ptr
8107 }
8108 pendingQueries.length = ptr
8109
8110 // Update all pending stat queries
8111 ptr = 0
8112 for (i = 0; i < pendingStats.length; ++i) {
8113 var stats = pendingStats[i]
8114 var start = stats.startQueryIndex
8115 var end = stats.endQueryIndex
8116 stats.sum += timeSum[end] - timeSum[start]
8117 var startPtr = queryPtr[start]
8118 var endPtr = queryPtr[end]
8119 if (endPtr === startPtr) {
8120 stats.stats.gpuTime += stats.sum / 1e6
8121 freePendingStats(stats)
8122 } else {
8123 stats.startQueryIndex = startPtr
8124 stats.endQueryIndex = endPtr
8125 pendingStats[ptr++] = stats
8126 }
8127 }
8128 pendingStats.length = ptr
8129 }
8130
8131 return {
8132 beginQuery: beginQuery,
8133 endQuery: endQuery,
8134 pushScopeStats: pushScopeStats,
8135 update: update,
8136 getNumPendingQueries: function () {
8137 return pendingQueries.length
8138 },
8139 clear: function () {
8140 queryPool.push.apply(queryPool, pendingQueries)
8141 for (var i = 0; i < queryPool.length; i++) {
8142 extensions.ext_disjoint_timer_query.deleteQueryEXT(queryPool[i])
8143 }
8144 pendingQueries.length = 0
8145 queryPool.length = 0
8146 },
8147 restore: function () {
8148 pendingQueries.length = 0
8149 queryPool.length = 0
8150 }
8151 }
8152}
8153
8154var GL_COLOR_BUFFER_BIT = 16384
8155var GL_DEPTH_BUFFER_BIT = 256
8156var GL_STENCIL_BUFFER_BIT = 1024
8157
8158var GL_ARRAY_BUFFER = 34962
8159
8160var CONTEXT_LOST_EVENT = 'webglcontextlost'
8161var CONTEXT_RESTORED_EVENT = 'webglcontextrestored'
8162
8163var DYN_PROP = 1
8164var DYN_CONTEXT = 2
8165var DYN_STATE = 3
8166
8167function find (haystack, needle) {
8168 for (var i = 0; i < haystack.length; ++i) {
8169 if (haystack[i] === needle) {
8170 return i
8171 }
8172 }
8173 return -1
8174}
8175
8176function wrapREGL (args) {
8177 var config = parseArgs(args)
8178 if (!config) {
8179 return null
8180 }
8181
8182 var gl = config.gl
8183 var glAttributes = gl.getContextAttributes()
8184 var contextLost = gl.isContextLost()
8185
8186 var extensionState = createExtensionCache(gl, config)
8187 if (!extensionState) {
8188 return null
8189 }
8190
8191 var stringStore = createStringStore()
8192 var stats$$1 = stats()
8193 var extensions = extensionState.extensions
8194 var timer = createTimer(gl, extensions)
8195
8196 var START_TIME = clock()
8197 var WIDTH = gl.drawingBufferWidth
8198 var HEIGHT = gl.drawingBufferHeight
8199
8200 var contextState = {
8201 tick: 0,
8202 time: 0,
8203 viewportWidth: WIDTH,
8204 viewportHeight: HEIGHT,
8205 framebufferWidth: WIDTH,
8206 framebufferHeight: HEIGHT,
8207 drawingBufferWidth: WIDTH,
8208 drawingBufferHeight: HEIGHT,
8209 pixelRatio: config.pixelRatio
8210 }
8211 var uniformState = {}
8212 var drawState = {
8213 elements: null,
8214 primitive: 4, // GL_TRIANGLES
8215 count: -1,
8216 offset: 0,
8217 instances: -1
8218 }
8219
8220 var limits = wrapLimits(gl, extensions)
8221 var bufferState = wrapBufferState(
8222 gl,
8223 stats$$1,
8224 config,
8225 destroyBuffer)
8226 var attributeState = wrapAttributeState(
8227 gl,
8228 extensions,
8229 limits,
8230 stats$$1,
8231 bufferState)
8232 function destroyBuffer (buffer) {
8233 return attributeState.destroyBuffer(buffer)
8234 }
8235 var elementState = wrapElementsState(gl, extensions, bufferState, stats$$1)
8236 var shaderState = wrapShaderState(gl, stringStore, stats$$1, config)
8237 var textureState = createTextureSet(
8238 gl,
8239 extensions,
8240 limits,
8241 function () { core.procs.poll() },
8242 contextState,
8243 stats$$1,
8244 config)
8245 var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats$$1, config)
8246 var framebufferState = wrapFBOState(
8247 gl,
8248 extensions,
8249 limits,
8250 textureState,
8251 renderbufferState,
8252 stats$$1)
8253 var core = reglCore(
8254 gl,
8255 stringStore,
8256 extensions,
8257 limits,
8258 bufferState,
8259 elementState,
8260 textureState,
8261 framebufferState,
8262 uniformState,
8263 attributeState,
8264 shaderState,
8265 drawState,
8266 contextState,
8267 timer,
8268 config)
8269 var readPixels = wrapReadPixels(
8270 gl,
8271 framebufferState,
8272 core.procs.poll,
8273 contextState,
8274 glAttributes, extensions, limits)
8275
8276 var nextState = core.next
8277 var canvas = gl.canvas
8278
8279 var rafCallbacks = []
8280 var lossCallbacks = []
8281 var restoreCallbacks = []
8282 var destroyCallbacks = [config.onDestroy]
8283
8284 var activeRAF = null
8285 function handleRAF () {
8286 if (rafCallbacks.length === 0) {
8287 if (timer) {
8288 timer.update()
8289 }
8290 activeRAF = null
8291 return
8292 }
8293
8294 // schedule next animation frame
8295 activeRAF = raf.next(handleRAF)
8296
8297 // poll for changes
8298 poll()
8299
8300 // fire a callback for all pending rafs
8301 for (var i = rafCallbacks.length - 1; i >= 0; --i) {
8302 var cb = rafCallbacks[i]
8303 if (cb) {
8304 cb(contextState, null, 0)
8305 }
8306 }
8307
8308 // flush all pending webgl calls
8309 gl.flush()
8310
8311 // poll GPU timers *after* gl.flush so we don't delay command dispatch
8312 if (timer) {
8313 timer.update()
8314 }
8315 }
8316
8317 function startRAF () {
8318 if (!activeRAF && rafCallbacks.length > 0) {
8319 activeRAF = raf.next(handleRAF)
8320 }
8321 }
8322
8323 function stopRAF () {
8324 if (activeRAF) {
8325 raf.cancel(handleRAF)
8326 activeRAF = null
8327 }
8328 }
8329
8330 function handleContextLoss (event) {
8331 event.preventDefault()
8332
8333 // set context lost flag
8334 contextLost = true
8335
8336 // pause request animation frame
8337 stopRAF()
8338
8339 // lose context
8340 lossCallbacks.forEach(function (cb) {
8341 cb()
8342 })
8343 }
8344
8345 function handleContextRestored (event) {
8346 // clear error code
8347 gl.getError()
8348
8349 // clear context lost flag
8350 contextLost = false
8351
8352 // refresh state
8353 extensionState.restore()
8354 shaderState.restore()
8355 bufferState.restore()
8356 textureState.restore()
8357 renderbufferState.restore()
8358 framebufferState.restore()
8359 attributeState.restore()
8360 if (timer) {
8361 timer.restore()
8362 }
8363
8364 // refresh state
8365 core.procs.refresh()
8366
8367 // restart RAF
8368 startRAF()
8369
8370 // restore context
8371 restoreCallbacks.forEach(function (cb) {
8372 cb()
8373 })
8374 }
8375
8376 if (canvas) {
8377 canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false)
8378 canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false)
8379 }
8380
8381 function destroy () {
8382 rafCallbacks.length = 0
8383 stopRAF()
8384
8385 if (canvas) {
8386 canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss)
8387 canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored)
8388 }
8389
8390 shaderState.clear()
8391 framebufferState.clear()
8392 renderbufferState.clear()
8393 textureState.clear()
8394 elementState.clear()
8395 bufferState.clear()
8396 attributeState.clear()
8397
8398 if (timer) {
8399 timer.clear()
8400 }
8401
8402 destroyCallbacks.forEach(function (cb) {
8403 cb()
8404 })
8405 }
8406
8407 function compileProcedure (options) {
8408
8409
8410
8411 function flattenNestedOptions (options) {
8412 var result = extend({}, options)
8413 delete result.uniforms
8414 delete result.attributes
8415 delete result.context
8416 delete result.vao
8417
8418 if ('stencil' in result && result.stencil.op) {
8419 result.stencil.opBack = result.stencil.opFront = result.stencil.op
8420 delete result.stencil.op
8421 }
8422
8423 function merge (name) {
8424 if (name in result) {
8425 var child = result[name]
8426 delete result[name]
8427 Object.keys(child).forEach(function (prop) {
8428 result[name + '.' + prop] = child[prop]
8429 })
8430 }
8431 }
8432 merge('blend')
8433 merge('depth')
8434 merge('cull')
8435 merge('stencil')
8436 merge('polygonOffset')
8437 merge('scissor')
8438 merge('sample')
8439
8440 if ('vao' in options) {
8441 result.vao = options.vao
8442 }
8443
8444 return result
8445 }
8446
8447 function separateDynamic (object) {
8448 var staticItems = {}
8449 var dynamicItems = {}
8450 Object.keys(object).forEach(function (option) {
8451 var value = object[option]
8452 if (dynamic.isDynamic(value)) {
8453 dynamicItems[option] = dynamic.unbox(value, option)
8454 } else {
8455 staticItems[option] = value
8456 }
8457 })
8458 return {
8459 dynamic: dynamicItems,
8460 static: staticItems
8461 }
8462 }
8463
8464 // Treat context variables separate from other dynamic variables
8465 var context = separateDynamic(options.context || {})
8466 var uniforms = separateDynamic(options.uniforms || {})
8467 var attributes = separateDynamic(options.attributes || {})
8468 var opts = separateDynamic(flattenNestedOptions(options))
8469
8470 var stats$$1 = {
8471 gpuTime: 0.0,
8472 cpuTime: 0.0,
8473 count: 0
8474 }
8475
8476 var compiled = core.compile(opts, attributes, uniforms, context, stats$$1)
8477
8478 var draw = compiled.draw
8479 var batch = compiled.batch
8480 var scope = compiled.scope
8481
8482 // FIXME: we should modify code generation for batch commands so this
8483 // isn't necessary
8484 var EMPTY_ARRAY = []
8485 function reserve (count) {
8486 while (EMPTY_ARRAY.length < count) {
8487 EMPTY_ARRAY.push(null)
8488 }
8489 return EMPTY_ARRAY
8490 }
8491
8492 function REGLCommand (args, body) {
8493 var i
8494 if (contextLost) {
8495
8496 }
8497 if (typeof args === 'function') {
8498 return scope.call(this, null, args, 0)
8499 } else if (typeof body === 'function') {
8500 if (typeof args === 'number') {
8501 for (i = 0; i < args; ++i) {
8502 scope.call(this, null, body, i)
8503 }
8504 } else if (Array.isArray(args)) {
8505 for (i = 0; i < args.length; ++i) {
8506 scope.call(this, args[i], body, i)
8507 }
8508 } else {
8509 return scope.call(this, args, body, 0)
8510 }
8511 } else if (typeof args === 'number') {
8512 if (args > 0) {
8513 return batch.call(this, reserve(args | 0), args | 0)
8514 }
8515 } else if (Array.isArray(args)) {
8516 if (args.length) {
8517 return batch.call(this, args, args.length)
8518 }
8519 } else {
8520 return draw.call(this, args)
8521 }
8522 }
8523
8524 return extend(REGLCommand, {
8525 stats: stats$$1
8526 })
8527 }
8528
8529 var setFBO = framebufferState.setFBO = compileProcedure({
8530 framebuffer: dynamic.define.call(null, DYN_PROP, 'framebuffer')
8531 })
8532
8533 function clearImpl (_, options) {
8534 var clearFlags = 0
8535 core.procs.poll()
8536
8537 var c = options.color
8538 if (c) {
8539 gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0)
8540 clearFlags |= GL_COLOR_BUFFER_BIT
8541 }
8542 if ('depth' in options) {
8543 gl.clearDepth(+options.depth)
8544 clearFlags |= GL_DEPTH_BUFFER_BIT
8545 }
8546 if ('stencil' in options) {
8547 gl.clearStencil(options.stencil | 0)
8548 clearFlags |= GL_STENCIL_BUFFER_BIT
8549 }
8550
8551
8552 gl.clear(clearFlags)
8553 }
8554
8555 function clear (options) {
8556
8557 if ('framebuffer' in options) {
8558 if (options.framebuffer &&
8559 options.framebuffer_reglType === 'framebufferCube') {
8560 for (var i = 0; i < 6; ++i) {
8561 setFBO(extend({
8562 framebuffer: options.framebuffer.faces[i]
8563 }, options), clearImpl)
8564 }
8565 } else {
8566 setFBO(options, clearImpl)
8567 }
8568 } else {
8569 clearImpl(null, options)
8570 }
8571 }
8572
8573 function frame (cb) {
8574
8575 rafCallbacks.push(cb)
8576
8577 function cancel () {
8578 // FIXME: should we check something other than equals cb here?
8579 // what if a user calls frame twice with the same callback...
8580 //
8581 var i = find(rafCallbacks, cb)
8582
8583 function pendingCancel () {
8584 var index = find(rafCallbacks, pendingCancel)
8585 rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1]
8586 rafCallbacks.length -= 1
8587 if (rafCallbacks.length <= 0) {
8588 stopRAF()
8589 }
8590 }
8591 rafCallbacks[i] = pendingCancel
8592 }
8593
8594 startRAF()
8595
8596 return {
8597 cancel: cancel
8598 }
8599 }
8600
8601 // poll viewport
8602 function pollViewport () {
8603 var viewport = nextState.viewport
8604 var scissorBox = nextState.scissor_box
8605 viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0
8606 contextState.viewportWidth =
8607 contextState.framebufferWidth =
8608 contextState.drawingBufferWidth =
8609 viewport[2] =
8610 scissorBox[2] = gl.drawingBufferWidth
8611 contextState.viewportHeight =
8612 contextState.framebufferHeight =
8613 contextState.drawingBufferHeight =
8614 viewport[3] =
8615 scissorBox[3] = gl.drawingBufferHeight
8616 }
8617
8618 function poll () {
8619 contextState.tick += 1
8620 contextState.time = now()
8621 pollViewport()
8622 core.procs.poll()
8623 }
8624
8625 function refresh () {
8626 pollViewport()
8627 core.procs.refresh()
8628 if (timer) {
8629 timer.update()
8630 }
8631 }
8632
8633 function now () {
8634 return (clock() - START_TIME) / 1000.0
8635 }
8636
8637 refresh()
8638
8639 function addListener (event, callback) {
8640
8641
8642 var callbacks
8643 switch (event) {
8644 case 'frame':
8645 return frame(callback)
8646 case 'lost':
8647 callbacks = lossCallbacks
8648 break
8649 case 'restore':
8650 callbacks = restoreCallbacks
8651 break
8652 case 'destroy':
8653 callbacks = destroyCallbacks
8654 break
8655 default:
8656
8657 }
8658
8659 callbacks.push(callback)
8660 return {
8661 cancel: function () {
8662 for (var i = 0; i < callbacks.length; ++i) {
8663 if (callbacks[i] === callback) {
8664 callbacks[i] = callbacks[callbacks.length - 1]
8665 callbacks.pop()
8666 return
8667 }
8668 }
8669 }
8670 }
8671 }
8672
8673 var regl = extend(compileProcedure, {
8674 // Clear current FBO
8675 clear: clear,
8676
8677 // Short cuts for dynamic variables
8678 prop: dynamic.define.bind(null, DYN_PROP),
8679 context: dynamic.define.bind(null, DYN_CONTEXT),
8680 this: dynamic.define.bind(null, DYN_STATE),
8681
8682 // executes an empty draw command
8683 draw: compileProcedure({}),
8684
8685 // Resources
8686 buffer: function (options) {
8687 return bufferState.create(options, GL_ARRAY_BUFFER, false, false)
8688 },
8689 elements: function (options) {
8690 return elementState.create(options, false)
8691 },
8692 texture: textureState.create2D,
8693 cube: textureState.createCube,
8694 renderbuffer: renderbufferState.create,
8695 framebuffer: framebufferState.create,
8696 framebufferCube: framebufferState.createCube,
8697 vao: attributeState.createVAO,
8698
8699 // Expose context attributes
8700 attributes: glAttributes,
8701
8702 // Frame rendering
8703 frame: frame,
8704 on: addListener,
8705
8706 // System limits
8707 limits: limits,
8708 hasExtension: function (name) {
8709 return limits.extensions.indexOf(name.toLowerCase()) >= 0
8710 },
8711
8712 // Read pixels
8713 read: readPixels,
8714
8715 // Destroy regl and all associated resources
8716 destroy: destroy,
8717
8718 // Direct GL state manipulation
8719 _gl: gl,
8720 _refresh: refresh,
8721
8722 poll: function () {
8723 poll()
8724 if (timer) {
8725 timer.update()
8726 }
8727 },
8728
8729 // Current time
8730 now: now,
8731
8732 // regl Statistics Information
8733 stats: stats$$1
8734 })
8735
8736 config.onDone(null, regl)
8737
8738 return regl
8739}
8740
8741return wrapREGL;
8742
8743})));