diff --git a/docs/index.html b/docs/index.html
index 1e8dbef..7c776ea 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -11,6 +11,7 @@
+
@@ -322,8 +323,8 @@
var mouse = require('mouse-event')
-function mouseListen(element, callback) {
- if(!callback) {
+function mouseListen (element, callback) {
+ if (!callback) {
callback = element
element = window
}
@@ -332,64 +333,63 @@
var x = 0
var y = 0
var mods = {
- shift: false,
- alt: false,
+ shift: false,
+ alt: false,
control: false,
- meta: false
+ meta: false
}
var attached = false
- function updateMods(ev) {
+ function updateMods (ev) {
var changed = false
- if('altKey' in ev) {
+ if ('altKey' in ev) {
changed = changed || ev.altKey !== mods.alt
mods.alt = !!ev.altKey
}
- if('shiftKey' in ev) {
+ if ('shiftKey' in ev) {
changed = changed || ev.shiftKey !== mods.shift
mods.shift = !!ev.shiftKey
}
- if('ctrlKey' in ev) {
+ if ('ctrlKey' in ev) {
changed = changed || ev.ctrlKey !== mods.control
mods.control = !!ev.ctrlKey
}
- if('metaKey' in ev) {
+ if ('metaKey' in ev) {
changed = changed || ev.metaKey !== mods.meta
mods.meta = !!ev.metaKey
}
return changed
}
- function handleEvent(nextButtons, ev) {
+ function handleEvent (nextButtons, ev) {
var nextX = mouse.x(ev)
var nextY = mouse.y(ev)
- if('buttons' in ev) {
- nextButtons = ev.buttons|0
- }
- if(nextButtons !== buttonState ||
- nextX !== x ||
- nextY !== y ||
- updateMods(ev)) {
- buttonState = nextButtons|0
- x = nextX||0
- y = nextY||0
+ if ('buttons' in ev) {
+ nextButtons = ev.buttons | 0
+ }
+ if (nextButtons !== buttonState ||
+ nextX !== x ||
+ nextY !== y ||
+ updateMods(ev)) {
+ buttonState = nextButtons | 0
+ x = nextX || 0
+ y = nextY || 0
callback && callback(buttonState, x, y, mods)
}
}
- function clearState(ev) {
+ function clearState (ev) {
handleEvent(0, ev)
}
- function handleBlur() {
- if(buttonState ||
+ function handleBlur () {
+ if (buttonState ||
x ||
y ||
mods.shift ||
mods.alt ||
mods.meta ||
mods.control) {
-
x = y = 0
buttonState = 0
mods.shift = mods.alt = mods.control = mods.meta = false
@@ -397,30 +397,30 @@
}
}
- function handleMods(ev) {
- if(updateMods(ev)) {
+ function handleMods (ev) {
+ if (updateMods(ev)) {
callback && callback(buttonState, x, y, mods)
}
}
- function handleMouseMove(ev) {
- if(mouse.buttons(ev) === 0) {
+ function handleMouseMove (ev) {
+ if (mouse.buttons(ev) === 0) {
handleEvent(0, ev)
} else {
handleEvent(buttonState, ev)
}
}
- function handleMouseDown(ev) {
+ function handleMouseDown (ev) {
handleEvent(buttonState | mouse.buttons(ev), ev)
}
- function handleMouseUp(ev) {
+ function handleMouseUp (ev) {
handleEvent(buttonState & ~mouse.buttons(ev), ev)
}
- function attachListeners() {
- if(attached) {
+ function attachListeners () {
+ if (attached) {
return
}
attached = true
@@ -442,7 +442,7 @@
element.addEventListener('keydown', handleMods)
element.addEventListener('keypress', handleMods)
- if(element !== window) {
+ if (element !== window) {
window.addEventListener('blur', handleBlur)
window.addEventListener('keyup', handleMods)
@@ -451,8 +451,8 @@
}
}
- function detachListeners() {
- if(!attached) {
+ function detachListeners () {
+ if (!attached) {
return
}
attached = false
@@ -474,7 +474,7 @@
element.removeEventListener('keydown', handleMods)
element.removeEventListener('keypress', handleMods)
- if(element !== window) {
+ if (element !== window) {
window.removeEventListener('blur', handleBlur)
window.removeEventListener('keyup', handleMods)
@@ -483,7 +483,7 @@
}
}
- //Attach listeners
+ // Attach listeners
attachListeners()
var result = {
@@ -492,30 +492,30 @@
Object.defineProperties(result, {
enabled: {
- get: function() { return attached },
- set: function(f) {
- if(f) {
+ get: function () { return attached },
+ set: function (f) {
+ if (f) {
attachListeners()
} else {
- detachListeners
+ detachListeners()
}
},
enumerable: true
},
buttons: {
- get: function() { return buttonState },
+ get: function () { return buttonState },
enumerable: true
},
x: {
- get: function() { return x },
+ get: function () { return x },
enumerable: true
},
y: {
- get: function() { return y },
+ get: function () { return y },
enumerable: true
},
mods: {
- get: function() { return mods },
+ get: function () { return mods },
enumerable: true
}
})
@@ -639,287 +639,9652 @@
return out
}
},{}],11:[function(require,module,exports){
-(function (global){
-(function(Oa){"object"===typeof exports&&"undefined"!==typeof module?module.exports=Oa():"function"===typeof define&&define.amd?define([],Oa):("undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:this).createREGL=Oa()})(function(){return function f(p,u,l){function k(c,a){if(!u[c]){if(!p[c]){var b="function"==typeof require&&require;if(!a&&b)return b(c,!0);if(x)return x(c,!0);b=Error("Cannot find module '"+c+"'");throw b.code="MODULE_NOT_FOUND",b;}b=
-u[c]={exports:{}};p[c][0].call(b.exports,function(a){var b=p[c][1][a];return k(b?b:a)},b,b.exports,f,p,u,l)}return u[c].exports}for(var x="function"==typeof require&&require,r=0;r":516,notequal:517,"!=":517,"!==":517,gequal:518,">=":518,always:519},Y={0:0,zero:0,keep:7680,replace:7681,increment:7682,decrement:7683,"increment wrap":34055,"decrement wrap":34056,invert:5386},L={cw:2304,ccw:2305},H=new x(!1,!1,!1,function(){});p.exports=function(h,
-f,t,p,M,u,Z,D,K,Aa,va,q,S,ma,ga){function W(d){return d.replace(".","_")}function R(d,a,c){var b=W(d);w.push(d);z[b]=e[b]=!!c;wa[b]=a}function G(d,a,c){var b=W(d);w.push(d);Array.isArray(c)?(e[b]=c.slice(),z[b]=c.slice()):e[b]=z[b]=c;xa[b]=a}function ba(){var d=b(),a=d.link,c=d.global;d.id=Ra++;d.batchId="0";var h=a(Qa),A=d.shared={props:"a0"};Object.keys(Qa).forEach(function(d){A[d]=c.def(h,".",d)});var J=d.next={},P=d.current={};Object.keys(xa).forEach(function(d){Array.isArray(e[d])&&(J[d]=c.def(A.next,
-".",d),P[d]=c.def(A.current,".",d))});var Sa=d.constants={};Object.keys(Ma).forEach(function(d){Sa[d]=c.def(JSON.stringify(Ma[d]))});d.invoke=function(e,I){switch(I.type){case 0:var c=["this",A.context,A.props,d.batchId];return e.def(a(I.data),".call(",c.slice(0,Math.max(I.data.length+1,4)),")");case 1:return e.def(A.props,I.data);case 2:return e.def(A.context,I.data);case 3:return e.def("this",I.data);case 4:return I.data.append(d,e),I.data.ref}};d.attribCache={};var I={};d.scopeAttrib=function(d){d=
-f.id(d);if(d in I)return I[d];var e=Aa.scope[d];e||(e=Aa.scope[d]=new Ba);return I[d]=a(e)};return d}function na(d){var e=d["static"];d=d.dynamic;var b;if("profile"in e){var h=!!e.profile;b=c(function(d,e){return h});b.enable=h}else if("profile"in d){var A=d.profile;b=a(A,function(d,e){return d.invoke(e,A)})}return b}function ya(d,e){var b=d["static"],h=d.dynamic;if("framebuffer"in b){var A=b.framebuffer;return A?(A=D.getFramebuffer(A),c(function(d,e){var a=d.link(A),v=d.shared;e.set(v.framebuffer,
-".next",a);v=v.context;e.set(v,".framebufferWidth",a+".width");e.set(v,".framebufferHeight",a+".height");return a})):c(function(d,e){var a=d.shared;e.set(a.framebuffer,".next","null");a=a.context;e.set(a,".framebufferWidth",a+".drawingBufferWidth");e.set(a,".framebufferHeight",a+".drawingBufferHeight");return"null"})}if("framebuffer"in h){var J=h.framebuffer;return a(J,function(d,e){var a=d.invoke(e,J),v=d.shared,c=v.framebuffer,a=e.def(c,".getFramebuffer(",a,")");e.set(c,".next",a);v=v.context;e.set(v,
-".framebufferWidth",a+"?"+a+".width:"+v+".drawingBufferWidth");e.set(v,".framebufferHeight",a+"?"+a+".height:"+v+".drawingBufferHeight");return a})}return null}function U(d,e,c){function b(d){if(d in h){var I=h[d];d=!0;var c=I.x|0,qa=I.y|0,P,aa;"width"in I?P=I.width|0:d=!1;"height"in I?aa=I.height|0:d=!1;return new x(!d&&e&&e.thisDep,!d&&e&&e.contextDep,!d&&e&&e.propDep,function(d,e){var a=d.shared.context,v=P;"width"in I||(v=e.def(a,".","framebufferWidth","-",c));var b=aa;"height"in I||(b=e.def(a,
-".","framebufferHeight","-",qa));return[c,qa,v,b]})}if(d in J){var w=J[d];d=a(w,function(d,e){var a=d.invoke(e,w),I=d.shared.context,c=e.def(a,".x|0"),v=e.def(a,".y|0"),qa=e.def('"width" in ',a,"?",a,".width|0:","(",I,".","framebufferWidth","-",c,")"),a=e.def('"height" in ',a,"?",a,".height|0:","(",I,".","framebufferHeight","-",v,")");return[c,v,qa,a]});e&&(d.thisDep=d.thisDep||e.thisDep,d.contextDep=d.contextDep||e.contextDep,d.propDep=d.propDep||e.propDep);return d}return e?new x(e.thisDep,e.contextDep,
-e.propDep,function(d,e){var a=d.shared.context;return[0,0,e.def(a,".","framebufferWidth"),e.def(a,".","framebufferHeight")]}):null}var h=d["static"],J=d.dynamic;if(d=b("viewport")){var P=d;d=new x(d.thisDep,d.contextDep,d.propDep,function(d,e){var a=P.append(d,e),c=d.shared.context;e.set(c,".viewportWidth",a[2]);e.set(c,".viewportHeight",a[3]);return a})}return{viewport:d,scissor_box:b("scissor.box")}}function ia(d){function e(d){if(d in b){var I=f.id(b[d]);d=c(function(){return I});d.id=I;return d}if(d in
-h){var v=h[d];return a(v,function(d,e){var a=d.invoke(e,v);return e.def(d.shared.strings,".id(",a,")")})}return null}var b=d["static"],h=d.dynamic,A=e("frag"),J=e("vert"),P=null;r(A)&&r(J)?(P=va.program(J.id,A.id),d=c(function(d,e){return d.link(P)})):d=new x(A&&A.thisDep||J&&J.thisDep,A&&A.contextDep||J&&J.contextDep,A&&A.propDep||J&&J.propDep,function(d,e){var a=d.shared.shader,c;c=A?A.append(d,e):e.def(a,".","frag");var v;v=J?J.append(d,e):e.def(a,".","vert");return e.def(a+".program("+v+","+c+
-")")});return{frag:A,vert:J,progVar:d,program:P}}function ka(d,e){function b(d,e){if(d in h){var v=h[d]|0;return c(function(d,a){e&&(d.OFFSET=v);return v})}if(d in A){var qa=A[d];return a(qa,function(d,a){var c=d.invoke(a,qa);e&&(d.OFFSET=c);return c})}return e&&J?c(function(d,e){d.OFFSET="0";return 0}):null}var h=d["static"],A=d.dynamic,J=function(){if("elements"in h){var d=h.elements;l(d)?d=u.getElements(u.create(d,!0)):d&&(d=u.getElements(d));var e=c(function(e,a){if(d){var c=e.link(d);return e.ELEMENTS=
-c}return e.ELEMENTS=null});e.value=d;return e}if("elements"in A){var v=A.elements;return a(v,function(d,e){var a=d.shared,c=a.isBufferArgs,a=a.elements,I=d.invoke(e,v),b=e.def("null"),c=e.def(c,"(",I,")"),I=d.cond(c).then(b,"=",a,".createStream(",I,");")["else"](b,"=",a,".getElements(",I,");");e.entry(I);e.exit(d.cond(c).then(a,".destroyStream(",b,");"));return d.ELEMENTS=b})}return null}(),P=b("offset",!0);return{elements:J,primitive:function(){if("primitive"in h){var d=h.primitive;return c(function(e,
-a){return E[d]})}if("primitive"in A){var e=A.primitive;return a(e,function(d,a){var c=d.constants.primTypes,v=d.invoke(a,e);return a.def(c,"[",v,"]")})}return J?r(J)?J.value?c(function(d,e){return e.def(d.ELEMENTS,".primType")}):c(function(){return 4}):new x(J.thisDep,J.contextDep,J.propDep,function(d,e){var a=d.ELEMENTS;return e.def(a,"?",a,".primType:",4)}):null}(),count:function(){if("count"in h){var d=h.count|0;return c(function(){return d})}if("count"in A){var e=A.count;return a(e,function(d,
-a){return d.invoke(a,e)})}return J?r(J)?J?P?new x(P.thisDep,P.contextDep,P.propDep,function(d,e){return e.def(d.ELEMENTS,".vertCount-",d.OFFSET)}):c(function(d,e){return e.def(d.ELEMENTS,".vertCount")}):c(function(){return-1}):new x(J.thisDep||P.thisDep,J.contextDep||P.contextDep,J.propDep||P.propDep,function(d,e){var a=d.ELEMENTS;return d.OFFSET?e.def(a,"?",a,".vertCount-",d.OFFSET,":-1"):e.def(a,"?",a,".vertCount:-1")}):null}(),instances:b("instances",!1),offset:P}}function ra(d,e){var b=d["static"],
-h=d.dynamic,A={};w.forEach(function(d){function e(I,w){if(d in b){var qa=I(b[d]);A[v]=c(function(){return qa})}else if(d in h){var P=h[d];A[v]=a(P,function(d,e){return w(d,e,d.invoke(e,P))})}}var v=W(d);switch(d){case "cull.enable":case "blend.enable":case "dither":case "stencil.enable":case "depth.enable":case "scissor.enable":case "polygonOffset.enable":case "sample.alpha":case "sample.enable":case "depth.mask":return e(function(d){return d},function(d,e,a){return a});case "depth.func":return e(function(d){return B[d]},
-function(d,e,a){return e.def(d.constants.compareFuncs,"[",a,"]")});case "depth.range":return e(function(d){return d},function(d,e,a){d=e.def("+",a,"[0]");e=e.def("+",a,"[1]");return[d,e]});case "blend.func":return e(function(d){return[m["srcRGB"in d?d.srcRGB:d.src],m["dstRGB"in d?d.dstRGB:d.dst],m["srcAlpha"in d?d.srcAlpha:d.src],m["dstAlpha"in d?d.dstAlpha:d.dst]]},function(d,e,a){function c(d,v){return e.def('"',d,v,'" in ',a,"?",a,".",d,v,":",a,".",d)}d=d.constants.blendFuncs;var v=c("src","RGB"),
-b=c("dst","RGB"),v=e.def(d,"[",v,"]"),h=e.def(d,"[",c("src","Alpha"),"]"),b=e.def(d,"[",b,"]");d=e.def(d,"[",c("dst","Alpha"),"]");return[v,b,h,d]});case "blend.equation":return e(function(d){if("string"===typeof d)return[ca[d],ca[d]];if("object"===typeof d)return[ca[d.rgb],ca[d.alpha]]},function(d,e,a){var c=d.constants.blendEquations,v=e.def(),b=e.def();d=d.cond("typeof ",a,'==="string"');d.then(v,"=",b,"=",c,"[",a,"];");d["else"](v,"=",c,"[",a,".rgb];",b,"=",c,"[",a,".alpha];");e(d);return[v,b]});
-case "blend.color":return e(function(d){return F(4,function(e){return+d[e]})},function(d,e,a){return F(4,function(d){return e.def("+",a,"[",d,"]")})});case "stencil.mask":return e(function(d){return d|0},function(d,e,a){return e.def(a,"|0")});case "stencil.func":return e(function(d){return[B[d.cmp||"keep"],d.ref||0,"mask"in d?d.mask:-1]},function(d,e,a){d=e.def('"cmp" in ',a,"?",d.constants.compareFuncs,"[",a,".cmp]",":",7680);var c=e.def(a,".ref|0");e=e.def('"mask" in ',a,"?",a,".mask|0:-1");return[d,
-c,e]});case "stencil.opFront":case "stencil.opBack":return e(function(e){return["stencil.opBack"===d?1029:1028,Y[e.fail||"keep"],Y[e.zfail||"keep"],Y[e.zpass||"keep"]]},function(e,a,c){function v(d){return a.def('"',d,'" in ',c,"?",b,"[",c,".",d,"]:",7680)}var b=e.constants.stencilOps;return["stencil.opBack"===d?1029:1028,v("fail"),v("zfail"),v("zpass")]});case "polygonOffset.offset":return e(function(d){return[d.factor|0,d.units|0]},function(d,e,a){d=e.def(a,".factor|0");e=e.def(a,".units|0");return[d,
-e]});case "cull.face":return e(function(d){var e=0;"front"===d?e=1028:"back"===d&&(e=1029);return e},function(d,e,a){return e.def(a,'==="front"?',1028,":",1029)});case "lineWidth":return e(function(d){return d},function(d,e,a){return a});case "frontFace":return e(function(d){return L[d]},function(d,e,a){return e.def(a+'==="cw"?2304:2305')});case "colorMask":return e(function(d){return d.map(function(d){return!!d})},function(d,e,a){return F(4,function(d){return"!!"+a+"["+d+"]"})});case "sample.coverage":return e(function(d){return["value"in
-d?d.value:1,!!d.invert]},function(d,e,a){d=e.def('"value" in ',a,"?+",a,".value:1");e=e.def("!!",a,".invert");return[d,e]})}});return A}function sa(d,e){var b=d["static"],h=d.dynamic,A={};Object.keys(b).forEach(function(d){var e=b[d],a;if("number"===typeof e||"boolean"===typeof e)a=c(function(){return e});else if("function"===typeof e){var v=e._reglType;if("texture2d"===v||"textureCube"===v)a=c(function(d){return d.link(e)});else if("framebuffer"===v||"framebufferCube"===v)a=c(function(d){return d.link(e.color[0])})}else y(e)&&
-(a=c(function(d){return d.global.def("[",F(e.length,function(d){return e[d]}),"]")}));a.value=e;A[d]=a});Object.keys(h).forEach(function(d){var e=h[d];A[d]=a(e,function(d,a){return d.invoke(a,e)})});return A}function da(d,e){var b=d["static"],h=d.dynamic,A={};Object.keys(b).forEach(function(d){var e=b[d],a=f.id(d),v=new Ba;if(l(e))v.state=1,v.buffer=M.getBuffer(M.create(e,34962,!1,!0)),v.type=0;else{var h=M.getBuffer(e);if(h)v.state=1,v.buffer=h,v.type=0;else if(e.constant){var w=e.constant;v.buffer=
-"null";v.state=2;"number"===typeof w?v.x=w:N.forEach(function(d,e){e="+e+"?"+c+".constant["+e+"]:0;"}).join(""),"}}else{","if(",h,"(",c,".buffer)){",aa,"=",w,".createStream(",34962,",",c,".buffer);","}else{",aa,"=",w,".getBuffer(",c,".buffer);","}",q,'="type" in ',
-c,"?",b.glTypes,"[",c,".type]:",aa,".dtype;",A.normalized,"=!!",c,".normalized;");v("size");v("offset");v("stride");v("divisor");a("}}");a.exit("if(",A.isStream,"){",w,".destroyStream(",aa,");","}");return A})});return A}function ja(d){var e=d["static"],b=d.dynamic,h={};Object.keys(e).forEach(function(d){var a=e[d];h[d]=c(function(d,e){return"number"===typeof a||"boolean"===typeof a?""+a:d.link(a)})});Object.keys(b).forEach(function(d){var e=b[d];h[d]=a(e,function(d,a){return d.invoke(a,e)})});return h}
-function la(d,e,a,c,b){var h=ya(d,b),w=U(d,h,b),z=ka(d,b),q=ra(d,b),k=ia(d,b),g=w.viewport;g&&(q.viewport=g);g=W("scissor.box");(w=w[g])&&(q[g]=w);w=0>1)",B],");")}function e(){a(x,".drawArraysInstancedANGLE(",[f,l,n,B],");")}q?S?d():(a("if(",q,"){"),d(),a("}else{"),e(),a("}")):e()}function g(){function d(){a(z+".drawElements("+[f,n,K,l+"<<(("+K+"-5121)>>1)"]+");")}function e(){a(z+".drawArrays("+[f,l,n]+");")}q?S?d():(a("if(",q,"){"),d(),a("}else{"),e(),a("}")):e()}var w=d.shared,z=w.gl,m=w.draw,k=c.draw,q=function(){var b=k.elements,h=e;if(b){if(b.contextDep&&c.contextDynamic||b.propDep)h=a;b=b.append(d,h)}else b=h.def(m,".","elements");
-b&&h("if("+b+")"+z+".bindBuffer(34963,"+b+".buffer.buffer);");return b}(),f=b("primitive"),l=b("offset"),n=function(){var b=k.count,h=e;if(b){if(b.contextDep&&c.contextDynamic||b.propDep)h=a;b=b.append(d,h)}else b=h.def(m,".","count");return b}();if("number"===typeof n){if(0===n)return}else a("if(",n,"){"),a.exit("}");var B,x;ta&&(B=b("instances"),x=d.instancing);var K=q+".type",S=k.elements&&r(k.elements);ta&&("number"!==typeof B||0<=B)?"string"===typeof B?(a("if(",B,">0){"),h(),a("}else if(",B,
-"<0){"),g(),a("}")):h():g()}function Ea(d,e,a,b,c){e=ba();c=e.proc("body",c);ta&&(e.instancing=c.def(e.shared.extensions,".angle_instanced_arrays"));d(e,c,a,b);return e.compile().body}function Fa(d,e,a,b){pa(d,e);X(d,e,a,b.attributes,function(){return!0});T(d,e,a,b.uniforms,function(){return!0});ua(d,e,e,a)}function Ha(d,e){var a=d.proc("draw",1);pa(d,a);ea(d,a,e.context);O(d,a,e.framebuffer);ha(d,a,e);Q(d,a,e.state);V(d,a,e,!1,!0);var b=e.shader.progVar.append(d,a);a(d.shared.gl,".useProgram(",b,
-".program);");if(e.shader.program)Fa(d,a,e,e.shader.program);else{var c=d.global.def("{}"),h=a.def(b,".id"),g=a.def(c,"[",h,"]");a(d.cond(g).then(g,".call(this,a0);")["else"](g,"=",c,"[",h,"]=",d.link(function(a){return Ea(Fa,d,e,a,1)}),"(",b,");",g,".call(this,a0);"))}0g&&(g=c.buffer.byteLength,5123===y?g>>=1:5125===y&&(g>>=2));c.vertCount=g;g=r;0>r&&(g=4,r=c.buffer.dimension,1===r&&(g=0),2===r&&(g=1),3===r&&(g=4));c.primType=g}function g(a){p.elementsCount--;
-delete E[a.id];a.buffer.destroy();a.buffer=null}var E={},C=0,N={uint8:5121,uint16:5123};b.oes_element_index_uint&&(N.uint32=5125);t.prototype.bind=function(){this.buffer.bind()};var n=[];return{create:function(a,b){function n(a){if(a)if("number"===typeof a)x(a),C.primType=4,C.vertCount=a|0,C.type=5121;else{var b=null,g=35044,m=-1,f=-1,t=0,B=0;if(Array.isArray(a)||l(a)||k(a))b=a;else if("data"in a&&(b=a.data),"usage"in a&&(g=c[a.usage]),"primitive"in a&&(m=r[a.primitive]),"count"in a&&(f=a.count|0),
-"type"in a&&(B=N[a.type]),"length"in a)t=a.length|0;else if(t=f,5123===B||5122===B)t*=2;else if(5125===B||5124===B)t*=4;y(C,b,g,m,f,t,B)}else x(),C.primType=4,C.vertCount=0,C.type=5121;return n}var x=f.create(null,34963,!0),C=new t(x._buffer);p.elementsCount++;n(a);n._reglType="elements";n._elements=C;n.subdata=function(a,b){x.subdata(a,b);return n};n.destroy=function(){g(C)};return n},createStream:function(a){var b=n.pop();b||(b=new t(f.create(null,34963,!0,!1)._buffer));y(b,a,35040,-1,-1,0,0);return b},
-destroyStream:function(a){n.push(a)},getElements:function(a){return"function"===typeof a&&a._elements instanceof t?a._elements:null},clear:function(){x(E).forEach(g)}}}},{"./constants/primitives.json":5,"./constants/usage.json":6,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/values":31}],10:[function(f,p,u){p.exports=function(f,k){function x(a){a=a.toLowerCase();var c;try{c=r[a]=f.getExtension(a)}catch(k){}return!!c}for(var r={},c=0;cg;++g){for(r=0;ra;++a)b[a].resize(g);c.width=c.height=g;return c},_reglType:"framebufferCube",destroy:function(){b.forEach(function(a){a.destroy()})}})},clear:function(){l(D).forEach(H)},restore:function(){l(D).forEach(function(a){a.framebuffer=
-c.createFramebuffer();h(a)})}})}},{"./util/extend":22,"./util/values":31}],12:[function(f,p,u){p.exports=function(f,k){var x=1;k.ext_texture_filter_anisotropic&&(x=f.getParameter(34047));var r=1,c=1;k.webgl_draw_buffers&&(r=f.getParameter(34852),c=f.getParameter(36063));return{colorBits:[f.getParameter(3410),f.getParameter(3411),f.getParameter(3412),f.getParameter(3413)],depthBits:f.getParameter(3414),stencilBits:f.getParameter(3415),subpixelBits:f.getParameter(3408),extensions:Object.keys(k).filter(function(a){return!!k[a]}),
-maxAnisotropic:x,maxDrawbuffers:r,maxColorAttachments:c,pointSizeDims:f.getParameter(33901),lineWidthDims:f.getParameter(33902),maxViewportDims:f.getParameter(3386),maxCombinedTextureUnits:f.getParameter(35661),maxCubeMapSize:f.getParameter(34076),maxRenderbufferSize:f.getParameter(34024),maxTextureUnits:f.getParameter(34930),maxTextureSize:f.getParameter(3379),maxAttributes:f.getParameter(34921),maxVertexUniforms:f.getParameter(36347),maxVertexTextureUnits:f.getParameter(35660),maxVaryingVectors:f.getParameter(36348),
-maxFragmentUniforms:f.getParameter(36349),glsl:f.getParameter(35724),renderer:f.getParameter(7937),vendor:f.getParameter(7936),version:f.getParameter(7938)}}},{}],13:[function(f,p,u){var l=f("./util/is-typed-array");p.exports=function(k,f,r,c,a,b){return function(a){var b;b=null===f.next?5121:f.next.colorAttachments[0].texture._texture.type;var t=0,y=0,g=c.framebufferWidth,p=c.framebufferHeight,C=null;l(a)?C=a:a&&(t=a.x|0,y=a.y|0,g=(a.width||c.framebufferWidth-t)|0,p=(a.height||c.framebufferHeight-
-y)|0,C=a.data||null);r();a=g*p*4;C||(5121===b?C=new Uint8Array(a):5126===b&&(C=C||new Float32Array(a)));k.pixelStorei(3333,4);k.readPixels(t,y,g,p,6408,b,C);return C}}},{"./util/is-typed-array":26}],14:[function(f,p,u){var l=f("./util/values"),k=[];k[32854]=2;k[32855]=2;k[36194]=2;k[33189]=2;k[36168]=1;k[34041]=4;k[35907]=4;k[34836]=16;k[34842]=8;k[34843]=6;p.exports=function(f,r,c,a,b){function p(a){this.id=g++;this.refCount=1;this.renderbuffer=a;this.format=32854;this.height=this.width=0;b.profile&&
-(this.stats={size:0})}function M(b){var c=b.renderbuffer;f.bindRenderbuffer(36161,null);f.deleteRenderbuffer(c);b.renderbuffer=null;b.refCount=0;delete E[b.id];a.renderbufferCount--}var t={rgba4:32854,rgb565:36194,"rgb5 a1":32855,depth:33189,stencil:36168,"depth stencil":34041};r.ext_srgb&&(t.srgba=35907);r.ext_color_buffer_half_float&&(t.rgba16f=34842,t.rgb16f=34843);r.webgl_color_buffer_float&&(t.rgba32f=34836);var y=[];Object.keys(t).forEach(function(a){y[t[a]]=a});var g=0,E={};p.prototype.decRef=
-function(){0>=--this.refCount&&M(this)};b.profile&&(a.getTotalRenderbufferSize=function(){var a=0;Object.keys(E).forEach(function(b){a+=E[b].stats.size});return a});return{create:function(c,g){function n(a,c){var g=0,l=0,h=32854;"object"===typeof a&&a?("shape"in a?(l=a.shape,g=l[0]|0,l=l[1]|0):("radius"in a&&(g=l=a.radius|0),"width"in a&&(g=a.width|0),"height"in a&&(l=a.height|0)),"format"in a&&(h=t[a.format])):"number"===typeof a?(g=a|0,l="number"===typeof c?c|0:g):a||(g=l=1);if(g!==m.width||l!==
-m.height||h!==m.format)return n.width=m.width=g,n.height=m.height=l,m.format=h,f.bindRenderbuffer(36161,m.renderbuffer),f.renderbufferStorage(36161,h,g,l),b.profile&&(m.stats.size=k[m.format]*m.width*m.height),n.format=y[m.format],n}var m=new p(f.createRenderbuffer());E[m.id]=m;a.renderbufferCount++;n(c,g);n.resize=function(a,c){var g=a|0,l=c|0||g;if(g===m.width&&l===m.height)return n;n.width=m.width=g;n.height=m.height=l;f.bindRenderbuffer(36161,m.renderbuffer);f.renderbufferStorage(36161,m.format,
-g,l);b.profile&&(m.stats.size=k[m.format]*m.width*m.height);return n};n._reglType="renderbuffer";n._renderbuffer=m;b.profile&&(n.stats=m.stats);n.destroy=function(){m.decRef()};return n},clear:function(){l(E).forEach(M)},restore:function(){l(E).forEach(function(a){a.renderbuffer=f.createRenderbuffer();f.bindRenderbuffer(36161,a.renderbuffer);f.renderbufferStorage(36161,a.format,a.width,a.height)});f.bindRenderbuffer(36161,null)}}}},{"./util/values":31}],15:[function(f,p,u){var l=f("./util/values");
-p.exports=function(f,x,r,c){function a(a,c,b,g){this.name=a;this.id=c;this.location=b;this.info=g}function b(a,c){for(var b=0;ba&&(a=b.stats.uniformsCount)});return a},r.getMaxAttributesCount=function(){var a=0;C.forEach(function(b){b.stats.attributesCount>a&&(a=b.stats.attributesCount)});return a});return{clear:function(){var a=f.deleteShader.bind(f);
-l(y).forEach(a);y={};l(g).forEach(a);g={};C.forEach(function(a){f.deleteProgram(a.program)});C.length=0;E={};r.shaderCount=0},program:function(a,b,c){r.shaderCount++;var g=E[b];g||(g=E[b]={});var f=g[a];f||(f=new M(b,a),t(f,c),g[a]=f,C.push(f));return f},restore:function(){y={};g={};for(var a=0;a>=h,c.height>>=h,S(c,g[h]),a.mipmask|=1<b;++b)a.images[b]=null;return a}function U(a){for(var b=a.images,c=0;ca){for(var b=0;b=--this.refCount&&la(this)}});Z.profile&&(L.getTotalTextureSize=function(){var a=0;Object.keys(ca).forEach(function(b){a+=ca[b].stats.size});return a});return{create2D:function(b,c){function g(b,c){var e=f.texInfo;ia.call(e);var h=ya();"number"===typeof b?"number"===typeof c?
-G(h,b|0,c|0):G(h,b|0,b|0):b?(ka(e,b),ba(h,b)):G(h,1,1);e.genMipmaps&&(h.mipmask=(h.width<<1)-1);f.mipmask=h.mipmask;K(f,h);f.internalformat=h.internalformat;g.width=h.width;g.height=h.height;da(f);na(h,3553);ra(e,3553);ja();U(h);Z.profile&&(f.stats.size=a(f.internalformat,f.type,h.width,h.height,e.genMipmaps,!1));g.format=Fa[f.internalformat];g.type=Ha[f.type];g.mag=Ia[e.magFilter];g.min=Ca[e.minFilter];g.wrapS=Da[e.wrapS];g.wrapT=Da[e.wrapT];return g}var f=new sa(3553);ca[f.id]=f;L.textureCount++;
-g(b,c);g.subimage=function(a,b,c,e){b|=0;c|=0;e|=0;var d=ga();K(d,f);d.width=0;d.height=0;S(d,a);d.width=d.width||(f.width>>e)-b;d.height=d.height||(f.height>>e)-c;da(f);ma(d,3553,b,c,e);ja();W(d);return g};g.resize=function(b,c){var e=b|0,k=c|0||e;if(e===f.width&&k===f.height)return g;g.width=f.width=e;g.height=f.height=k;da(f);for(var d=0;f.mipmask>>d;++d)h.texImage2D(3553,d,f.format,e>>d,k>>d,0,f.format,f.type,null);ja();Z.profile&&(f.stats.size=a(f.internalformat,f.type,e,k,!1,!1));return g};
-g._reglType="texture2d";g._texture=f;Z.profile&&(g.stats=f.stats);g.destroy=function(){f.decRef()};return g},createCube:function(b,c,g,f,k,l){function m(b,c,e,g,h,f){var k,l=n.texInfo;ia.call(l);for(k=0;6>k;++k)d[k]=ya();if("number"===typeof b||!b)for(b=b|0||1,k=0;6>k;++k)G(d[k],b,b);else if("object"===typeof b)if(c)ba(d[0],b),ba(d[1],c),ba(d[2],e),ba(d[3],g),ba(d[4],h),ba(d[5],f);else if(ka(l,b),Y(n,b),"faces"in b)for(b=b.faces,k=0;6>k;++k)K(d[k],n),ba(d[k],b[k]);else for(k=0;6>k;++k)ba(d[k],b);
-K(n,d[0]);n.mipmask=l.genMipmaps?(d[0].width<<1)-1:d[0].mipmask;n.internalformat=d[0].internalformat;m.width=d[0].width;m.height=d[0].height;da(n);for(k=0;6>k;++k)na(d[k],34069+k);ra(l,34067);ja();Z.profile&&(n.stats.size=a(n.internalformat,n.type,m.width,m.height,l.genMipmaps,!0));m.format=Fa[n.internalformat];m.type=Ha[n.type];m.mag=Ia[l.magFilter];m.min=Ca[l.minFilter];m.wrapS=Da[l.wrapS];m.wrapT=Da[l.wrapT];for(k=0;6>k;++k)U(d[k]);return m}var n=new sa(34067);ca[n.id]=n;L.cubeCount++;var d=Array(6);
-m(b,c,g,f,k,l);m.subimage=function(a,b,c,d,e){c|=0;d|=0;e|=0;var g=ga();K(g,n);g.width=0;g.height=0;S(g,b);g.width=g.width||(n.width>>e)-c;g.height=g.height||(n.height>>e)-d;da(n);ma(g,34069+a,c,d,e);ja();W(g);return m};m.resize=function(b){b|=0;if(b!==n.width){m.width=n.width=b;m.height=n.height=b;da(n);for(var c=0;6>c;++c)for(var d=0;n.mipmask>>d;++d)h.texImage2D(34069+c,d,n.format,b>>d,b>>d,0,n.format,n.type,null);ja();Z.profile&&(n.stats.size=a(n.internalformat,n.type,m.width,m.height,!1,!0));
-return m}};m._reglType="textureCube";m._texture=n;Z.profile&&(m.stats=n.stats);m.destroy=function(){n.decRef()};return m},clear:function(){for(var a=0;ab;++b)if(0!==(a.mipmask&1<>b,a.height>>b,0,a.internalformat,a.type,null);else for(var c=0;6>c;++c)h.texImage2D(34069+c,b,a.internalformat,a.width>>b,a.height>>b,0,a.internalformat,a.type,null);ra(a.texInfo,a.target)})}}}},{"./constants/arraytypes.json":3,"./util/extend":22,"./util/flatten":23,"./util/is-array-like":24,"./util/is-ndarray":25,"./util/is-typed-array":26,"./util/pool":28,"./util/to-half-float":30,"./util/values":31}],19:[function(f,p,u){p.exports=function(f,k){function p(){this.endQueryIndex=this.startQueryIndex=
--1;this.sum=0;this.stats=null}function r(a,b,c){var f=F.pop()||new p;f.startQueryIndex=a;f.endQueryIndex=b;f.sum=0;f.stats=c;u.push(f)}var c=k.ext_disjoint_timer_query;if(!c)return null;var a=[],b=[],F=[],u=[],t=[],y=[];return{beginQuery:function(g){var f=a.pop()||c.createQueryEXT();c.beginQueryEXT(35007,f);b.push(f);r(b.length-1,b.length,g)},endQuery:function(){c.endQueryEXT(35007)},pushScopeStats:r,update:function(){var g,f;g=b.length;if(0!==g){y.length=Math.max(y.length,g+1);t.length=Math.max(t.length,
-g+1);t[0]=0;var k=y[0]=0;for(f=g=0;f>>=a;b=(255>>=b;a|=
-b;b=(15>>=b;a|=b;b=(3>>b>>1}function k(c){a:{for(var a=16;268435456>=a;a*=16)if(c<=a){c=a;break a}c=0}a=r[l(c)>>2];return 0>2].push(c)}var r=f("./loop")(8,function(){return[]});p.exports={alloc:k,free:x,allocType:function(c,a){var b=null;switch(c){case 5120:b=new Int8Array(k(a),0,a);break;case 5121:b=new Uint8Array(k(a),0,a);break;case 5122:b=new Int16Array(k(2*a),0,a);break;case 5123:b=new Uint16Array(k(2*
-a),0,a);break;case 5124:b=new Int32Array(k(4*a),0,a);break;case 5125:b=new Uint32Array(k(4*a),0,a);break;case 5126:b=new Float32Array(k(4*a),0,a);break;default:return null}return b.length!==a?b.subarray(0,a):b},freeType:function(c){x(c.buffer)}}},{"./loop":27}],29:[function(f,p,u){p.exports="function"===typeof requestAnimationFrame&&"function"===typeof cancelAnimationFrame?{next:function(f){return requestAnimationFrame(f)},cancel:function(f){return cancelAnimationFrame(f)}}:{next:function(f){return setTimeout(f,
-16)},cancel:clearTimeout}},{}],30:[function(f,p,u){var l=f("./pool"),k=new Float32Array(1),x=new Uint32Array(k.buffer);p.exports=function(f){for(var c=l.allocType(5123,f.length),a=0;a>>31<<15,u=(b<<1>>>24)-127,b=b>>13&1023;c[a]=-24>u?p:-14>u?p+(b+1024>>-14-u):15=Q.length&&u()}var c=l(Q,a);Q[c]=b}}}function D(){var a=O.viewport,b=O.scissor_box;a[0]=a[1]=b[0]=b[1]=0;U.viewportWidth=U.framebufferWidth=U.drawingBufferWidth=a[2]=b[2]=q.drawingBufferWidth;U.viewportHeight=U.framebufferHeight=U.drawingBufferHeight=a[3]=b[3]=q.drawingBufferHeight}function K(){U.tick+=1;U.time=va();D();ea.procs.poll()}function Aa(){D();
-ea.procs.refresh();G&&G.update()}function va(){return(c()-ba)/1E3}f=b(f);if(!f)return null;var q=f.gl,S=q.getContextAttributes();q.isContextLost();var ma=F(q,f);if(!ma)return null;var ga=a(),W=Y(),R=ma.extensions,G=L(q,R),ba=c(),na=q.drawingBufferWidth,ya=q.drawingBufferHeight,U={tick:0,time:0,viewportWidth:na,viewportHeight:ya,framebufferWidth:na,framebufferHeight:ya,drawingBufferWidth:na,drawingBufferHeight:ya,pixelRatio:f.pixelRatio},ia=M(q,R),ka=t(q,W,f),ra=y(q,R,ka,W),na=N(q,R,ia,ka,ga),sa=n(q,
-ga,W,f),da=g(q,R,ia,function(){ea.procs.poll()},U,W,f),ja=E(q,R,ia,W,f),la=C(q,R,ia,da,ja,W),ea=B(q,ga,R,ia,ka,ra,da,la,{},na,sa,{elements:null,primitive:4,count:-1,offset:0,instances:-1},U,G,f),ga=m(q,la,ea.procs.poll,U,S,R),O=ea.next,ha=q.canvas,Q=[],pa=[],V=[],X=[f.onDestroy],T=null;ha&&(ha.addEventListener("webglcontextlost",La,!1),ha.addEventListener("webglcontextrestored",za,!1));Aa();S=k(Ga,{clear:function(a){var b=0;ea.procs.poll();var c=a.color;c&&(q.clearColor(+c[0]||0,+c[1]||0,+c[2]||0,
-+c[3]||0),b|=16384);"depth"in a&&(q.clearDepth(+a.depth),b|=256);"stencil"in a&&(q.clearStencil(a.stencil|0),b|=1024);q.clear(b)},prop:x.define.bind(null,1),context:x.define.bind(null,2),"this":x.define.bind(null,3),draw:Ga({}),buffer:function(a){return ka.create(a,34962,!1,!1)},elements:function(a){return ra.create(a,!1)},texture:da.create2D,cube:da.createCube,renderbuffer:ja.create,framebuffer:la.create,framebufferCube:la.createCube,attributes:S,frame:Z,on:function(a,b){var c;switch(a){case "frame":return Z(b);
-case "lost":c=pa;break;case "restore":c=V;break;case "destroy":c=X}c.push(b);return{cancel:function(){for(var a=0;a= 0) &&
+ ((value | 0) === value))) {
+ raise('invalid parameter type, (' + value + ')' + encolon(message) +
+ '. must be a nonnegative integer');
+ }
+}
- var right = new Float32Array([1, 0, 0])
- var front = new Float32Array([0, 0, 1])
+function checkOneOf (value, list, message) {
+ if (list.indexOf(value) < 0) {
+ raise('invalid value' + encolon(message) + '. must be one of: ' + list);
+ }
+}
- var minDistance = Math.log('minDistance' in props ? props.minDistance : 0.1)
- var maxDistance = Math.log('maxDistance' in props ? props.maxDistance : 1000)
+var constructorKeys = [
+ 'gl',
+ 'canvas',
+ 'container',
+ 'attributes',
+ 'pixelRatio',
+ 'extensions',
+ 'optionalExtensions',
+ 'profile',
+ 'onDone'
+];
- var ddistance = 0
+function checkConstructor (obj) {
+ Object.keys(obj).forEach(function (key) {
+ if (constructorKeys.indexOf(key) < 0) {
+ raise('invalid regl constructor argument "' + key + '". must be one of ' + constructorKeys);
+ }
+ });
+}
- var prevX = 0
- var prevY = 0
+function leftPad (str, n) {
+ str = str + '';
+ while (str.length < n) {
+ str = ' ' + str;
+ }
+ return str
+}
- if (isBrowser && props.mouse !== false) {
- mouseChange(function (buttons, x, y) {
- if (buttons & 1) {
- var dx = (x - prevX) / window.innerWidth
- var dy = (y - prevY) / window.innerHeight
- var w = Math.max(cameraState.distance, 0.5)
+function ShaderFile () {
+ this.name = 'unknown';
+ this.lines = [];
+ this.index = {};
+ this.hasErrors = false;
+}
- cameraState.dtheta += w * dx
- cameraState.dphi += w * dy
+function ShaderLine (number, line) {
+ this.number = number;
+ this.line = line;
+ this.errors = [];
+}
+
+function ShaderError (fileNumber, lineNumber, message) {
+ this.file = fileNumber;
+ this.line = lineNumber;
+ this.message = message;
+}
+
+function guessCommand () {
+ var error = new Error();
+ var stack = (error.stack || error).toString();
+ var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack);
+ if (pat) {
+ return pat[1]
+ }
+ var pat2 = /compileProcedure.*\n\s*at\s+(.*)(\n|$)/.exec(stack);
+ if (pat2) {
+ return pat2[1]
+ }
+ return 'unknown'
+}
+
+function guessCallSite () {
+ var error = new Error();
+ var stack = (error.stack || error).toString();
+ var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack);
+ if (pat) {
+ return pat[1]
+ }
+ var pat2 = /at REGLCommand.*\n\s+at\s+(.*)\n/.exec(stack);
+ if (pat2) {
+ return pat2[1]
+ }
+ return 'unknown'
+}
+
+function parseSource (source, command) {
+ var lines = source.split('\n');
+ var lineNumber = 1;
+ var fileNumber = 0;
+ var files = {
+ unknown: new ShaderFile(),
+ 0: new ShaderFile()
+ };
+ files.unknown.name = files[0].name = command || guessCommand();
+ files.unknown.lines.push(new ShaderLine(0, ''));
+ for (var i = 0; i < lines.length; ++i) {
+ var line = lines[i];
+ var parts = /^\s*\#\s*(\w+)\s+(.+)\s*$/.exec(line);
+ if (parts) {
+ switch (parts[1]) {
+ case 'line':
+ var lineNumberInfo = /(\d+)(\s+\d+)?/.exec(parts[2]);
+ if (lineNumberInfo) {
+ lineNumber = lineNumberInfo[1] | 0;
+ if (lineNumberInfo[2]) {
+ fileNumber = lineNumberInfo[2] | 0;
+ if (!(fileNumber in files)) {
+ files[fileNumber] = new ShaderFile();
+ }
+ }
+ }
+ break
+ case 'define':
+ var nameInfo = /SHADER_NAME(_B64)?\s+(.*)$/.exec(parts[2]);
+ if (nameInfo) {
+ files[fileNumber].name = (nameInfo[1]
+ ? decodeB64(nameInfo[2])
+ : nameInfo[2]);
+ }
+ break
}
- prevX = x
- prevY = y
- })
+ }
+ files[fileNumber].lines.push(new ShaderLine(lineNumber++, line));
+ }
+ Object.keys(files).forEach(function (fileNumber) {
+ var file = files[fileNumber];
+ file.lines.forEach(function (line) {
+ file.index[line.number] = line;
+ });
+ });
+ return files
+}
+
+function parseErrorLog (errLog) {
+ var result = [];
+ errLog.split('\n').forEach(function (errMsg) {
+ if (errMsg.length < 5) {
+ return
+ }
+ var parts = /^ERROR\:\s+(\d+)\:(\d+)\:\s*(.*)$/.exec(errMsg);
+ if (parts) {
+ result.push(new ShaderError(
+ parts[1] | 0,
+ parts[2] | 0,
+ parts[3].trim()));
+ } else if (errMsg.length > 0) {
+ result.push(new ShaderError('unknown', 0, errMsg));
+ }
+ });
+ return result
+}
+
+function annotateFiles (files, errors) {
+ errors.forEach(function (error) {
+ var file = files[error.file];
+ if (file) {
+ var line = file.index[error.line];
+ if (line) {
+ line.errors.push(error);
+ file.hasErrors = true;
+ return
+ }
+ }
+ files.unknown.hasErrors = true;
+ files.unknown.lines[0].errors.push(error);
+ });
+}
+
+function checkShaderError (gl, shader, source, type, command) {
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ var errLog = gl.getShaderInfoLog(shader);
+ var typeName = type === gl.FRAGMENT_SHADER ? 'fragment' : 'vertex';
+ checkCommandType(source, 'string', typeName + ' shader source must be a string', command);
+ var files = parseSource(source, command);
+ var errors = parseErrorLog(errLog);
+ annotateFiles(files, errors);
+
+ Object.keys(files).forEach(function (fileNumber) {
+ var file = files[fileNumber];
+ if (!file.hasErrors) {
+ return
+ }
+
+ var strings = [''];
+ var styles = [''];
+
+ function push (str, style) {
+ strings.push(str);
+ styles.push(style || '');
+ }
+
+ push('file number ' + fileNumber + ': ' + file.name + '\n', 'color:red;text-decoration:underline;font-weight:bold');
+
+ file.lines.forEach(function (line) {
+ if (line.errors.length > 0) {
+ push(leftPad(line.number, 4) + '| ', 'background-color:yellow; font-weight:bold');
+ push(line.line + '\n', 'color:red; background-color:yellow; font-weight:bold');
+
+ // try to guess token
+ var offset = 0;
+ line.errors.forEach(function (error) {
+ var message = error.message;
+ var token = /^\s*\'(.*)\'\s*\:\s*(.*)$/.exec(message);
+ if (token) {
+ var tokenPat = token[1];
+ message = token[2];
+ switch (tokenPat) {
+ case 'assign':
+ tokenPat = '=';
+ break
+ }
+ offset = Math.max(line.line.indexOf(tokenPat, offset), 0);
+ } else {
+ offset = 0;
+ }
+
+ push(leftPad('| ', 6));
+ push(leftPad('^^^', offset + 3) + '\n', 'font-weight:bold');
+ push(leftPad('| ', 6));
+ push(message + '\n', 'font-weight:bold');
+ });
+ push(leftPad('| ', 6) + '\n');
+ } else {
+ push(leftPad(line.number, 4) + '| ');
+ push(line.line + '\n', 'color:red');
+ }
+ });
+ if (typeof document !== 'undefined') {
+ styles[0] = strings.join('%c');
+ console.log.apply(console, styles);
+ } else {
+ console.log(strings.join(''));
+ }
+ });
+
+ check.raise('Error compiling ' + typeName + ' shader, ' + files[0].name);
+ }
+}
+
+function checkLinkError (gl, program, fragShader, vertShader, command) {
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ var errLog = gl.getProgramInfoLog(program);
+ var fragParse = parseSource(fragShader, command);
+ var vertParse = parseSource(vertShader, command);
+
+ var header = 'Error linking program with vertex shader, "' +
+ vertParse[0].name + '", and fragment shader "' + fragParse[0].name + '"';
+
+ if (typeof document !== 'undefined') {
+ console.log('%c' + header + '\n%c' + errLog,
+ 'color:red;text-decoration:underline;font-weight:bold',
+ 'color:red');
+ } else {
+ console.log(header + '\n' + errLog);
+ }
+ check.raise(header);
+ }
+}
+
+function saveCommandRef (object) {
+ object._commandRef = guessCommand();
+}
+
+function saveDrawCommandInfo (opts, uniforms, attributes, stringStore) {
+ saveCommandRef(opts);
+
+ function id (str) {
+ if (str) {
+ return stringStore.id(str)
+ }
+ return 0
+ }
+ opts._fragId = id(opts.static.frag);
+ opts._vertId = id(opts.static.vert);
+
+ function addProps (dict, set) {
+ Object.keys(set).forEach(function (u) {
+ dict[stringStore.id(u)] = true;
+ });
+ }
+
+ var uniformSet = opts._uniformSet = {};
+ addProps(uniformSet, uniforms.static);
+ addProps(uniformSet, uniforms.dynamic);
+
+ var attributeSet = opts._attributeSet = {};
+ addProps(attributeSet, attributes.static);
+ addProps(attributeSet, attributes.dynamic);
+
+ opts._hasCount = (
+ 'count' in opts.static ||
+ 'count' in opts.dynamic ||
+ 'elements' in opts.static ||
+ 'elements' in opts.dynamic);
+}
+
+function commandRaise (message, command) {
+ var callSite = guessCallSite();
+ raise(message +
+ ' in command ' + (command || guessCommand()) +
+ (callSite === 'unknown' ? '' : ' called from ' + callSite));
+}
+
+function checkCommand (pred, message, command) {
+ if (!pred) {
+ commandRaise(message, command || guessCommand());
+ }
+}
+
+function checkParameterCommand (param, possibilities, message, command) {
+ if (!(param in possibilities)) {
+ commandRaise(
+ 'unknown parameter (' + param + ')' + encolon(message) +
+ '. possible values: ' + Object.keys(possibilities).join(),
+ command || guessCommand());
+ }
+}
+
+function checkCommandType (value, type, message, command) {
+ if (typeof value !== type) {
+ commandRaise(
+ 'invalid parameter type' + encolon(message) +
+ '. expected ' + type + ', got ' + (typeof value),
+ command || guessCommand());
+ }
+}
+
+function checkOptional (block) {
+ block();
+}
+
+function checkFramebufferFormat (attachment, texFormats, rbFormats) {
+ if (attachment.texture) {
+ checkOneOf(
+ attachment.texture._texture.internalformat,
+ texFormats,
+ 'unsupported texture format for attachment');
+ } else {
+ checkOneOf(
+ attachment.renderbuffer._renderbuffer.format,
+ rbFormats,
+ 'unsupported renderbuffer format for attachment');
+ }
+}
+
+var GL_CLAMP_TO_EDGE = 0x812F;
+
+var GL_NEAREST = 0x2600;
+var GL_NEAREST_MIPMAP_NEAREST = 0x2700;
+var GL_LINEAR_MIPMAP_NEAREST = 0x2701;
+var GL_NEAREST_MIPMAP_LINEAR = 0x2702;
+var GL_LINEAR_MIPMAP_LINEAR = 0x2703;
+
+var GL_BYTE = 5120;
+var GL_UNSIGNED_BYTE = 5121;
+var GL_SHORT = 5122;
+var GL_UNSIGNED_SHORT = 5123;
+var GL_INT = 5124;
+var GL_UNSIGNED_INT = 5125;
+var GL_FLOAT = 5126;
+
+var GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033;
+var GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
+var GL_UNSIGNED_SHORT_5_6_5 = 0x8363;
+var GL_UNSIGNED_INT_24_8_WEBGL = 0x84FA;
+
+var GL_HALF_FLOAT_OES = 0x8D61;
+
+var TYPE_SIZE = {};
+
+TYPE_SIZE[GL_BYTE] =
+TYPE_SIZE[GL_UNSIGNED_BYTE] = 1;
+
+TYPE_SIZE[GL_SHORT] =
+TYPE_SIZE[GL_UNSIGNED_SHORT] =
+TYPE_SIZE[GL_HALF_FLOAT_OES] =
+TYPE_SIZE[GL_UNSIGNED_SHORT_5_6_5] =
+TYPE_SIZE[GL_UNSIGNED_SHORT_4_4_4_4] =
+TYPE_SIZE[GL_UNSIGNED_SHORT_5_5_5_1] = 2;
+
+TYPE_SIZE[GL_INT] =
+TYPE_SIZE[GL_UNSIGNED_INT] =
+TYPE_SIZE[GL_FLOAT] =
+TYPE_SIZE[GL_UNSIGNED_INT_24_8_WEBGL] = 4;
+
+function pixelSize (type, channels) {
+ if (type === GL_UNSIGNED_SHORT_5_5_5_1 ||
+ type === GL_UNSIGNED_SHORT_4_4_4_4 ||
+ type === GL_UNSIGNED_SHORT_5_6_5) {
+ return 2
+ } else if (type === GL_UNSIGNED_INT_24_8_WEBGL) {
+ return 4
+ } else {
+ return TYPE_SIZE[type] * channels
+ }
+}
+
+function isPow2 (v) {
+ return !(v & (v - 1)) && (!!v)
+}
+
+function checkTexture2D (info, mipData, limits) {
+ var i;
+ var w = mipData.width;
+ var h = mipData.height;
+ var c = mipData.channels;
+
+ // Check texture shape
+ check(w > 0 && w <= limits.maxTextureSize &&
+ h > 0 && h <= limits.maxTextureSize,
+ 'invalid texture shape');
+
+ // check wrap mode
+ if (info.wrapS !== GL_CLAMP_TO_EDGE || info.wrapT !== GL_CLAMP_TO_EDGE) {
+ check(isPow2(w) && isPow2(h),
+ 'incompatible wrap mode for texture, both width and height must be power of 2');
+ }
+
+ if (mipData.mipmask === 1) {
+ if (w !== 1 && h !== 1) {
+ check(
+ info.minFilter !== GL_NEAREST_MIPMAP_NEAREST &&
+ info.minFilter !== GL_NEAREST_MIPMAP_LINEAR &&
+ info.minFilter !== GL_LINEAR_MIPMAP_NEAREST &&
+ info.minFilter !== GL_LINEAR_MIPMAP_LINEAR,
+ 'min filter requires mipmap');
+ }
+ } else {
+ // texture must be power of 2
+ check(isPow2(w) && isPow2(h),
+ 'texture must be a square power of 2 to support mipmapping');
+ check(mipData.mipmask === (w << 1) - 1,
+ 'missing or incomplete mipmap data');
+ }
+
+ if (mipData.type === GL_FLOAT) {
+ if (limits.extensions.indexOf('oes_texture_float_linear') < 0) {
+ check(info.minFilter === GL_NEAREST && info.magFilter === GL_NEAREST,
+ 'filter not supported, must enable oes_texture_float_linear');
+ }
+ check(!info.genMipmaps,
+ 'mipmap generation not supported with float textures');
+ }
+
+ // check image complete
+ var mipimages = mipData.images;
+ for (i = 0; i < 16; ++i) {
+ if (mipimages[i]) {
+ var mw = w >> i;
+ var mh = h >> i;
+ check(mipData.mipmask & (1 << i), 'missing mipmap data');
+
+ var img = mipimages[i];
+
+ check(
+ img.width === mw &&
+ img.height === mh,
+ 'invalid shape for mip images');
+
+ check(
+ img.format === mipData.format &&
+ img.internalformat === mipData.internalformat &&
+ img.type === mipData.type,
+ 'incompatible type for mip image');
+
+ if (img.compressed) {
+ // TODO: check size for compressed images
+ } else if (img.data) {
+ // check(img.data.byteLength === mw * mh *
+ // Math.max(pixelSize(img.type, c), img.unpackAlignment),
+ var rowSize = Math.ceil(pixelSize(img.type, c) * mw / img.unpackAlignment) * img.unpackAlignment;
+ check(img.data.byteLength === rowSize * mh,
+ 'invalid data for image, buffer size is inconsistent with image format');
+ } else if (img.element) {
+ // TODO: check element can be loaded
+ } else if (img.copy) {
+ // TODO: check compatible format and type
+ }
+ } else if (!info.genMipmaps) {
+ check((mipData.mipmask & (1 << i)) === 0, 'extra mipmap data');
+ }
+ }
+
+ if (mipData.compressed) {
+ check(!info.genMipmaps,
+ 'mipmap generation for compressed images not supported');
+ }
+}
+
+function checkTextureCube (texture, info, faces, limits) {
+ var w = texture.width;
+ var h = texture.height;
+ var c = texture.channels;
+
+ // Check texture shape
+ check(
+ w > 0 && w <= limits.maxTextureSize && h > 0 && h <= limits.maxTextureSize,
+ 'invalid texture shape');
+ check(
+ w === h,
+ 'cube map must be square');
+ check(
+ info.wrapS === GL_CLAMP_TO_EDGE && info.wrapT === GL_CLAMP_TO_EDGE,
+ 'wrap mode not supported by cube map');
+
+ for (var i = 0; i < faces.length; ++i) {
+ var face = faces[i];
+ check(
+ face.width === w && face.height === h,
+ 'inconsistent cube map face shape');
+
+ if (info.genMipmaps) {
+ check(!face.compressed,
+ 'can not generate mipmap for compressed textures');
+ check(face.mipmask === 1,
+ 'can not specify mipmaps and generate mipmaps');
+ } else {
+ // TODO: check mip and filter mode
+ }
+
+ var mipmaps = face.images;
+ for (var j = 0; j < 16; ++j) {
+ var img = mipmaps[j];
+ if (img) {
+ var mw = w >> j;
+ var mh = h >> j;
+ check(face.mipmask & (1 << j), 'missing mipmap data');
+ check(
+ img.width === mw &&
+ img.height === mh,
+ 'invalid shape for mip images');
+ check(
+ img.format === texture.format &&
+ img.internalformat === texture.internalformat &&
+ img.type === texture.type,
+ 'incompatible type for mip image');
+
+ if (img.compressed) {
+ // TODO: check size for compressed images
+ } else if (img.data) {
+ check(img.data.byteLength === mw * mh *
+ Math.max(pixelSize(img.type, c), img.unpackAlignment),
+ 'invalid data for image, buffer size is inconsistent with image format');
+ } else if (img.element) {
+ // TODO: check element can be loaded
+ } else if (img.copy) {
+ // TODO: check compatible format and type
+ }
+ }
+ }
+ }
+}
+
+var check$1 = extend(check, {
+ optional: checkOptional,
+ raise: raise,
+ commandRaise: commandRaise,
+ command: checkCommand,
+ parameter: checkParameter,
+ commandParameter: checkParameterCommand,
+ constructor: checkConstructor,
+ type: checkTypeOf,
+ commandType: checkCommandType,
+ isTypedArray: checkIsTypedArray,
+ nni: checkNonNegativeInt,
+ oneOf: checkOneOf,
+ shaderError: checkShaderError,
+ linkError: checkLinkError,
+ callSite: guessCallSite,
+ saveCommandRef: saveCommandRef,
+ saveDrawInfo: saveDrawCommandInfo,
+ framebufferFormat: checkFramebufferFormat,
+ guessCommand: guessCommand,
+ texture2D: checkTexture2D,
+ textureCube: checkTextureCube
+});
+
+var VARIABLE_COUNTER = 0;
+
+var DYN_FUNC = 0;
+
+function DynamicVariable (type, data) {
+ this.id = (VARIABLE_COUNTER++);
+ this.type = type;
+ this.data = data;
+}
+
+function escapeStr (str) {
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
+}
+
+function splitParts (str) {
+ if (str.length === 0) {
+ return []
+ }
+
+ var firstChar = str.charAt(0);
+ var lastChar = str.charAt(str.length - 1);
+
+ if (str.length > 1 &&
+ firstChar === lastChar &&
+ (firstChar === '"' || firstChar === "'")) {
+ return ['"' + escapeStr(str.substr(1, str.length - 2)) + '"']
+ }
+
+ var parts = /\[(false|true|null|\d+|'[^']*'|"[^"]*")\]/.exec(str);
+ if (parts) {
+ return (
+ splitParts(str.substr(0, parts.index))
+ .concat(splitParts(parts[1]))
+ .concat(splitParts(str.substr(parts.index + parts[0].length)))
+ )
+ }
+
+ var subparts = str.split('.');
+ if (subparts.length === 1) {
+ return ['"' + escapeStr(str) + '"']
+ }
+
+ var result = [];
+ for (var i = 0; i < subparts.length; ++i) {
+ result = result.concat(splitParts(subparts[i]));
+ }
+ return result
+}
+
+function toAccessorString (str) {
+ return '[' + splitParts(str).join('][') + ']'
+}
+
+function defineDynamic (type, data) {
+ return new DynamicVariable(type, toAccessorString(data + ''))
+}
+
+function isDynamic (x) {
+ return (typeof x === 'function' && !x._reglType) ||
+ x instanceof DynamicVariable
+}
+
+function unbox (x, path) {
+ if (typeof x === 'function') {
+ return new DynamicVariable(DYN_FUNC, x)
+ }
+ return x
+}
+
+var dynamic = {
+ DynamicVariable: DynamicVariable,
+ define: defineDynamic,
+ isDynamic: isDynamic,
+ unbox: unbox,
+ accessor: toAccessorString
+};
+
+/* globals requestAnimationFrame, cancelAnimationFrame */
+var raf = {
+ next: typeof requestAnimationFrame === 'function'
+ ? function (cb) { return requestAnimationFrame(cb) }
+ : function (cb) { return setTimeout(cb, 16) },
+ cancel: typeof cancelAnimationFrame === 'function'
+ ? function (raf) { return cancelAnimationFrame(raf) }
+ : clearTimeout
+};
+
+/* globals performance */
+var clock = (typeof performance !== 'undefined' && performance.now)
+ ? function () { return performance.now() }
+ : function () { return +(new Date()) };
+
+function createStringStore () {
+ var stringIds = {'': 0};
+ var stringValues = [''];
+ return {
+ id: function (str) {
+ var result = stringIds[str];
+ if (result) {
+ return result
+ }
+ result = stringIds[str] = stringValues.length;
+ stringValues.push(str);
+ return result
+ },
+
+ str: function (id) {
+ return stringValues[id]
+ }
+ }
+}
+
+// Context and canvas creation helper functions
+function createCanvas (element, onDone, pixelRatio) {
+ var canvas = document.createElement('canvas');
+ extend(canvas.style, {
+ border: 0,
+ margin: 0,
+ padding: 0,
+ top: 0,
+ left: 0
+ });
+ element.appendChild(canvas);
+
+ if (element === document.body) {
+ canvas.style.position = 'absolute';
+ extend(element.style, {
+ margin: 0,
+ padding: 0
+ });
+ }
+
+ function resize () {
+ var w = window.innerWidth;
+ var h = window.innerHeight;
+ if (element !== document.body) {
+ var bounds = element.getBoundingClientRect();
+ w = bounds.right - bounds.left;
+ h = bounds.bottom - bounds.top;
+ }
+ canvas.width = pixelRatio * w;
+ canvas.height = pixelRatio * h;
+ extend(canvas.style, {
+ width: w + 'px',
+ height: h + 'px'
+ });
+ }
+
+ window.addEventListener('resize', resize, false);
+
+ function onDestroy () {
+ window.removeEventListener('resize', resize);
+ element.removeChild(canvas);
+ }
+
+ resize();
+
+ return {
+ canvas: canvas,
+ onDestroy: onDestroy
+ }
+}
+
+function createContext (canvas, contexAttributes) {
+ function get (name) {
+ try {
+ return canvas.getContext(name, contexAttributes)
+ } catch (e) {
+ return null
+ }
+ }
+ return (
+ get('webgl') ||
+ get('experimental-webgl') ||
+ get('webgl-experimental')
+ )
+}
+
+function isHTMLElement (obj) {
+ return (
+ typeof obj.nodeName === 'string' &&
+ typeof obj.appendChild === 'function' &&
+ typeof obj.getBoundingClientRect === 'function'
+ )
+}
+
+function isWebGLContext (obj) {
+ return (
+ typeof obj.drawArrays === 'function' ||
+ typeof obj.drawElements === 'function'
+ )
+}
+
+function parseExtensions (input) {
+ if (typeof input === 'string') {
+ return input.split()
+ }
+ check$1(Array.isArray(input), 'invalid extension array');
+ return input
+}
+
+function getElement (desc) {
+ if (typeof desc === 'string') {
+ check$1(typeof document !== 'undefined', 'not supported outside of DOM');
+ return document.querySelector(desc)
+ }
+ return desc
+}
+
+function parseArgs (args_) {
+ var args = args_ || {};
+ var element, container, canvas, gl;
+ var contextAttributes = {};
+ var extensions = [];
+ var optionalExtensions = [];
+ var pixelRatio = (typeof window === 'undefined' ? 1 : window.devicePixelRatio);
+ var profile = false;
+ var onDone = function (err) {
+ if (err) {
+ check$1.raise(err);
+ }
+ };
+ var onDestroy = function () {};
+ if (typeof args === 'string') {
+ check$1(
+ typeof document !== 'undefined',
+ 'selector queries only supported in DOM enviroments');
+ element = document.querySelector(args);
+ check$1(element, 'invalid query string for element');
+ } else if (typeof args === 'object') {
+ if (isHTMLElement(args)) {
+ element = args;
+ } else if (isWebGLContext(args)) {
+ gl = args;
+ canvas = gl.canvas;
+ } else {
+ check$1.constructor(args);
+ if ('gl' in args) {
+ gl = args.gl;
+ } else if ('canvas' in args) {
+ canvas = getElement(args.canvas);
+ } else if ('container' in args) {
+ container = getElement(args.container);
+ }
+ if ('attributes' in args) {
+ contextAttributes = args.attributes;
+ check$1.type(contextAttributes, 'object', 'invalid context attributes');
+ }
+ if ('extensions' in args) {
+ extensions = parseExtensions(args.extensions);
+ }
+ if ('optionalExtensions' in args) {
+ optionalExtensions = parseExtensions(args.optionalExtensions);
+ }
+ if ('onDone' in args) {
+ check$1.type(
+ args.onDone, 'function',
+ 'invalid or missing onDone callback');
+ onDone = args.onDone;
+ }
+ if ('profile' in args) {
+ profile = !!args.profile;
+ }
+ if ('pixelRatio' in args) {
+ pixelRatio = +args.pixelRatio;
+ check$1(pixelRatio > 0, 'invalid pixel ratio');
+ }
+ }
+ } else {
+ check$1.raise('invalid arguments to regl');
+ }
+
+ if (element) {
+ if (element.nodeName.toLowerCase() === 'canvas') {
+ canvas = element;
+ } else {
+ container = element;
+ }
+ }
+
+ if (!gl) {
+ if (!canvas) {
+ check$1(
+ typeof document !== 'undefined',
+ 'must manually specify webgl context outside of DOM environments');
+ var result = createCanvas(container || document.body, onDone, pixelRatio);
+ if (!result) {
+ return null
+ }
+ canvas = result.canvas;
+ onDestroy = result.onDestroy;
+ }
+ gl = createContext(canvas, contextAttributes);
+ }
+
+ if (!gl) {
+ onDestroy();
+ onDone('webgl not supported, try upgrading your browser or graphics drivers http://get.webgl.org');
+ return null
+ }
+
+ return {
+ gl: gl,
+ canvas: canvas,
+ container: container,
+ extensions: extensions,
+ optionalExtensions: optionalExtensions,
+ pixelRatio: pixelRatio,
+ profile: profile,
+ onDone: onDone,
+ onDestroy: onDestroy
+ }
+}
+
+function createExtensionCache (gl, config) {
+ var extensions = {};
+
+ function tryLoadExtension (name_) {
+ check$1.type(name_, 'string', 'extension name must be string');
+ var name = name_.toLowerCase();
+ var ext;
+ try {
+ ext = extensions[name] = gl.getExtension(name);
+ } catch (e) {}
+ return !!ext
+ }
+
+ for (var i = 0; i < config.extensions.length; ++i) {
+ var name = config.extensions[i];
+ if (!tryLoadExtension(name)) {
+ config.onDestroy();
+ config.onDone('"' + name + '" extension is not supported by the current WebGL context, try upgrading your system or a different browser');
+ return null
+ }
+ }
+
+ config.optionalExtensions.forEach(tryLoadExtension);
+
+ return {
+ extensions: extensions,
+ restore: function () {
+ Object.keys(extensions).forEach(function (name) {
+ if (!tryLoadExtension(name)) {
+ throw new Error('(regl): error restoring extension ' + name)
+ }
+ });
+ }
+ }
+}
+
+var GL_SUBPIXEL_BITS = 0x0D50;
+var GL_RED_BITS = 0x0D52;
+var GL_GREEN_BITS = 0x0D53;
+var GL_BLUE_BITS = 0x0D54;
+var GL_ALPHA_BITS = 0x0D55;
+var GL_DEPTH_BITS = 0x0D56;
+var GL_STENCIL_BITS = 0x0D57;
+
+var GL_ALIASED_POINT_SIZE_RANGE = 0x846D;
+var GL_ALIASED_LINE_WIDTH_RANGE = 0x846E;
+
+var GL_MAX_TEXTURE_SIZE = 0x0D33;
+var GL_MAX_VIEWPORT_DIMS = 0x0D3A;
+var GL_MAX_VERTEX_ATTRIBS = 0x8869;
+var GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
+var GL_MAX_VARYING_VECTORS = 0x8DFC;
+var GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D;
+var GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
+var GL_MAX_TEXTURE_IMAGE_UNITS = 0x8872;
+var GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD;
+var GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
+var GL_MAX_RENDERBUFFER_SIZE = 0x84E8;
+
+var GL_VENDOR = 0x1F00;
+var GL_RENDERER = 0x1F01;
+var GL_VERSION = 0x1F02;
+var GL_SHADING_LANGUAGE_VERSION = 0x8B8C;
+
+var GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
+
+var GL_MAX_COLOR_ATTACHMENTS_WEBGL = 0x8CDF;
+var GL_MAX_DRAW_BUFFERS_WEBGL = 0x8824;
+
+var wrapLimits = function (gl, extensions) {
+ var maxAnisotropic = 1;
+ if (extensions.ext_texture_filter_anisotropic) {
+ maxAnisotropic = gl.getParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+ }
+
+ var maxDrawbuffers = 1;
+ var maxColorAttachments = 1;
+ if (extensions.webgl_draw_buffers) {
+ maxDrawbuffers = gl.getParameter(GL_MAX_DRAW_BUFFERS_WEBGL);
+ maxColorAttachments = gl.getParameter(GL_MAX_COLOR_ATTACHMENTS_WEBGL);
+ }
+
+ return {
+ // drawing buffer bit depth
+ colorBits: [
+ gl.getParameter(GL_RED_BITS),
+ gl.getParameter(GL_GREEN_BITS),
+ gl.getParameter(GL_BLUE_BITS),
+ gl.getParameter(GL_ALPHA_BITS)
+ ],
+ depthBits: gl.getParameter(GL_DEPTH_BITS),
+ stencilBits: gl.getParameter(GL_STENCIL_BITS),
+ subpixelBits: gl.getParameter(GL_SUBPIXEL_BITS),
+
+ // supported extensions
+ extensions: Object.keys(extensions).filter(function (ext) {
+ return !!extensions[ext]
+ }),
+
+ // max aniso samples
+ maxAnisotropic: maxAnisotropic,
+
+ // max draw buffers
+ maxDrawbuffers: maxDrawbuffers,
+ maxColorAttachments: maxColorAttachments,
+
+ // point and line size ranges
+ pointSizeDims: gl.getParameter(GL_ALIASED_POINT_SIZE_RANGE),
+ lineWidthDims: gl.getParameter(GL_ALIASED_LINE_WIDTH_RANGE),
+ maxViewportDims: gl.getParameter(GL_MAX_VIEWPORT_DIMS),
+ maxCombinedTextureUnits: gl.getParameter(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS),
+ maxCubeMapSize: gl.getParameter(GL_MAX_CUBE_MAP_TEXTURE_SIZE),
+ maxRenderbufferSize: gl.getParameter(GL_MAX_RENDERBUFFER_SIZE),
+ maxTextureUnits: gl.getParameter(GL_MAX_TEXTURE_IMAGE_UNITS),
+ maxTextureSize: gl.getParameter(GL_MAX_TEXTURE_SIZE),
+ maxAttributes: gl.getParameter(GL_MAX_VERTEX_ATTRIBS),
+ maxVertexUniforms: gl.getParameter(GL_MAX_VERTEX_UNIFORM_VECTORS),
+ maxVertexTextureUnits: gl.getParameter(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS),
+ maxVaryingVectors: gl.getParameter(GL_MAX_VARYING_VECTORS),
+ maxFragmentUniforms: gl.getParameter(GL_MAX_FRAGMENT_UNIFORM_VECTORS),
+
+ // vendor info
+ glsl: gl.getParameter(GL_SHADING_LANGUAGE_VERSION),
+ renderer: gl.getParameter(GL_RENDERER),
+ vendor: gl.getParameter(GL_VENDOR),
+ version: gl.getParameter(GL_VERSION)
+ }
+};
+
+function isNDArrayLike (obj) {
+ return (
+ !!obj &&
+ typeof obj === 'object' &&
+ Array.isArray(obj.shape) &&
+ Array.isArray(obj.stride) &&
+ typeof obj.offset === 'number' &&
+ obj.shape.length === obj.stride.length &&
+ (Array.isArray(obj.data) ||
+ isTypedArray(obj.data)))
+}
+
+var values = function (obj) {
+ return Object.keys(obj).map(function (key) { return obj[key] })
+};
+
+function loop (n, f) {
+ var result = Array(n);
+ for (var i = 0; i < n; ++i) {
+ result[i] = f(i);
+ }
+ return result
+}
+
+var GL_BYTE$1 = 5120;
+var GL_UNSIGNED_BYTE$2 = 5121;
+var GL_SHORT$1 = 5122;
+var GL_UNSIGNED_SHORT$1 = 5123;
+var GL_INT$1 = 5124;
+var GL_UNSIGNED_INT$1 = 5125;
+var GL_FLOAT$2 = 5126;
+
+var bufferPool = loop(8, function () {
+ return []
+});
+
+function nextPow16 (v) {
+ for (var i = 16; i <= (1 << 28); i *= 16) {
+ if (v <= i) {
+ return i
+ }
+ }
+ return 0
+}
+
+function log2 (v) {
+ var r, shift;
+ r = (v > 0xFFFF) << 4;
+ v >>>= r;
+ shift = (v > 0xFF) << 3;
+ v >>>= shift; r |= shift;
+ shift = (v > 0xF) << 2;
+ v >>>= shift; r |= shift;
+ shift = (v > 0x3) << 1;
+ v >>>= shift; r |= shift;
+ return r | (v >> 1)
+}
+
+function alloc (n) {
+ var sz = nextPow16(n);
+ var bin = bufferPool[log2(sz) >> 2];
+ if (bin.length > 0) {
+ return bin.pop()
+ }
+ return new ArrayBuffer(sz)
+}
+
+function free (buf) {
+ bufferPool[log2(buf.byteLength) >> 2].push(buf);
+}
+
+function allocType (type, n) {
+ var result = null;
+ switch (type) {
+ case GL_BYTE$1:
+ result = new Int8Array(alloc(n), 0, n);
+ break
+ case GL_UNSIGNED_BYTE$2:
+ result = new Uint8Array(alloc(n), 0, n);
+ break
+ case GL_SHORT$1:
+ result = new Int16Array(alloc(2 * n), 0, n);
+ break
+ case GL_UNSIGNED_SHORT$1:
+ result = new Uint16Array(alloc(2 * n), 0, n);
+ break
+ case GL_INT$1:
+ result = new Int32Array(alloc(4 * n), 0, n);
+ break
+ case GL_UNSIGNED_INT$1:
+ result = new Uint32Array(alloc(4 * n), 0, n);
+ break
+ case GL_FLOAT$2:
+ result = new Float32Array(alloc(4 * n), 0, n);
+ break
+ default:
+ return null
+ }
+ if (result.length !== n) {
+ return result.subarray(0, n)
+ }
+ return result
+}
+
+function freeType (array) {
+ free(array.buffer);
+}
+
+var pool = {
+ alloc: alloc,
+ free: free,
+ allocType: allocType,
+ freeType: freeType
+};
+
+var flattenUtils = {
+ shape: arrayShape$1,
+ flatten: flattenArray
+};
+
+function flatten1D (array, nx, out) {
+ for (var i = 0; i < nx; ++i) {
+ out[i] = array[i];
+ }
+}
+
+function flatten2D (array, nx, ny, out) {
+ var ptr = 0;
+ for (var i = 0; i < nx; ++i) {
+ var row = array[i];
+ for (var j = 0; j < ny; ++j) {
+ out[ptr++] = row[j];
+ }
+ }
+}
+
+function flatten3D (array, nx, ny, nz, out, ptr_) {
+ var ptr = ptr_;
+ for (var i = 0; i < nx; ++i) {
+ var row = array[i];
+ for (var j = 0; j < ny; ++j) {
+ var col = row[j];
+ for (var k = 0; k < nz; ++k) {
+ out[ptr++] = col[k];
+ }
+ }
+ }
+}
+
+function flattenRec (array, shape, level, out, ptr) {
+ var stride = 1;
+ for (var i = level + 1; i < shape.length; ++i) {
+ stride *= shape[i];
+ }
+ var n = shape[level];
+ if (shape.length - level === 4) {
+ var nx = shape[level + 1];
+ var ny = shape[level + 2];
+ var nz = shape[level + 3];
+ for (i = 0; i < n; ++i) {
+ flatten3D(array[i], nx, ny, nz, out, ptr);
+ ptr += stride;
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ flattenRec(array[i], shape, level + 1, out, ptr);
+ ptr += stride;
+ }
+ }
+}
+
+function flattenArray (array, shape, type, out_) {
+ var sz = 1;
+ if (shape.length) {
+ for (var i = 0; i < shape.length; ++i) {
+ sz *= shape[i];
+ }
+ } else {
+ sz = 0;
+ }
+ var out = out_ || pool.allocType(type, sz);
+ switch (shape.length) {
+ case 0:
+ break
+ case 1:
+ flatten1D(array, shape[0], out);
+ break
+ case 2:
+ flatten2D(array, shape[0], shape[1], out);
+ break
+ case 3:
+ flatten3D(array, shape[0], shape[1], shape[2], out, 0);
+ break
+ default:
+ flattenRec(array, shape, 0, out, 0);
+ }
+ return out
+}
+
+function arrayShape$1 (array_) {
+ var shape = [];
+ for (var array = array_; array.length; array = array[0]) {
+ shape.push(array.length);
+ }
+ return shape
+}
+
+var int8 = 5120;
+var int16 = 5122;
+var int32 = 5124;
+var uint8 = 5121;
+var uint16 = 5123;
+var uint32 = 5125;
+var float = 5126;
+var float32 = 5126;
+var glTypes = {
+ int8: int8,
+ int16: int16,
+ int32: int32,
+ uint8: uint8,
+ uint16: uint16,
+ uint32: uint32,
+ float: float,
+ float32: float32
+};
+
+var dynamic$1 = 35048;
+var stream = 35040;
+var usageTypes = {
+ dynamic: dynamic$1,
+ stream: stream,
+ "static": 35044
+};
+
+var arrayFlatten = flattenUtils.flatten;
+var arrayShape = flattenUtils.shape;
+
+var GL_STATIC_DRAW = 0x88E4;
+var GL_STREAM_DRAW = 0x88E0;
+
+var GL_UNSIGNED_BYTE$1 = 5121;
+var GL_FLOAT$1 = 5126;
+
+var DTYPES_SIZES = [];
+DTYPES_SIZES[5120] = 1; // int8
+DTYPES_SIZES[5122] = 2; // int16
+DTYPES_SIZES[5124] = 4; // int32
+DTYPES_SIZES[5121] = 1; // uint8
+DTYPES_SIZES[5123] = 2; // uint16
+DTYPES_SIZES[5125] = 4; // uint32
+DTYPES_SIZES[5126] = 4; // float32
+
+function typedArrayCode (data) {
+ return arrayTypes[Object.prototype.toString.call(data)] | 0
+}
+
+function copyArray (out, inp) {
+ for (var i = 0; i < inp.length; ++i) {
+ out[i] = inp[i];
+ }
+}
+
+function transpose (
+ result, data, shapeX, shapeY, strideX, strideY, offset) {
+ var ptr = 0;
+ for (var i = 0; i < shapeX; ++i) {
+ for (var j = 0; j < shapeY; ++j) {
+ result[ptr++] = data[strideX * i + strideY * j + offset];
+ }
+ }
+}
+
+function wrapBufferState (gl, stats, config) {
+ var bufferCount = 0;
+ var bufferSet = {};
+
+ function REGLBuffer (type) {
+ this.id = bufferCount++;
+ this.buffer = gl.createBuffer();
+ this.type = type;
+ this.usage = GL_STATIC_DRAW;
+ this.byteLength = 0;
+ this.dimension = 1;
+ this.dtype = GL_UNSIGNED_BYTE$1;
+
+ this.persistentData = null;
+
+ if (config.profile) {
+ this.stats = {size: 0};
+ }
+ }
+
+ REGLBuffer.prototype.bind = function () {
+ gl.bindBuffer(this.type, this.buffer);
+ };
+
+ REGLBuffer.prototype.destroy = function () {
+ destroy(this);
+ };
+
+ var streamPool = [];
+
+ function createStream (type, data) {
+ var buffer = streamPool.pop();
+ if (!buffer) {
+ buffer = new REGLBuffer(type);
+ }
+ buffer.bind();
+ initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false);
+ return buffer
+ }
+
+ function destroyStream (stream$$1) {
+ streamPool.push(stream$$1);
+ }
+
+ function initBufferFromTypedArray (buffer, data, usage) {
+ buffer.byteLength = data.byteLength;
+ gl.bufferData(buffer.type, data, usage);
+ }
+
+ function initBufferFromData (buffer, data, usage, dtype, dimension, persist) {
+ var shape;
+ buffer.usage = usage;
+ if (Array.isArray(data)) {
+ buffer.dtype = dtype || GL_FLOAT$1;
+ if (data.length > 0) {
+ var flatData;
+ if (Array.isArray(data[0])) {
+ shape = arrayShape(data);
+ var dim = 1;
+ for (var i = 1; i < shape.length; ++i) {
+ dim *= shape[i];
+ }
+ buffer.dimension = dim;
+ flatData = arrayFlatten(data, shape, buffer.dtype);
+ initBufferFromTypedArray(buffer, flatData, usage);
+ if (persist) {
+ buffer.persistentData = flatData;
+ } else {
+ pool.freeType(flatData);
+ }
+ } else if (typeof data[0] === 'number') {
+ buffer.dimension = dimension;
+ var typedData = pool.allocType(buffer.dtype, data.length);
+ copyArray(typedData, data);
+ initBufferFromTypedArray(buffer, typedData, usage);
+ if (persist) {
+ buffer.persistentData = typedData;
+ } else {
+ pool.freeType(typedData);
+ }
+ } else if (isTypedArray(data[0])) {
+ buffer.dimension = data[0].length;
+ buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT$1;
+ flatData = arrayFlatten(
+ data,
+ [data.length, data[0].length],
+ buffer.dtype);
+ initBufferFromTypedArray(buffer, flatData, usage);
+ if (persist) {
+ buffer.persistentData = flatData;
+ } else {
+ pool.freeType(flatData);
+ }
+ } else {
+ check$1.raise('invalid buffer data');
+ }
+ }
+ } else if (isTypedArray(data)) {
+ buffer.dtype = dtype || typedArrayCode(data);
+ buffer.dimension = dimension;
+ initBufferFromTypedArray(buffer, data, usage);
+ if (persist) {
+ buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer));
+ }
+ } else if (isNDArrayLike(data)) {
+ shape = data.shape;
+ var stride = data.stride;
+ var offset = data.offset;
+
+ var shapeX = 0;
+ var shapeY = 0;
+ var strideX = 0;
+ var strideY = 0;
+ if (shape.length === 1) {
+ shapeX = shape[0];
+ shapeY = 1;
+ strideX = stride[0];
+ strideY = 0;
+ } else if (shape.length === 2) {
+ shapeX = shape[0];
+ shapeY = shape[1];
+ strideX = stride[0];
+ strideY = stride[1];
+ } else {
+ check$1.raise('invalid shape');
+ }
+
+ buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT$1;
+ buffer.dimension = shapeY;
+
+ var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY);
+ transpose(transposeData,
+ data.data,
+ shapeX, shapeY,
+ strideX, strideY,
+ offset);
+ initBufferFromTypedArray(buffer, transposeData, usage);
+ if (persist) {
+ buffer.persistentData = transposeData;
+ } else {
+ pool.freeType(transposeData);
+ }
+ } else {
+ check$1.raise('invalid buffer data');
+ }
+ }
+
+ function destroy (buffer) {
+ stats.bufferCount--;
+
+ var handle = buffer.buffer;
+ check$1(handle, 'buffer must not be deleted already');
+ gl.deleteBuffer(handle);
+ buffer.buffer = null;
+ delete bufferSet[buffer.id];
+ }
+
+ function createBuffer (options, type, deferInit, persistent) {
+ stats.bufferCount++;
+
+ var buffer = new REGLBuffer(type);
+ bufferSet[buffer.id] = buffer;
+
+ function reglBuffer (options) {
+ var usage = GL_STATIC_DRAW;
+ var data = null;
+ var byteLength = 0;
+ var dtype = 0;
+ var dimension = 1;
+ if (Array.isArray(options) ||
+ isTypedArray(options) ||
+ isNDArrayLike(options)) {
+ data = options;
+ } else if (typeof options === 'number') {
+ byteLength = options | 0;
+ } else if (options) {
+ check$1.type(
+ options, 'object',
+ 'buffer arguments must be an object, a number or an array');
+
+ if ('data' in options) {
+ check$1(
+ data === null ||
+ Array.isArray(data) ||
+ isTypedArray(data) ||
+ isNDArrayLike(data),
+ 'invalid data for buffer');
+ data = options.data;
+ }
+
+ if ('usage' in options) {
+ check$1.parameter(options.usage, usageTypes, 'invalid buffer usage');
+ usage = usageTypes[options.usage];
+ }
+
+ if ('type' in options) {
+ check$1.parameter(options.type, glTypes, 'invalid buffer type');
+ dtype = glTypes[options.type];
+ }
+
+ if ('dimension' in options) {
+ check$1.type(options.dimension, 'number', 'invalid dimension');
+ dimension = options.dimension | 0;
+ }
+
+ if ('length' in options) {
+ check$1.nni(byteLength, 'buffer length must be a nonnegative integer');
+ byteLength = options.length | 0;
+ }
+ }
+
+ buffer.bind();
+ if (!data) {
+ gl.bufferData(buffer.type, byteLength, usage);
+ buffer.dtype = dtype || GL_UNSIGNED_BYTE$1;
+ buffer.usage = usage;
+ buffer.dimension = dimension;
+ buffer.byteLength = byteLength;
+ } else {
+ initBufferFromData(buffer, data, usage, dtype, dimension, persistent);
+ }
+
+ if (config.profile) {
+ buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype];
+ }
+
+ return reglBuffer
+ }
+
+ function setSubData (data, offset) {
+ check$1(offset + data.byteLength <= buffer.byteLength,
+ 'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength);
+
+ gl.bufferSubData(buffer.type, offset, data);
+ }
+
+ function subdata (data, offset_) {
+ var offset = (offset_ || 0) | 0;
+ var shape;
+ buffer.bind();
+ if (Array.isArray(data)) {
+ if (data.length > 0) {
+ if (typeof data[0] === 'number') {
+ var converted = pool.allocType(buffer.dtype, data.length);
+ copyArray(converted, data);
+ setSubData(converted, offset);
+ pool.freeType(converted);
+ } else if (Array.isArray(data[0]) || isTypedArray(data[0])) {
+ shape = arrayShape(data);
+ var flatData = arrayFlatten(data, shape, buffer.dtype);
+ setSubData(flatData, offset);
+ pool.freeType(flatData);
+ } else {
+ check$1.raise('invalid buffer data');
+ }
+ }
+ } else if (isTypedArray(data)) {
+ setSubData(data, offset);
+ } else if (isNDArrayLike(data)) {
+ shape = data.shape;
+ var stride = data.stride;
+
+ var shapeX = 0;
+ var shapeY = 0;
+ var strideX = 0;
+ var strideY = 0;
+ if (shape.length === 1) {
+ shapeX = shape[0];
+ shapeY = 1;
+ strideX = stride[0];
+ strideY = 0;
+ } else if (shape.length === 2) {
+ shapeX = shape[0];
+ shapeY = shape[1];
+ strideX = stride[0];
+ strideY = stride[1];
+ } else {
+ check$1.raise('invalid shape');
+ }
+ var dtype = Array.isArray(data.data)
+ ? buffer.dtype
+ : typedArrayCode(data.data);
+
+ var transposeData = pool.allocType(dtype, shapeX * shapeY);
+ transpose(transposeData,
+ data.data,
+ shapeX, shapeY,
+ strideX, strideY,
+ data.offset);
+ setSubData(transposeData, offset);
+ pool.freeType(transposeData);
+ } else {
+ check$1.raise('invalid data for buffer subdata');
+ }
+ return reglBuffer
+ }
+
+ if (!deferInit) {
+ reglBuffer(options);
+ }
+
+ reglBuffer._reglType = 'buffer';
+ reglBuffer._buffer = buffer;
+ reglBuffer.subdata = subdata;
+ if (config.profile) {
+ reglBuffer.stats = buffer.stats;
+ }
+ reglBuffer.destroy = function () { destroy(buffer); };
+
+ return reglBuffer
+ }
+
+ function restoreBuffers () {
+ values(bufferSet).forEach(function (buffer) {
+ buffer.buffer = gl.createBuffer();
+ gl.bindBuffer(buffer.type, buffer.buffer);
+ gl.bufferData(
+ buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage);
+ });
+ }
+
+ if (config.profile) {
+ stats.getTotalBufferSize = function () {
+ var total = 0;
+ // TODO: Right now, the streams are not part of the total count.
+ Object.keys(bufferSet).forEach(function (key) {
+ total += bufferSet[key].stats.size;
+ });
+ return total
+ };
+ }
+
+ return {
+ create: createBuffer,
+
+ createStream: createStream,
+ destroyStream: destroyStream,
+
+ clear: function () {
+ values(bufferSet).forEach(destroy);
+ streamPool.forEach(destroy);
+ },
+
+ getBuffer: function (wrapper) {
+ if (wrapper && wrapper._buffer instanceof REGLBuffer) {
+ return wrapper._buffer
+ }
+ return null
+ },
+
+ restore: restoreBuffers,
+
+ _initBuffer: initBufferFromData
+ }
+}
+
+var points = 0;
+var point = 0;
+var lines = 1;
+var line = 1;
+var triangles = 4;
+var triangle = 4;
+var primTypes = {
+ points: points,
+ point: point,
+ lines: lines,
+ line: line,
+ triangles: triangles,
+ triangle: triangle,
+ "line loop": 2,
+ "line strip": 3,
+ "triangle strip": 5,
+ "triangle fan": 6
+};
+
+var GL_POINTS = 0;
+var GL_LINES = 1;
+var GL_TRIANGLES = 4;
+
+var GL_BYTE$2 = 5120;
+var GL_UNSIGNED_BYTE$3 = 5121;
+var GL_SHORT$2 = 5122;
+var GL_UNSIGNED_SHORT$2 = 5123;
+var GL_INT$2 = 5124;
+var GL_UNSIGNED_INT$2 = 5125;
+
+var GL_ELEMENT_ARRAY_BUFFER = 34963;
+
+var GL_STREAM_DRAW$1 = 0x88E0;
+var GL_STATIC_DRAW$1 = 0x88E4;
+
+function wrapElementsState (gl, extensions, bufferState, stats) {
+ var elementSet = {};
+ var elementCount = 0;
+
+ var elementTypes = {
+ 'uint8': GL_UNSIGNED_BYTE$3,
+ 'uint16': GL_UNSIGNED_SHORT$2
+ };
+
+ if (extensions.oes_element_index_uint) {
+ elementTypes.uint32 = GL_UNSIGNED_INT$2;
+ }
+
+ function REGLElementBuffer (buffer) {
+ this.id = elementCount++;
+ elementSet[this.id] = this;
+ this.buffer = buffer;
+ this.primType = GL_TRIANGLES;
+ this.vertCount = 0;
+ this.type = 0;
+ }
+
+ REGLElementBuffer.prototype.bind = function () {
+ this.buffer.bind();
+ };
+
+ var bufferPool = [];
+
+ function createElementStream (data) {
+ var result = bufferPool.pop();
+ if (!result) {
+ result = new REGLElementBuffer(bufferState.create(
+ null,
+ GL_ELEMENT_ARRAY_BUFFER,
+ true,
+ false)._buffer);
+ }
+ initElements(result, data, GL_STREAM_DRAW$1, -1, -1, 0, 0);
+ return result
+ }
+
+ function destroyElementStream (elements) {
+ bufferPool.push(elements);
+ }
+
+ function initElements (
+ elements,
+ data,
+ usage,
+ prim,
+ count,
+ byteLength,
+ type) {
+ elements.buffer.bind();
+ if (data) {
+ var predictedType = type;
+ if (!type && (
+ !isTypedArray(data) ||
+ (isNDArrayLike(data) && !isTypedArray(data.data)))) {
+ predictedType = extensions.oes_element_index_uint
+ ? GL_UNSIGNED_INT$2
+ : GL_UNSIGNED_SHORT$2;
+ }
+ bufferState._initBuffer(
+ elements.buffer,
+ data,
+ usage,
+ predictedType,
+ 3);
+ } else {
+ gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage);
+ elements.buffer.dtype = dtype || GL_UNSIGNED_BYTE$3;
+ elements.buffer.usage = usage;
+ elements.buffer.dimension = 3;
+ elements.buffer.byteLength = byteLength;
+ }
+
+ var dtype = type;
+ if (!type) {
+ switch (elements.buffer.dtype) {
+ case GL_UNSIGNED_BYTE$3:
+ case GL_BYTE$2:
+ dtype = GL_UNSIGNED_BYTE$3;
+ break
+
+ case GL_UNSIGNED_SHORT$2:
+ case GL_SHORT$2:
+ dtype = GL_UNSIGNED_SHORT$2;
+ break
+
+ case GL_UNSIGNED_INT$2:
+ case GL_INT$2:
+ dtype = GL_UNSIGNED_INT$2;
+ break
+
+ default:
+ check$1.raise('unsupported type for element array');
+ }
+ elements.buffer.dtype = dtype;
+ }
+ elements.type = dtype;
+
+ // Check oes_element_index_uint extension
+ check$1(
+ dtype !== GL_UNSIGNED_INT$2 ||
+ !!extensions.oes_element_index_uint,
+ '32 bit element buffers not supported, enable oes_element_index_uint first');
+
+ // try to guess default primitive type and arguments
+ var vertCount = count;
+ if (vertCount < 0) {
+ vertCount = elements.buffer.byteLength;
+ if (dtype === GL_UNSIGNED_SHORT$2) {
+ vertCount >>= 1;
+ } else if (dtype === GL_UNSIGNED_INT$2) {
+ vertCount >>= 2;
+ }
+ }
+ elements.vertCount = vertCount;
+
+ // try to guess primitive type from cell dimension
+ var primType = prim;
+ if (prim < 0) {
+ primType = GL_TRIANGLES;
+ var dimension = elements.buffer.dimension;
+ if (dimension === 1) primType = GL_POINTS;
+ if (dimension === 2) primType = GL_LINES;
+ if (dimension === 3) primType = GL_TRIANGLES;
+ }
+ elements.primType = primType;
+ }
+
+ function destroyElements (elements) {
+ stats.elementsCount--;
+
+ check$1(elements.buffer !== null, 'must not double destroy elements');
+ delete elementSet[elements.id];
+ elements.buffer.destroy();
+ elements.buffer = null;
+ }
+
+ function createElements (options, persistent) {
+ var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true);
+ var elements = new REGLElementBuffer(buffer._buffer);
+ stats.elementsCount++;
+
+ function reglElements (options) {
+ if (!options) {
+ buffer();
+ elements.primType = GL_TRIANGLES;
+ elements.vertCount = 0;
+ elements.type = GL_UNSIGNED_BYTE$3;
+ } else if (typeof options === 'number') {
+ buffer(options);
+ elements.primType = GL_TRIANGLES;
+ elements.vertCount = options | 0;
+ elements.type = GL_UNSIGNED_BYTE$3;
+ } else {
+ var data = null;
+ var usage = GL_STATIC_DRAW$1;
+ var primType = -1;
+ var vertCount = -1;
+ var byteLength = 0;
+ var dtype = 0;
+ if (Array.isArray(options) ||
+ isTypedArray(options) ||
+ isNDArrayLike(options)) {
+ data = options;
+ } else {
+ check$1.type(options, 'object', 'invalid arguments for elements');
+ if ('data' in options) {
+ data = options.data;
+ check$1(
+ Array.isArray(data) ||
+ isTypedArray(data) ||
+ isNDArrayLike(data),
+ 'invalid data for element buffer');
+ }
+ if ('usage' in options) {
+ check$1.parameter(
+ options.usage,
+ usageTypes,
+ 'invalid element buffer usage');
+ usage = usageTypes[options.usage];
+ }
+ if ('primitive' in options) {
+ check$1.parameter(
+ options.primitive,
+ primTypes,
+ 'invalid element buffer primitive');
+ primType = primTypes[options.primitive];
+ }
+ if ('count' in options) {
+ check$1(
+ typeof options.count === 'number' && options.count >= 0,
+ 'invalid vertex count for elements');
+ vertCount = options.count | 0;
+ }
+ if ('type' in options) {
+ check$1.parameter(
+ options.type,
+ elementTypes,
+ 'invalid buffer type');
+ dtype = elementTypes[options.type];
+ }
+ if ('length' in options) {
+ byteLength = options.length | 0;
+ } else {
+ byteLength = vertCount;
+ if (dtype === GL_UNSIGNED_SHORT$2 || dtype === GL_SHORT$2) {
+ byteLength *= 2;
+ } else if (dtype === GL_UNSIGNED_INT$2 || dtype === GL_INT$2) {
+ byteLength *= 4;
+ }
+ }
+ }
+ initElements(
+ elements,
+ data,
+ usage,
+ primType,
+ vertCount,
+ byteLength,
+ dtype);
+ }
+
+ return reglElements
+ }
+
+ reglElements(options);
+
+ reglElements._reglType = 'elements';
+ reglElements._elements = elements;
+ reglElements.subdata = function (data, offset) {
+ buffer.subdata(data, offset);
+ return reglElements
+ };
+ reglElements.destroy = function () {
+ destroyElements(elements);
+ };
+
+ return reglElements
+ }
+
+ return {
+ create: createElements,
+ createStream: createElementStream,
+ destroyStream: destroyElementStream,
+ getElements: function (elements) {
+ if (typeof elements === 'function' &&
+ elements._elements instanceof REGLElementBuffer) {
+ return elements._elements
+ }
+ return null
+ },
+ clear: function () {
+ values(elementSet).forEach(destroyElements);
+ }
+ }
+}
+
+var FLOAT = new Float32Array(1);
+var INT = new Uint32Array(FLOAT.buffer);
+
+var GL_UNSIGNED_SHORT$4 = 5123;
+
+function convertToHalfFloat (array) {
+ var ushorts = pool.allocType(GL_UNSIGNED_SHORT$4, array.length);
+
+ for (var i = 0; i < array.length; ++i) {
+ if (isNaN(array[i])) {
+ ushorts[i] = 0xffff;
+ } else if (array[i] === Infinity) {
+ ushorts[i] = 0x7c00;
+ } else if (array[i] === -Infinity) {
+ ushorts[i] = 0xfc00;
+ } else {
+ FLOAT[0] = array[i];
+ var x = INT[0];
+
+ var sgn = (x >>> 31) << 15;
+ var exp = ((x << 1) >>> 24) - 127;
+ var frac = (x >> 13) & ((1 << 10) - 1);
+
+ if (exp < -24) {
+ // round non-representable denormals to 0
+ ushorts[i] = sgn;
+ } else if (exp < -14) {
+ // handle denormals
+ var s = -14 - exp;
+ ushorts[i] = sgn + ((frac + (1 << 10)) >> s);
+ } else if (exp > 15) {
+ // round overflow to +/- Infinity
+ ushorts[i] = sgn + 0x7c00;
+ } else {
+ // otherwise convert directly
+ ushorts[i] = sgn + ((exp + 15) << 10) + frac;
+ }
+ }
+ }
+
+ return ushorts
+}
+
+function isArrayLike (s) {
+ return Array.isArray(s) || isTypedArray(s)
+}
+
+var GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3;
+
+var GL_TEXTURE_2D = 0x0DE1;
+var GL_TEXTURE_CUBE_MAP = 0x8513;
+var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
+
+var GL_RGBA = 0x1908;
+var GL_ALPHA = 0x1906;
+var GL_RGB = 0x1907;
+var GL_LUMINANCE = 0x1909;
+var GL_LUMINANCE_ALPHA = 0x190A;
+
+var GL_RGBA4 = 0x8056;
+var GL_RGB5_A1 = 0x8057;
+var GL_RGB565 = 0x8D62;
+
+var GL_UNSIGNED_SHORT_4_4_4_4$1 = 0x8033;
+var GL_UNSIGNED_SHORT_5_5_5_1$1 = 0x8034;
+var GL_UNSIGNED_SHORT_5_6_5$1 = 0x8363;
+var GL_UNSIGNED_INT_24_8_WEBGL$1 = 0x84FA;
+
+var GL_DEPTH_COMPONENT = 0x1902;
+var GL_DEPTH_STENCIL = 0x84F9;
+
+var GL_SRGB_EXT = 0x8C40;
+var GL_SRGB_ALPHA_EXT = 0x8C42;
+
+var GL_HALF_FLOAT_OES$1 = 0x8D61;
+
+var GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
+var GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
+var GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
+var GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
+
+var GL_COMPRESSED_RGB_ATC_WEBGL = 0x8C92;
+var GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL = 0x8C93;
+var GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
+
+var GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+var GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
+var GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+var GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
+
+var GL_COMPRESSED_RGB_ETC1_WEBGL = 0x8D64;
+
+var GL_UNSIGNED_BYTE$4 = 0x1401;
+var GL_UNSIGNED_SHORT$3 = 0x1403;
+var GL_UNSIGNED_INT$3 = 0x1405;
+var GL_FLOAT$3 = 0x1406;
+
+var GL_TEXTURE_WRAP_S = 0x2802;
+var GL_TEXTURE_WRAP_T = 0x2803;
+
+var GL_REPEAT = 0x2901;
+var GL_CLAMP_TO_EDGE$1 = 0x812F;
+var GL_MIRRORED_REPEAT = 0x8370;
+
+var GL_TEXTURE_MAG_FILTER = 0x2800;
+var GL_TEXTURE_MIN_FILTER = 0x2801;
+
+var GL_NEAREST$1 = 0x2600;
+var GL_LINEAR = 0x2601;
+var GL_NEAREST_MIPMAP_NEAREST$1 = 0x2700;
+var GL_LINEAR_MIPMAP_NEAREST$1 = 0x2701;
+var GL_NEAREST_MIPMAP_LINEAR$1 = 0x2702;
+var GL_LINEAR_MIPMAP_LINEAR$1 = 0x2703;
+
+var GL_GENERATE_MIPMAP_HINT = 0x8192;
+var GL_DONT_CARE = 0x1100;
+var GL_FASTEST = 0x1101;
+var GL_NICEST = 0x1102;
+
+var GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
+
+var GL_UNPACK_ALIGNMENT = 0x0CF5;
+var GL_UNPACK_FLIP_Y_WEBGL = 0x9240;
+var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241;
+var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243;
+
+var GL_BROWSER_DEFAULT_WEBGL = 0x9244;
+
+var GL_TEXTURE0 = 0x84C0;
+
+var MIPMAP_FILTERS = [
+ GL_NEAREST_MIPMAP_NEAREST$1,
+ GL_NEAREST_MIPMAP_LINEAR$1,
+ GL_LINEAR_MIPMAP_NEAREST$1,
+ GL_LINEAR_MIPMAP_LINEAR$1
+];
+
+var CHANNELS_FORMAT = [
+ 0,
+ GL_LUMINANCE,
+ GL_LUMINANCE_ALPHA,
+ GL_RGB,
+ GL_RGBA
+];
+
+var FORMAT_CHANNELS = {};
+FORMAT_CHANNELS[GL_LUMINANCE] =
+FORMAT_CHANNELS[GL_ALPHA] =
+FORMAT_CHANNELS[GL_DEPTH_COMPONENT] = 1;
+FORMAT_CHANNELS[GL_DEPTH_STENCIL] =
+FORMAT_CHANNELS[GL_LUMINANCE_ALPHA] = 2;
+FORMAT_CHANNELS[GL_RGB] =
+FORMAT_CHANNELS[GL_SRGB_EXT] = 3;
+FORMAT_CHANNELS[GL_RGBA] =
+FORMAT_CHANNELS[GL_SRGB_ALPHA_EXT] = 4;
+
+function objectName (str) {
+ return '[object ' + str + ']'
+}
+
+var CANVAS_CLASS = objectName('HTMLCanvasElement');
+var CONTEXT2D_CLASS = objectName('CanvasRenderingContext2D');
+var IMAGE_CLASS = objectName('HTMLImageElement');
+var VIDEO_CLASS = objectName('HTMLVideoElement');
+
+var PIXEL_CLASSES = Object.keys(arrayTypes).concat([
+ CANVAS_CLASS,
+ CONTEXT2D_CLASS,
+ IMAGE_CLASS,
+ VIDEO_CLASS
+]);
+
+// for every texture type, store
+// the size in bytes.
+var TYPE_SIZES = [];
+TYPE_SIZES[GL_UNSIGNED_BYTE$4] = 1;
+TYPE_SIZES[GL_FLOAT$3] = 4;
+TYPE_SIZES[GL_HALF_FLOAT_OES$1] = 2;
+
+TYPE_SIZES[GL_UNSIGNED_SHORT$3] = 2;
+TYPE_SIZES[GL_UNSIGNED_INT$3] = 4;
+
+var FORMAT_SIZES_SPECIAL = [];
+FORMAT_SIZES_SPECIAL[GL_RGBA4] = 2;
+FORMAT_SIZES_SPECIAL[GL_RGB5_A1] = 2;
+FORMAT_SIZES_SPECIAL[GL_RGB565] = 2;
+FORMAT_SIZES_SPECIAL[GL_DEPTH_STENCIL] = 4;
+
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_S3TC_DXT1_EXT] = 0.5;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT1_EXT] = 0.5;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT3_EXT] = 1;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_S3TC_DXT5_EXT] = 1;
+
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ATC_WEBGL] = 0.5;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL] = 1;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL] = 1;
+
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG] = 0.5;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG] = 0.25;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG] = 0.5;
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG] = 0.25;
+
+FORMAT_SIZES_SPECIAL[GL_COMPRESSED_RGB_ETC1_WEBGL] = 0.5;
+
+function isNumericArray (arr) {
+ return (
+ Array.isArray(arr) &&
+ (arr.length === 0 ||
+ typeof arr[0] === 'number'))
+}
+
+function isRectArray (arr) {
+ if (!Array.isArray(arr)) {
+ return false
+ }
+ var width = arr.length;
+ if (width === 0 || !isArrayLike(arr[0])) {
+ return false
+ }
+ return true
+}
+
+function classString (x) {
+ return Object.prototype.toString.call(x)
+}
+
+function isCanvasElement (object) {
+ return classString(object) === CANVAS_CLASS
+}
+
+function isContext2D (object) {
+ return classString(object) === CONTEXT2D_CLASS
+}
+
+function isImageElement (object) {
+ return classString(object) === IMAGE_CLASS
+}
+
+function isVideoElement (object) {
+ return classString(object) === VIDEO_CLASS
+}
+
+function isPixelData (object) {
+ if (!object) {
+ return false
+ }
+ var className = classString(object);
+ if (PIXEL_CLASSES.indexOf(className) >= 0) {
+ return true
+ }
+ return (
+ isNumericArray(object) ||
+ isRectArray(object) ||
+ isNDArrayLike(object))
+}
+
+function typedArrayCode$1 (data) {
+ return arrayTypes[Object.prototype.toString.call(data)] | 0
+}
+
+function convertData (result, data) {
+ var n = data.length;
+ switch (result.type) {
+ case GL_UNSIGNED_BYTE$4:
+ case GL_UNSIGNED_SHORT$3:
+ case GL_UNSIGNED_INT$3:
+ case GL_FLOAT$3:
+ var converted = pool.allocType(result.type, n);
+ converted.set(data);
+ result.data = converted;
+ break
+
+ case GL_HALF_FLOAT_OES$1:
+ result.data = convertToHalfFloat(data);
+ break
+
+ default:
+ check$1.raise('unsupported texture type, must specify a typed array');
+ }
+}
+
+function preConvert (image, n) {
+ return pool.allocType(
+ image.type === GL_HALF_FLOAT_OES$1
+ ? GL_FLOAT$3
+ : image.type, n)
+}
+
+function postConvert (image, data) {
+ if (image.type === GL_HALF_FLOAT_OES$1) {
+ image.data = convertToHalfFloat(data);
+ pool.freeType(data);
+ } else {
+ image.data = data;
+ }
+}
+
+function transposeData (image, array, strideX, strideY, strideC, offset) {
+ var w = image.width;
+ var h = image.height;
+ var c = image.channels;
+ var n = w * h * c;
+ var data = preConvert(image, n);
+
+ var p = 0;
+ for (var i = 0; i < h; ++i) {
+ for (var j = 0; j < w; ++j) {
+ for (var k = 0; k < c; ++k) {
+ data[p++] = array[strideX * j + strideY * i + strideC * k + offset];
+ }
+ }
+ }
+
+ postConvert(image, data);
+}
+
+function getTextureSize (format, type, width, height, isMipmap, isCube) {
+ var s;
+ if (typeof FORMAT_SIZES_SPECIAL[format] !== 'undefined') {
+ // we have a special array for dealing with weird color formats such as RGB5A1
+ s = FORMAT_SIZES_SPECIAL[format];
+ } else {
+ s = FORMAT_CHANNELS[format] * TYPE_SIZES[type];
+ }
+
+ if (isCube) {
+ s *= 6;
+ }
+
+ if (isMipmap) {
+ // compute the total size of all the mipmaps.
+ var total = 0;
+
+ var w = width;
+ while (w >= 1) {
+ // we can only use mipmaps on a square image,
+ // so we can simply use the width and ignore the height:
+ total += s * w * w;
+ w /= 2;
+ }
+ return total
+ } else {
+ return s * width * height
+ }
+}
+
+function createTextureSet (
+ gl, extensions, limits, reglPoll, contextState, stats, config) {
+ // -------------------------------------------------------
+ // Initialize constants and parameter tables here
+ // -------------------------------------------------------
+ var mipmapHint = {
+ "don't care": GL_DONT_CARE,
+ 'dont care': GL_DONT_CARE,
+ 'nice': GL_NICEST,
+ 'fast': GL_FASTEST
+ };
+
+ var wrapModes = {
+ 'repeat': GL_REPEAT,
+ 'clamp': GL_CLAMP_TO_EDGE$1,
+ 'mirror': GL_MIRRORED_REPEAT
+ };
+
+ var magFilters = {
+ 'nearest': GL_NEAREST$1,
+ 'linear': GL_LINEAR
+ };
+
+ var minFilters = extend({
+ 'mipmap': GL_LINEAR_MIPMAP_LINEAR$1,
+ 'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST$1,
+ 'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST$1,
+ 'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR$1,
+ 'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR$1
+ }, magFilters);
+
+ var colorSpace = {
+ 'none': 0,
+ 'browser': GL_BROWSER_DEFAULT_WEBGL
+ };
+
+ var textureTypes = {
+ 'uint8': GL_UNSIGNED_BYTE$4,
+ 'rgba4': GL_UNSIGNED_SHORT_4_4_4_4$1,
+ 'rgb565': GL_UNSIGNED_SHORT_5_6_5$1,
+ 'rgb5 a1': GL_UNSIGNED_SHORT_5_5_5_1$1
+ };
+
+ var textureFormats = {
+ 'alpha': GL_ALPHA,
+ 'luminance': GL_LUMINANCE,
+ 'luminance alpha': GL_LUMINANCE_ALPHA,
+ 'rgb': GL_RGB,
+ 'rgba': GL_RGBA,
+ 'rgba4': GL_RGBA4,
+ 'rgb5 a1': GL_RGB5_A1,
+ 'rgb565': GL_RGB565
+ };
+
+ var compressedTextureFormats = {};
+
+ if (extensions.ext_srgb) {
+ textureFormats.srgb = GL_SRGB_EXT;
+ textureFormats.srgba = GL_SRGB_ALPHA_EXT;
+ }
+
+ if (extensions.oes_texture_float) {
+ textureTypes.float32 = textureTypes.float = GL_FLOAT$3;
+ }
+
+ if (extensions.oes_texture_half_float) {
+ textureTypes['float16'] = textureTypes['half float'] = GL_HALF_FLOAT_OES$1;
+ }
+
+ if (extensions.webgl_depth_texture) {
+ extend(textureFormats, {
+ 'depth': GL_DEPTH_COMPONENT,
+ 'depth stencil': GL_DEPTH_STENCIL
+ });
+
+ extend(textureTypes, {
+ 'uint16': GL_UNSIGNED_SHORT$3,
+ 'uint32': GL_UNSIGNED_INT$3,
+ 'depth stencil': GL_UNSIGNED_INT_24_8_WEBGL$1
+ });
+ }
+
+ if (extensions.webgl_compressed_texture_s3tc) {
+ extend(compressedTextureFormats, {
+ 'rgb s3tc dxt1': GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+ 'rgba s3tc dxt1': GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ 'rgba s3tc dxt3': GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
+ 'rgba s3tc dxt5': GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+ });
+ }
+
+ if (extensions.webgl_compressed_texture_atc) {
+ extend(compressedTextureFormats, {
+ 'rgb atc': GL_COMPRESSED_RGB_ATC_WEBGL,
+ 'rgba atc explicit alpha': GL_COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL,
+ 'rgba atc interpolated alpha': GL_COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL
+ });
+ }
+
+ if (extensions.webgl_compressed_texture_pvrtc) {
+ extend(compressedTextureFormats, {
+ 'rgb pvrtc 4bppv1': GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
+ 'rgb pvrtc 2bppv1': GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG,
+ 'rgba pvrtc 4bppv1': GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG,
+ 'rgba pvrtc 2bppv1': GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+ });
+ }
+
+ if (extensions.webgl_compressed_texture_etc1) {
+ compressedTextureFormats['rgb etc1'] = GL_COMPRESSED_RGB_ETC1_WEBGL;
+ }
+
+ // Copy over all texture formats
+ var supportedCompressedFormats = Array.prototype.slice.call(
+ gl.getParameter(GL_COMPRESSED_TEXTURE_FORMATS));
+ Object.keys(compressedTextureFormats).forEach(function (name) {
+ var format = compressedTextureFormats[name];
+ if (supportedCompressedFormats.indexOf(format) >= 0) {
+ textureFormats[name] = format;
+ }
+ });
+
+ var supportedFormats = Object.keys(textureFormats);
+ limits.textureFormats = supportedFormats;
+
+ // associate with every format string its
+ // corresponding GL-value.
+ var textureFormatsInvert = [];
+ Object.keys(textureFormats).forEach(function (key) {
+ var val = textureFormats[key];
+ textureFormatsInvert[val] = key;
+ });
+
+ // associate with every type string its
+ // corresponding GL-value.
+ var textureTypesInvert = [];
+ Object.keys(textureTypes).forEach(function (key) {
+ var val = textureTypes[key];
+ textureTypesInvert[val] = key;
+ });
+
+ var magFiltersInvert = [];
+ Object.keys(magFilters).forEach(function (key) {
+ var val = magFilters[key];
+ magFiltersInvert[val] = key;
+ });
+
+ var minFiltersInvert = [];
+ Object.keys(minFilters).forEach(function (key) {
+ var val = minFilters[key];
+ minFiltersInvert[val] = key;
+ });
+
+ var wrapModesInvert = [];
+ Object.keys(wrapModes).forEach(function (key) {
+ var val = wrapModes[key];
+ wrapModesInvert[val] = key;
+ });
+
+ // colorFormats[] gives the format (channels) associated to an
+ // internalformat
+ var colorFormats = supportedFormats.reduce(function (color, key) {
+ var glenum = textureFormats[key];
+ if (glenum === GL_LUMINANCE ||
+ glenum === GL_ALPHA ||
+ glenum === GL_LUMINANCE ||
+ glenum === GL_LUMINANCE_ALPHA ||
+ glenum === GL_DEPTH_COMPONENT ||
+ glenum === GL_DEPTH_STENCIL) {
+ color[glenum] = glenum;
+ } else if (glenum === GL_RGB5_A1 || key.indexOf('rgba') >= 0) {
+ color[glenum] = GL_RGBA;
+ } else {
+ color[glenum] = GL_RGB;
+ }
+ return color
+ }, {});
+
+ function TexFlags () {
+ // format info
+ this.internalformat = GL_RGBA;
+ this.format = GL_RGBA;
+ this.type = GL_UNSIGNED_BYTE$4;
+ this.compressed = false;
+
+ // pixel storage
+ this.premultiplyAlpha = false;
+ this.flipY = false;
+ this.unpackAlignment = 1;
+ this.colorSpace = 0;
+
+ // shape info
+ this.width = 0;
+ this.height = 0;
+ this.channels = 0;
+ }
+
+ function copyFlags (result, other) {
+ result.internalformat = other.internalformat;
+ result.format = other.format;
+ result.type = other.type;
+ result.compressed = other.compressed;
+
+ result.premultiplyAlpha = other.premultiplyAlpha;
+ result.flipY = other.flipY;
+ result.unpackAlignment = other.unpackAlignment;
+ result.colorSpace = other.colorSpace;
+
+ result.width = other.width;
+ result.height = other.height;
+ result.channels = other.channels;
+ }
+
+ function parseFlags (flags, options) {
+ if (typeof options !== 'object' || !options) {
+ return
+ }
+
+ if ('premultiplyAlpha' in options) {
+ check$1.type(options.premultiplyAlpha, 'boolean',
+ 'invalid premultiplyAlpha');
+ flags.premultiplyAlpha = options.premultiplyAlpha;
+ }
+
+ if ('flipY' in options) {
+ check$1.type(options.flipY, 'boolean',
+ 'invalid texture flip');
+ flags.flipY = options.flipY;
+ }
+
+ if ('alignment' in options) {
+ check$1.oneOf(options.alignment, [1, 2, 4, 8],
+ 'invalid texture unpack alignment');
+ flags.unpackAlignment = options.alignment;
+ }
+
+ if ('colorSpace' in options) {
+ check$1.parameter(options.colorSpace, colorSpace,
+ 'invalid colorSpace');
+ flags.colorSpace = colorSpace[options.colorSpace];
+ }
+
+ if ('type' in options) {
+ var type = options.type;
+ check$1(extensions.oes_texture_float ||
+ !(type === 'float' || type === 'float32'),
+ 'you must enable the OES_texture_float extension in order to use floating point textures.');
+ check$1(extensions.oes_texture_half_float ||
+ !(type === 'half float' || type === 'float16'),
+ 'you must enable the OES_texture_half_float extension in order to use 16-bit floating point textures.');
+ check$1(extensions.webgl_depth_texture ||
+ !(type === 'uint16' || type === 'uint32' || type === 'depth stencil'),
+ 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.');
+ check$1.parameter(type, textureTypes,
+ 'invalid texture type');
+ flags.type = textureTypes[type];
+ }
+
+ var w = flags.width;
+ var h = flags.height;
+ var c = flags.channels;
+ var hasChannels = false;
+ if ('shape' in options) {
+ check$1(Array.isArray(options.shape) && options.shape.length >= 2,
+ 'shape must be an array');
+ w = options.shape[0];
+ h = options.shape[1];
+ if (options.shape.length === 3) {
+ c = options.shape[2];
+ check$1(c > 0 && c <= 4, 'invalid number of channels');
+ hasChannels = true;
+ }
+ check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width');
+ check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height');
+ } else {
+ if ('radius' in options) {
+ w = h = options.radius;
+ check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid radius');
+ }
+ if ('width' in options) {
+ w = options.width;
+ check$1(w >= 0 && w <= limits.maxTextureSize, 'invalid width');
+ }
+ if ('height' in options) {
+ h = options.height;
+ check$1(h >= 0 && h <= limits.maxTextureSize, 'invalid height');
+ }
+ if ('channels' in options) {
+ c = options.channels;
+ check$1(c > 0 && c <= 4, 'invalid number of channels');
+ hasChannels = true;
+ }
+ }
+ flags.width = w | 0;
+ flags.height = h | 0;
+ flags.channels = c | 0;
+
+ var hasFormat = false;
+ if ('format' in options) {
+ var formatStr = options.format;
+ check$1(extensions.webgl_depth_texture ||
+ !(formatStr === 'depth' || formatStr === 'depth stencil'),
+ 'you must enable the WEBGL_depth_texture extension in order to use depth/stencil textures.');
+ check$1.parameter(formatStr, textureFormats,
+ 'invalid texture format');
+ var internalformat = flags.internalformat = textureFormats[formatStr];
+ flags.format = colorFormats[internalformat];
+ if (formatStr in textureTypes) {
+ if (!('type' in options)) {
+ flags.type = textureTypes[formatStr];
+ }
+ }
+ if (formatStr in compressedTextureFormats) {
+ flags.compressed = true;
+ }
+ hasFormat = true;
+ }
+
+ // Reconcile channels and format
+ if (!hasChannels && hasFormat) {
+ flags.channels = FORMAT_CHANNELS[flags.format];
+ } else if (hasChannels && !hasFormat) {
+ if (flags.channels !== CHANNELS_FORMAT[flags.format]) {
+ flags.format = flags.internalformat = CHANNELS_FORMAT[flags.channels];
+ }
+ } else if (hasFormat && hasChannels) {
+ check$1(
+ flags.channels === FORMAT_CHANNELS[flags.format],
+ 'number of channels inconsistent with specified format');
+ }
+ }
+
+ function setFlags (flags) {
+ gl.pixelStorei(GL_UNPACK_FLIP_Y_WEBGL, flags.flipY);
+ gl.pixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL, flags.premultiplyAlpha);
+ gl.pixelStorei(GL_UNPACK_COLORSPACE_CONVERSION_WEBGL, flags.colorSpace);
+ gl.pixelStorei(GL_UNPACK_ALIGNMENT, flags.unpackAlignment);
+ }
+
+ // -------------------------------------------------------
+ // Tex image data
+ // -------------------------------------------------------
+ function TexImage () {
+ TexFlags.call(this);
+
+ this.xOffset = 0;
+ this.yOffset = 0;
+
+ // data
+ this.data = null;
+ this.needsFree = false;
+
+ // html element
+ this.element = null;
+
+ // copyTexImage info
+ this.needsCopy = false;
+ }
+
+ function parseImage (image, options) {
+ var data = null;
+ if (isPixelData(options)) {
+ data = options;
+ } else if (options) {
+ check$1.type(options, 'object', 'invalid pixel data type');
+ parseFlags(image, options);
+ if ('x' in options) {
+ image.xOffset = options.x | 0;
+ }
+ if ('y' in options) {
+ image.yOffset = options.y | 0;
+ }
+ if (isPixelData(options.data)) {
+ data = options.data;
+ }
+ }
+
+ check$1(
+ !image.compressed ||
+ data instanceof Uint8Array,
+ 'compressed texture data must be stored in a uint8array');
+
+ if (options.copy) {
+ check$1(!data, 'can not specify copy and data field for the same texture');
+ var viewW = contextState.viewportWidth;
+ var viewH = contextState.viewportHeight;
+ image.width = image.width || (viewW - image.xOffset);
+ image.height = image.height || (viewH - image.yOffset);
+ image.needsCopy = true;
+ check$1(image.xOffset >= 0 && image.xOffset < viewW &&
+ image.yOffset >= 0 && image.yOffset < viewH &&
+ image.width > 0 && image.width <= viewW &&
+ image.height > 0 && image.height <= viewH,
+ 'copy texture read out of bounds');
+ } else if (!data) {
+ image.width = image.width || 1;
+ image.height = image.height || 1;
+ image.channels = image.channels || 4;
+ } else if (isTypedArray(data)) {
+ image.channels = image.channels || 4;
+ image.data = data;
+ if (!('type' in options) && image.type === GL_UNSIGNED_BYTE$4) {
+ image.type = typedArrayCode$1(data);
+ }
+ } else if (isNumericArray(data)) {
+ image.channels = image.channels || 4;
+ convertData(image, data);
+ image.alignment = 1;
+ image.needsFree = true;
+ } else if (isNDArrayLike(data)) {
+ var array = data.data;
+ if (!Array.isArray(array) && image.type === GL_UNSIGNED_BYTE$4) {
+ image.type = typedArrayCode$1(array);
+ }
+ var shape = data.shape;
+ var stride = data.stride;
+ var shapeX, shapeY, shapeC, strideX, strideY, strideC;
+ if (shape.length === 3) {
+ shapeC = shape[2];
+ strideC = stride[2];
+ } else {
+ check$1(shape.length === 2, 'invalid ndarray pixel data, must be 2 or 3D');
+ shapeC = 1;
+ strideC = 1;
+ }
+ shapeX = shape[0];
+ shapeY = shape[1];
+ strideX = stride[0];
+ strideY = stride[1];
+ image.alignment = 1;
+ image.width = shapeX;
+ image.height = shapeY;
+ image.channels = shapeC;
+ image.format = image.internalformat = CHANNELS_FORMAT[shapeC];
+ image.needsFree = true;
+ transposeData(image, array, strideX, strideY, strideC, data.offset);
+ } else if (isCanvasElement(data) || isContext2D(data)) {
+ if (isCanvasElement(data)) {
+ image.element = data;
+ } else {
+ image.element = data.canvas;
+ }
+ image.width = image.element.width;
+ image.height = image.element.height;
+ image.channels = 4;
+ } else if (isImageElement(data)) {
+ image.element = data;
+ image.width = data.naturalWidth;
+ image.height = data.naturalHeight;
+ image.channels = 4;
+ } else if (isVideoElement(data)) {
+ image.element = data;
+ image.width = data.videoWidth;
+ image.height = data.videoHeight;
+ image.channels = 4;
+ } else if (isRectArray(data)) {
+ var w = image.width || data[0].length;
+ var h = image.height || data.length;
+ var c = image.channels;
+ if (isArrayLike(data[0][0])) {
+ c = c || data[0][0].length;
+ } else {
+ c = c || 1;
+ }
+ var arrayShape = flattenUtils.shape(data);
+ var n = 1;
+ for (var dd = 0; dd < arrayShape.length; ++dd) {
+ n *= arrayShape[dd];
+ }
+ var allocData = preConvert(image, n);
+ flattenUtils.flatten(data, arrayShape, '', allocData);
+ postConvert(image, allocData);
+ image.alignment = 1;
+ image.width = w;
+ image.height = h;
+ image.channels = c;
+ image.format = image.internalformat = CHANNELS_FORMAT[c];
+ image.needsFree = true;
+ }
+
+ if (image.type === GL_FLOAT$3) {
+ check$1(limits.extensions.indexOf('oes_texture_float') >= 0,
+ 'oes_texture_float extension not enabled');
+ } else if (image.type === GL_HALF_FLOAT_OES$1) {
+ check$1(limits.extensions.indexOf('oes_texture_half_float') >= 0,
+ 'oes_texture_half_float extension not enabled');
+ }
+
+ // do compressed texture validation here.
+ }
+
+ function setImage (info, target, miplevel) {
+ var element = info.element;
+ var data = info.data;
+ var internalformat = info.internalformat;
+ var format = info.format;
+ var type = info.type;
+ var width = info.width;
+ var height = info.height;
+
+ setFlags(info);
+
+ if (element) {
+ gl.texImage2D(target, miplevel, format, format, type, element);
+ } else if (info.compressed) {
+ gl.compressedTexImage2D(target, miplevel, internalformat, width, height, 0, data);
+ } else if (info.needsCopy) {
+ reglPoll();
+ gl.copyTexImage2D(
+ target, miplevel, format, info.xOffset, info.yOffset, width, height, 0);
+ } else {
+ gl.texImage2D(
+ target, miplevel, format, width, height, 0, format, type, data);
+ }
+ }
+
+ function setSubImage (info, target, x, y, miplevel) {
+ var element = info.element;
+ var data = info.data;
+ var internalformat = info.internalformat;
+ var format = info.format;
+ var type = info.type;
+ var width = info.width;
+ var height = info.height;
+
+ setFlags(info);
+
+ if (element) {
+ gl.texSubImage2D(
+ target, miplevel, x, y, format, type, element);
+ } else if (info.compressed) {
+ gl.compressedTexSubImage2D(
+ target, miplevel, x, y, internalformat, width, height, data);
+ } else if (info.needsCopy) {
+ reglPoll();
+ gl.copyTexSubImage2D(
+ target, miplevel, x, y, info.xOffset, info.yOffset, width, height);
+ } else {
+ gl.texSubImage2D(
+ target, miplevel, x, y, width, height, format, type, data);
+ }
+ }
+
+ // texImage pool
+ var imagePool = [];
+
+ function allocImage () {
+ return imagePool.pop() || new TexImage()
+ }
+
+ function freeImage (image) {
+ if (image.needsFree) {
+ pool.freeType(image.data);
+ }
+ TexImage.call(image);
+ imagePool.push(image);
+ }
+
+ // -------------------------------------------------------
+ // Mip map
+ // -------------------------------------------------------
+ function MipMap () {
+ TexFlags.call(this);
+
+ this.genMipmaps = false;
+ this.mipmapHint = GL_DONT_CARE;
+ this.mipmask = 0;
+ this.images = Array(16);
+ }
+
+ function parseMipMapFromShape (mipmap, width, height) {
+ var img = mipmap.images[0] = allocImage();
+ mipmap.mipmask = 1;
+ img.width = mipmap.width = width;
+ img.height = mipmap.height = height;
+ img.channels = mipmap.channels = 4;
+ }
+
+ function parseMipMapFromObject (mipmap, options) {
+ var imgData = null;
+ if (isPixelData(options)) {
+ imgData = mipmap.images[0] = allocImage();
+ copyFlags(imgData, mipmap);
+ parseImage(imgData, options);
+ mipmap.mipmask = 1;
+ } else {
+ parseFlags(mipmap, options);
+ if (Array.isArray(options.mipmap)) {
+ var mipData = options.mipmap;
+ for (var i = 0; i < mipData.length; ++i) {
+ imgData = mipmap.images[i] = allocImage();
+ copyFlags(imgData, mipmap);
+ imgData.width >>= i;
+ imgData.height >>= i;
+ parseImage(imgData, mipData[i]);
+ mipmap.mipmask |= (1 << i);
+ }
+ } else {
+ imgData = mipmap.images[0] = allocImage();
+ copyFlags(imgData, mipmap);
+ parseImage(imgData, options);
+ mipmap.mipmask = 1;
+ }
+ }
+ copyFlags(mipmap, mipmap.images[0]);
+
+ // For textures of the compressed format WEBGL_compressed_texture_s3tc
+ // we must have that
+ //
+ // "When level equals zero width and height must be a multiple of 4.
+ // When level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4. "
+ //
+ // but we do not yet support having multiple mipmap levels for compressed textures,
+ // so we only test for level zero.
+
+ if (mipmap.compressed &&
+ (mipmap.internalformat === GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ||
+ (mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
+ (mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) ||
+ (mipmap.internalformat === GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)) {
+ check$1(mipmap.width % 4 === 0 &&
+ mipmap.height % 4 === 0,
+ 'for compressed texture formats, mipmap level 0 must have width and height that are a multiple of 4');
+ }
+ }
+
+ function setMipMap (mipmap, target) {
+ var images = mipmap.images;
+ for (var i = 0; i < images.length; ++i) {
+ if (!images[i]) {
+ return
+ }
+ setImage(images[i], target, i);
+ }
+ }
+
+ var mipPool = [];
+
+ function allocMipMap () {
+ var result = mipPool.pop() || new MipMap();
+ TexFlags.call(result);
+ result.mipmask = 0;
+ for (var i = 0; i < 16; ++i) {
+ result.images[i] = null;
+ }
+ return result
+ }
+
+ function freeMipMap (mipmap) {
+ var images = mipmap.images;
+ for (var i = 0; i < images.length; ++i) {
+ if (images[i]) {
+ freeImage(images[i]);
+ }
+ images[i] = null;
+ }
+ mipPool.push(mipmap);
+ }
+
+ // -------------------------------------------------------
+ // Tex info
+ // -------------------------------------------------------
+ function TexInfo () {
+ this.minFilter = GL_NEAREST$1;
+ this.magFilter = GL_NEAREST$1;
+
+ this.wrapS = GL_CLAMP_TO_EDGE$1;
+ this.wrapT = GL_CLAMP_TO_EDGE$1;
+
+ this.anisotropic = 1;
+
+ this.genMipmaps = false;
+ this.mipmapHint = GL_DONT_CARE;
+ }
+
+ function parseTexInfo (info, options) {
+ if ('min' in options) {
+ var minFilter = options.min;
+ check$1.parameter(minFilter, minFilters);
+ info.minFilter = minFilters[minFilter];
+ if (MIPMAP_FILTERS.indexOf(info.minFilter) >= 0) {
+ info.genMipmaps = true;
+ }
+ }
+
+ if ('mag' in options) {
+ var magFilter = options.mag;
+ check$1.parameter(magFilter, magFilters);
+ info.magFilter = magFilters[magFilter];
+ }
+
+ var wrapS = info.wrapS;
+ var wrapT = info.wrapT;
+ if ('wrap' in options) {
+ var wrap = options.wrap;
+ if (typeof wrap === 'string') {
+ check$1.parameter(wrap, wrapModes);
+ wrapS = wrapT = wrapModes[wrap];
+ } else if (Array.isArray(wrap)) {
+ check$1.parameter(wrap[0], wrapModes);
+ check$1.parameter(wrap[1], wrapModes);
+ wrapS = wrapModes[wrap[0]];
+ wrapT = wrapModes[wrap[1]];
+ }
+ } else {
+ if ('wrapS' in options) {
+ var optWrapS = options.wrapS;
+ check$1.parameter(optWrapS, wrapModes);
+ wrapS = wrapModes[optWrapS];
+ }
+ if ('wrapT' in options) {
+ var optWrapT = options.wrapT;
+ check$1.parameter(optWrapT, wrapModes);
+ wrapT = wrapModes[optWrapT];
+ }
+ }
+ info.wrapS = wrapS;
+ info.wrapT = wrapT;
+
+ if ('anisotropic' in options) {
+ var anisotropic = options.anisotropic;
+ check$1(typeof anisotropic === 'number' &&
+ anisotropic >= 1 && anisotropic <= limits.maxAnisotropic,
+ 'aniso samples must be between 1 and ');
+ info.anisotropic = options.anisotropic;
+ }
+
+ if ('mipmap' in options) {
+ var hasMipMap = false;
+ switch (typeof options.mipmap) {
+ case 'string':
+ check$1.parameter(options.mipmap, mipmapHint,
+ 'invalid mipmap hint');
+ info.mipmapHint = mipmapHint[options.mipmap];
+ info.genMipmaps = true;
+ hasMipMap = true;
+ break
+
+ case 'boolean':
+ hasMipMap = info.genMipmaps = options.mipmap;
+ break
+
+ case 'object':
+ check$1(Array.isArray(options.mipmap), 'invalid mipmap type');
+ info.genMipmaps = false;
+ hasMipMap = true;
+ break
+
+ default:
+ check$1.raise('invalid mipmap type');
+ }
+ if (hasMipMap && !('min' in options)) {
+ info.minFilter = GL_NEAREST_MIPMAP_NEAREST$1;
+ }
+ }
+ }
+
+ function setTexInfo (info, target) {
+ gl.texParameteri(target, GL_TEXTURE_MIN_FILTER, info.minFilter);
+ gl.texParameteri(target, GL_TEXTURE_MAG_FILTER, info.magFilter);
+ gl.texParameteri(target, GL_TEXTURE_WRAP_S, info.wrapS);
+ gl.texParameteri(target, GL_TEXTURE_WRAP_T, info.wrapT);
+ if (extensions.ext_texture_filter_anisotropic) {
+ gl.texParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, info.anisotropic);
+ }
+ if (info.genMipmaps) {
+ gl.hint(GL_GENERATE_MIPMAP_HINT, info.mipmapHint);
+ gl.generateMipmap(target);
+ }
+ }
+
+ // -------------------------------------------------------
+ // Full texture object
+ // -------------------------------------------------------
+ var textureCount = 0;
+ var textureSet = {};
+ var numTexUnits = limits.maxTextureUnits;
+ var textureUnits = Array(numTexUnits).map(function () {
+ return null
+ });
+
+ function REGLTexture (target) {
+ TexFlags.call(this);
+ this.mipmask = 0;
+ this.internalformat = GL_RGBA;
+
+ this.id = textureCount++;
+
+ this.refCount = 1;
+
+ this.target = target;
+ this.texture = gl.createTexture();
+
+ this.unit = -1;
+ this.bindCount = 0;
+
+ this.texInfo = new TexInfo();
+
+ if (config.profile) {
+ this.stats = {size: 0};
+ }
+ }
+
+ function tempBind (texture) {
+ gl.activeTexture(GL_TEXTURE0);
+ gl.bindTexture(texture.target, texture.texture);
+ }
+
+ function tempRestore () {
+ var prev = textureUnits[0];
+ if (prev) {
+ gl.bindTexture(prev.target, prev.texture);
+ } else {
+ gl.bindTexture(GL_TEXTURE_2D, null);
+ }
+ }
+
+ function destroy (texture) {
+ var handle = texture.texture;
+ check$1(handle, 'must not double destroy texture');
+ var unit = texture.unit;
+ var target = texture.target;
+ if (unit >= 0) {
+ gl.activeTexture(GL_TEXTURE0 + unit);
+ gl.bindTexture(target, null);
+ textureUnits[unit] = null;
+ }
+ gl.deleteTexture(handle);
+ texture.texture = null;
+ texture.params = null;
+ texture.pixels = null;
+ texture.refCount = 0;
+ delete textureSet[texture.id];
+ stats.textureCount--;
+ }
+
+ extend(REGLTexture.prototype, {
+ bind: function () {
+ var texture = this;
+ texture.bindCount += 1;
+ var unit = texture.unit;
+ if (unit < 0) {
+ for (var i = 0; i < numTexUnits; ++i) {
+ var other = textureUnits[i];
+ if (other) {
+ if (other.bindCount > 0) {
+ continue
+ }
+ other.unit = -1;
+ }
+ textureUnits[i] = texture;
+ unit = i;
+ break
+ }
+ if (unit >= numTexUnits) {
+ check$1.raise('insufficient number of texture units');
+ }
+ if (config.profile && stats.maxTextureUnits < (unit + 1)) {
+ stats.maxTextureUnits = unit + 1; // +1, since the units are zero-based
+ }
+ texture.unit = unit;
+ gl.activeTexture(GL_TEXTURE0 + unit);
+ gl.bindTexture(texture.target, texture.texture);
+ }
+ return unit
+ },
+
+ unbind: function () {
+ this.bindCount -= 1;
+ },
+
+ decRef: function () {
+ if (--this.refCount <= 0) {
+ destroy(this);
+ }
+ }
+ });
+
+ function createTexture2D (a, b) {
+ var texture = new REGLTexture(GL_TEXTURE_2D);
+ textureSet[texture.id] = texture;
+ stats.textureCount++;
+
+ function reglTexture2D (a, b) {
+ var texInfo = texture.texInfo;
+ TexInfo.call(texInfo);
+ var mipData = allocMipMap();
+
+ if (typeof a === 'number') {
+ if (typeof b === 'number') {
+ parseMipMapFromShape(mipData, a | 0, b | 0);
+ } else {
+ parseMipMapFromShape(mipData, a | 0, a | 0);
+ }
+ } else if (a) {
+ check$1.type(a, 'object', 'invalid arguments to regl.texture');
+ parseTexInfo(texInfo, a);
+ parseMipMapFromObject(mipData, a);
+ } else {
+ // empty textures get assigned a default shape of 1x1
+ parseMipMapFromShape(mipData, 1, 1);
+ }
+
+ if (texInfo.genMipmaps) {
+ mipData.mipmask = (mipData.width << 1) - 1;
+ }
+ texture.mipmask = mipData.mipmask;
+
+ copyFlags(texture, mipData);
+
+ check$1.texture2D(texInfo, mipData, limits);
+ texture.internalformat = mipData.internalformat;
+
+ reglTexture2D.width = mipData.width;
+ reglTexture2D.height = mipData.height;
+
+ tempBind(texture);
+ setMipMap(mipData, GL_TEXTURE_2D);
+ setTexInfo(texInfo, GL_TEXTURE_2D);
+ tempRestore();
+
+ freeMipMap(mipData);
+
+ if (config.profile) {
+ texture.stats.size = getTextureSize(
+ texture.internalformat,
+ texture.type,
+ mipData.width,
+ mipData.height,
+ texInfo.genMipmaps,
+ false);
+ }
+ reglTexture2D.format = textureFormatsInvert[texture.internalformat];
+ reglTexture2D.type = textureTypesInvert[texture.type];
+
+ reglTexture2D.mag = magFiltersInvert[texInfo.magFilter];
+ reglTexture2D.min = minFiltersInvert[texInfo.minFilter];
+
+ reglTexture2D.wrapS = wrapModesInvert[texInfo.wrapS];
+ reglTexture2D.wrapT = wrapModesInvert[texInfo.wrapT];
+
+ return reglTexture2D
+ }
+
+ function subimage (image, x_, y_, level_) {
+ check$1(!!image, 'must specify image data');
+
+ var x = x_ | 0;
+ var y = y_ | 0;
+ var level = level_ | 0;
+
+ var imageData = allocImage();
+ copyFlags(imageData, texture);
+ imageData.width = 0;
+ imageData.height = 0;
+ parseImage(imageData, image);
+ imageData.width = imageData.width || ((texture.width >> level) - x);
+ imageData.height = imageData.height || ((texture.height >> level) - y);
+
+ check$1(
+ texture.type === imageData.type &&
+ texture.format === imageData.format &&
+ texture.internalformat === imageData.internalformat,
+ 'incompatible format for texture.subimage');
+ check$1(
+ x >= 0 && y >= 0 &&
+ x + imageData.width <= texture.width &&
+ y + imageData.height <= texture.height,
+ 'texture.subimage write out of bounds');
+ check$1(
+ texture.mipmask & (1 << level),
+ 'missing mipmap data');
+ check$1(
+ imageData.data || imageData.element || imageData.needsCopy,
+ 'missing image data');
+
+ tempBind(texture);
+ setSubImage(imageData, GL_TEXTURE_2D, x, y, level);
+ tempRestore();
+
+ freeImage(imageData);
+
+ return reglTexture2D
+ }
+
+ function resize (w_, h_) {
+ var w = w_ | 0;
+ var h = (h_ | 0) || w;
+ if (w === texture.width && h === texture.height) {
+ return reglTexture2D
+ }
+
+ reglTexture2D.width = texture.width = w;
+ reglTexture2D.height = texture.height = h;
+
+ tempBind(texture);
+ for (var i = 0; texture.mipmask >> i; ++i) {
+ gl.texImage2D(
+ GL_TEXTURE_2D,
+ i,
+ texture.format,
+ w >> i,
+ h >> i,
+ 0,
+ texture.format,
+ texture.type,
+ null);
+ }
+ tempRestore();
+
+ // also, recompute the texture size.
+ if (config.profile) {
+ texture.stats.size = getTextureSize(
+ texture.internalformat,
+ texture.type,
+ w,
+ h,
+ false,
+ false);
+ }
+
+ return reglTexture2D
+ }
+
+ reglTexture2D(a, b);
+
+ reglTexture2D.subimage = subimage;
+ reglTexture2D.resize = resize;
+ reglTexture2D._reglType = 'texture2d';
+ reglTexture2D._texture = texture;
+ if (config.profile) {
+ reglTexture2D.stats = texture.stats;
+ }
+ reglTexture2D.destroy = function () {
+ texture.decRef();
+ };
+
+ return reglTexture2D
+ }
+
+ function createTextureCube (a0, a1, a2, a3, a4, a5) {
+ var texture = new REGLTexture(GL_TEXTURE_CUBE_MAP);
+ textureSet[texture.id] = texture;
+ stats.cubeCount++;
+
+ var faces = new Array(6);
+
+ function reglTextureCube (a0, a1, a2, a3, a4, a5) {
+ var i;
+ var texInfo = texture.texInfo;
+ TexInfo.call(texInfo);
+ for (i = 0; i < 6; ++i) {
+ faces[i] = allocMipMap();
+ }
+
+ if (typeof a0 === 'number' || !a0) {
+ var s = (a0 | 0) || 1;
+ for (i = 0; i < 6; ++i) {
+ parseMipMapFromShape(faces[i], s, s);
+ }
+ } else if (typeof a0 === 'object') {
+ if (a1) {
+ parseMipMapFromObject(faces[0], a0);
+ parseMipMapFromObject(faces[1], a1);
+ parseMipMapFromObject(faces[2], a2);
+ parseMipMapFromObject(faces[3], a3);
+ parseMipMapFromObject(faces[4], a4);
+ parseMipMapFromObject(faces[5], a5);
+ } else {
+ parseTexInfo(texInfo, a0);
+ parseFlags(texture, a0);
+ if ('faces' in a0) {
+ var face_input = a0.faces;
+ check$1(Array.isArray(face_input) && face_input.length === 6,
+ 'cube faces must be a length 6 array');
+ for (i = 0; i < 6; ++i) {
+ check$1(typeof face_input[i] === 'object' && !!face_input[i],
+ 'invalid input for cube map face');
+ copyFlags(faces[i], texture);
+ parseMipMapFromObject(faces[i], face_input[i]);
+ }
+ } else {
+ for (i = 0; i < 6; ++i) {
+ parseMipMapFromObject(faces[i], a0);
+ }
+ }
+ }
+ } else {
+ check$1.raise('invalid arguments to cube map');
+ }
+
+ copyFlags(texture, faces[0]);
+ if (texInfo.genMipmaps) {
+ texture.mipmask = (faces[0].width << 1) - 1;
+ } else {
+ texture.mipmask = faces[0].mipmask;
+ }
+
+ check$1.textureCube(texture, texInfo, faces, limits);
+ texture.internalformat = faces[0].internalformat;
+
+ reglTextureCube.width = faces[0].width;
+ reglTextureCube.height = faces[0].height;
+
+ tempBind(texture);
+ for (i = 0; i < 6; ++i) {
+ setMipMap(faces[i], GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
+ }
+ setTexInfo(texInfo, GL_TEXTURE_CUBE_MAP);
+ tempRestore();
+
+ if (config.profile) {
+ texture.stats.size = getTextureSize(
+ texture.internalformat,
+ texture.type,
+ reglTextureCube.width,
+ reglTextureCube.height,
+ texInfo.genMipmaps,
+ true);
+ }
+
+ reglTextureCube.format = textureFormatsInvert[texture.internalformat];
+ reglTextureCube.type = textureTypesInvert[texture.type];
+
+ reglTextureCube.mag = magFiltersInvert[texInfo.magFilter];
+ reglTextureCube.min = minFiltersInvert[texInfo.minFilter];
+
+ reglTextureCube.wrapS = wrapModesInvert[texInfo.wrapS];
+ reglTextureCube.wrapT = wrapModesInvert[texInfo.wrapT];
+
+ for (i = 0; i < 6; ++i) {
+ freeMipMap(faces[i]);
+ }
+
+ return reglTextureCube
+ }
+
+ function subimage (face, image, x_, y_, level_) {
+ check$1(!!image, 'must specify image data');
+ check$1(typeof face === 'number' && face === (face | 0) &&
+ face >= 0 && face < 6, 'invalid face');
+
+ var x = x_ | 0;
+ var y = y_ | 0;
+ var level = level_ | 0;
+
+ var imageData = allocImage();
+ copyFlags(imageData, texture);
+ imageData.width = 0;
+ imageData.height = 0;
+ parseImage(imageData, image);
+ imageData.width = imageData.width || ((texture.width >> level) - x);
+ imageData.height = imageData.height || ((texture.height >> level) - y);
+
+ check$1(
+ texture.type === imageData.type &&
+ texture.format === imageData.format &&
+ texture.internalformat === imageData.internalformat,
+ 'incompatible format for texture.subimage');
+ check$1(
+ x >= 0 && y >= 0 &&
+ x + imageData.width <= texture.width &&
+ y + imageData.height <= texture.height,
+ 'texture.subimage write out of bounds');
+ check$1(
+ texture.mipmask & (1 << level),
+ 'missing mipmap data');
+ check$1(
+ imageData.data || imageData.element || imageData.needsCopy,
+ 'missing image data');
+
+ tempBind(texture);
+ setSubImage(imageData, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, x, y, level);
+ tempRestore();
+
+ freeImage(imageData);
+
+ return reglTextureCube
+ }
+
+ function resize (radius_) {
+ var radius = radius_ | 0;
+ if (radius === texture.width) {
+ return
+ }
+
+ reglTextureCube.width = texture.width = radius;
+ reglTextureCube.height = texture.height = radius;
+
+ tempBind(texture);
+ for (var i = 0; i < 6; ++i) {
+ for (var j = 0; texture.mipmask >> j; ++j) {
+ gl.texImage2D(
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
+ j,
+ texture.format,
+ radius >> j,
+ radius >> j,
+ 0,
+ texture.format,
+ texture.type,
+ null);
+ }
+ }
+ tempRestore();
+
+ if (config.profile) {
+ texture.stats.size = getTextureSize(
+ texture.internalformat,
+ texture.type,
+ reglTextureCube.width,
+ reglTextureCube.height,
+ false,
+ true);
+ }
+
+ return reglTextureCube
+ }
+
+ reglTextureCube(a0, a1, a2, a3, a4, a5);
+
+ reglTextureCube.subimage = subimage;
+ reglTextureCube.resize = resize;
+ reglTextureCube._reglType = 'textureCube';
+ reglTextureCube._texture = texture;
+ if (config.profile) {
+ reglTextureCube.stats = texture.stats;
+ }
+ reglTextureCube.destroy = function () {
+ texture.decRef();
+ };
+
+ return reglTextureCube
+ }
+
+ // Called when regl is destroyed
+ function destroyTextures () {
+ for (var i = 0; i < numTexUnits; ++i) {
+ gl.activeTexture(GL_TEXTURE0 + i);
+ gl.bindTexture(GL_TEXTURE_2D, null);
+ textureUnits[i] = null;
+ }
+ values(textureSet).forEach(destroy);
+
+ stats.cubeCount = 0;
+ stats.textureCount = 0;
+ }
+
+ if (config.profile) {
+ stats.getTotalTextureSize = function () {
+ var total = 0;
+ Object.keys(textureSet).forEach(function (key) {
+ total += textureSet[key].stats.size;
+ });
+ return total
+ };
+ }
+
+ function restoreTextures () {
+ values(textureSet).forEach(function (texture) {
+ texture.texture = gl.createTexture();
+ gl.bindTexture(texture.target, texture.texture);
+ for (var i = 0; i < 32; ++i) {
+ if ((texture.mipmask & (1 << i)) === 0) {
+ continue
+ }
+ if (texture.target === GL_TEXTURE_2D) {
+ gl.texImage2D(GL_TEXTURE_2D,
+ i,
+ texture.internalformat,
+ texture.width >> i,
+ texture.height >> i,
+ 0,
+ texture.internalformat,
+ texture.type,
+ null);
+ } else {
+ for (var j = 0; j < 6; ++j) {
+ gl.texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j,
+ i,
+ texture.internalformat,
+ texture.width >> i,
+ texture.height >> i,
+ 0,
+ texture.internalformat,
+ texture.type,
+ null);
+ }
+ }
+ }
+ setTexInfo(texture.texInfo, texture.target);
+ });
+ }
+
+ return {
+ create2D: createTexture2D,
+ createCube: createTextureCube,
+ clear: destroyTextures,
+ getTexture: function (wrapper) {
+ return null
+ },
+ restore: restoreTextures
+ }
+}
+
+var GL_RENDERBUFFER = 0x8D41;
+
+var GL_RGBA4$1 = 0x8056;
+var GL_RGB5_A1$1 = 0x8057;
+var GL_RGB565$1 = 0x8D62;
+var GL_DEPTH_COMPONENT16 = 0x81A5;
+var GL_STENCIL_INDEX8 = 0x8D48;
+var GL_DEPTH_STENCIL$1 = 0x84F9;
+
+var GL_SRGB8_ALPHA8_EXT = 0x8C43;
+
+var GL_RGBA32F_EXT = 0x8814;
+
+var GL_RGBA16F_EXT = 0x881A;
+var GL_RGB16F_EXT = 0x881B;
+
+var FORMAT_SIZES = [];
+
+FORMAT_SIZES[GL_RGBA4$1] = 2;
+FORMAT_SIZES[GL_RGB5_A1$1] = 2;
+FORMAT_SIZES[GL_RGB565$1] = 2;
+
+FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2;
+FORMAT_SIZES[GL_STENCIL_INDEX8] = 1;
+FORMAT_SIZES[GL_DEPTH_STENCIL$1] = 4;
+
+FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4;
+FORMAT_SIZES[GL_RGBA32F_EXT] = 16;
+FORMAT_SIZES[GL_RGBA16F_EXT] = 8;
+FORMAT_SIZES[GL_RGB16F_EXT] = 6;
+
+function getRenderbufferSize (format, width, height) {
+ return FORMAT_SIZES[format] * width * height
+}
+
+var wrapRenderbuffers = function (gl, extensions, limits, stats, config) {
+ var formatTypes = {
+ 'rgba4': GL_RGBA4$1,
+ 'rgb565': GL_RGB565$1,
+ 'rgb5 a1': GL_RGB5_A1$1,
+ 'depth': GL_DEPTH_COMPONENT16,
+ 'stencil': GL_STENCIL_INDEX8,
+ 'depth stencil': GL_DEPTH_STENCIL$1
+ };
+
+ if (extensions.ext_srgb) {
+ formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT;
+ }
+
+ if (extensions.ext_color_buffer_half_float) {
+ formatTypes['rgba16f'] = GL_RGBA16F_EXT;
+ formatTypes['rgb16f'] = GL_RGB16F_EXT;
+ }
+
+ if (extensions.webgl_color_buffer_float) {
+ formatTypes['rgba32f'] = GL_RGBA32F_EXT;
+ }
+
+ var formatTypesInvert = [];
+ Object.keys(formatTypes).forEach(function (key) {
+ var val = formatTypes[key];
+ formatTypesInvert[val] = key;
+ });
+
+ var renderbufferCount = 0;
+ var renderbufferSet = {};
+
+ function REGLRenderbuffer (renderbuffer) {
+ this.id = renderbufferCount++;
+ this.refCount = 1;
+
+ this.renderbuffer = renderbuffer;
+
+ this.format = GL_RGBA4$1;
+ this.width = 0;
+ this.height = 0;
+
+ if (config.profile) {
+ this.stats = {size: 0};
+ }
+ }
+
+ REGLRenderbuffer.prototype.decRef = function () {
+ if (--this.refCount <= 0) {
+ destroy(this);
+ }
+ };
+
+ function destroy (rb) {
+ var handle = rb.renderbuffer;
+ check$1(handle, 'must not double destroy renderbuffer');
+ gl.bindRenderbuffer(GL_RENDERBUFFER, null);
+ gl.deleteRenderbuffer(handle);
+ rb.renderbuffer = null;
+ rb.refCount = 0;
+ delete renderbufferSet[rb.id];
+ stats.renderbufferCount--;
+ }
+
+ function createRenderbuffer (a, b) {
+ var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer());
+ renderbufferSet[renderbuffer.id] = renderbuffer;
+ stats.renderbufferCount++;
+
+ function reglRenderbuffer (a, b) {
+ var w = 0;
+ var h = 0;
+ var format = GL_RGBA4$1;
+
+ if (typeof a === 'object' && a) {
+ var options = a;
+ if ('shape' in options) {
+ var shape = options.shape;
+ check$1(Array.isArray(shape) && shape.length >= 2,
+ 'invalid renderbuffer shape');
+ w = shape[0] | 0;
+ h = shape[1] | 0;
+ } else {
+ if ('radius' in options) {
+ w = h = options.radius | 0;
+ }
+ if ('width' in options) {
+ w = options.width | 0;
+ }
+ if ('height' in options) {
+ h = options.height | 0;
+ }
+ }
+ if ('format' in options) {
+ check$1.parameter(options.format, formatTypes,
+ 'invalid renderbuffer format');
+ format = formatTypes[options.format];
+ }
+ } else if (typeof a === 'number') {
+ w = a | 0;
+ if (typeof b === 'number') {
+ h = b | 0;
+ } else {
+ h = w;
+ }
+ } else if (!a) {
+ w = h = 1;
+ } else {
+ check$1.raise('invalid arguments to renderbuffer constructor');
+ }
+
+ // check shape
+ check$1(
+ w > 0 && h > 0 &&
+ w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize,
+ 'invalid renderbuffer size');
+
+ if (w === renderbuffer.width &&
+ h === renderbuffer.height &&
+ format === renderbuffer.format) {
+ return
+ }
+
+ reglRenderbuffer.width = renderbuffer.width = w;
+ reglRenderbuffer.height = renderbuffer.height = h;
+ renderbuffer.format = format;
+
+ gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer);
+ gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h);
+
+ if (config.profile) {
+ renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height);
+ }
+ reglRenderbuffer.format = formatTypesInvert[renderbuffer.format];
+
+ return reglRenderbuffer
+ }
+
+ function resize (w_, h_) {
+ var w = w_ | 0;
+ var h = (h_ | 0) || w;
+
+ if (w === renderbuffer.width && h === renderbuffer.height) {
+ return reglRenderbuffer
+ }
+
+ // check shape
+ check$1(
+ w > 0 && h > 0 &&
+ w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize,
+ 'invalid renderbuffer size');
+
+ reglRenderbuffer.width = renderbuffer.width = w;
+ reglRenderbuffer.height = renderbuffer.height = h;
+
+ gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer);
+ gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h);
+
+ // also, recompute size.
+ if (config.profile) {
+ renderbuffer.stats.size = getRenderbufferSize(
+ renderbuffer.format, renderbuffer.width, renderbuffer.height);
+ }
+
+ return reglRenderbuffer
+ }
+
+ reglRenderbuffer(a, b);
+
+ reglRenderbuffer.resize = resize;
+ reglRenderbuffer._reglType = 'renderbuffer';
+ reglRenderbuffer._renderbuffer = renderbuffer;
+ if (config.profile) {
+ reglRenderbuffer.stats = renderbuffer.stats;
+ }
+ reglRenderbuffer.destroy = function () {
+ renderbuffer.decRef();
+ };
+
+ return reglRenderbuffer
+ }
+
+ if (config.profile) {
+ stats.getTotalRenderbufferSize = function () {
+ var total = 0;
+ Object.keys(renderbufferSet).forEach(function (key) {
+ total += renderbufferSet[key].stats.size;
+ });
+ return total
+ };
+ }
+
+ function restoreRenderbuffers () {
+ values(renderbufferSet).forEach(function (rb) {
+ rb.renderbuffer = gl.createRenderbuffer();
+ gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer);
+ gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height);
+ });
+ gl.bindRenderbuffer(GL_RENDERBUFFER, null);
+ }
+
+ return {
+ create: createRenderbuffer,
+ clear: function () {
+ values(renderbufferSet).forEach(destroy);
+ },
+ restore: restoreRenderbuffers
+ }
+};
+
+// We store these constants so that the minifier can inline them
+var GL_FRAMEBUFFER = 0x8D40;
+var GL_RENDERBUFFER$1 = 0x8D41;
+
+var GL_TEXTURE_2D$1 = 0x0DE1;
+var GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 = 0x8515;
+
+var GL_COLOR_ATTACHMENT0 = 0x8CE0;
+var GL_DEPTH_ATTACHMENT = 0x8D00;
+var GL_STENCIL_ATTACHMENT = 0x8D20;
+var GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
+
+var GL_FRAMEBUFFER_COMPLETE = 0x8CD5;
+var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6;
+var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7;
+var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9;
+var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD;
+
+var GL_HALF_FLOAT_OES$2 = 0x8D61;
+var GL_UNSIGNED_BYTE$5 = 0x1401;
+var GL_FLOAT$4 = 0x1406;
+
+var GL_RGBA$1 = 0x1908;
+
+var GL_DEPTH_COMPONENT$1 = 0x1902;
+
+var colorTextureFormatEnums = [
+ GL_RGBA$1
+];
+
+// for every texture format, store
+// the number of channels
+var textureFormatChannels = [];
+textureFormatChannels[GL_RGBA$1] = 4;
+
+// for every texture type, store
+// the size in bytes.
+var textureTypeSizes = [];
+textureTypeSizes[GL_UNSIGNED_BYTE$5] = 1;
+textureTypeSizes[GL_FLOAT$4] = 4;
+textureTypeSizes[GL_HALF_FLOAT_OES$2] = 2;
+
+var GL_RGBA4$2 = 0x8056;
+var GL_RGB5_A1$2 = 0x8057;
+var GL_RGB565$2 = 0x8D62;
+var GL_DEPTH_COMPONENT16$1 = 0x81A5;
+var GL_STENCIL_INDEX8$1 = 0x8D48;
+var GL_DEPTH_STENCIL$2 = 0x84F9;
+
+var GL_SRGB8_ALPHA8_EXT$1 = 0x8C43;
+
+var GL_RGBA32F_EXT$1 = 0x8814;
+
+var GL_RGBA16F_EXT$1 = 0x881A;
+var GL_RGB16F_EXT$1 = 0x881B;
+
+var colorRenderbufferFormatEnums = [
+ GL_RGBA4$2,
+ GL_RGB5_A1$2,
+ GL_RGB565$2,
+ GL_SRGB8_ALPHA8_EXT$1,
+ GL_RGBA16F_EXT$1,
+ GL_RGB16F_EXT$1,
+ GL_RGBA32F_EXT$1
+];
+
+var statusCode = {};
+statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete';
+statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment';
+statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions';
+statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment';
+statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported';
+
+function wrapFBOState (
+ gl,
+ extensions,
+ limits,
+ textureState,
+ renderbufferState,
+ stats) {
+ var framebufferState = {
+ cur: null,
+ next: null,
+ dirty: false,
+ setFBO: null
+ };
+
+ var colorTextureFormats = ['rgba'];
+ var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1'];
+
+ if (extensions.ext_srgb) {
+ colorRenderbufferFormats.push('srgba');
+ }
+
+ if (extensions.ext_color_buffer_half_float) {
+ colorRenderbufferFormats.push('rgba16f', 'rgb16f');
+ }
+
+ if (extensions.webgl_color_buffer_float) {
+ colorRenderbufferFormats.push('rgba32f');
+ }
+
+ var colorTypes = ['uint8'];
+ if (extensions.oes_texture_half_float) {
+ colorTypes.push('half float', 'float16');
+ }
+ if (extensions.oes_texture_float) {
+ colorTypes.push('float', 'float32');
+ }
+
+ function FramebufferAttachment (target, texture, renderbuffer) {
+ this.target = target;
+ this.texture = texture;
+ this.renderbuffer = renderbuffer;
+
+ var w = 0;
+ var h = 0;
+ if (texture) {
+ w = texture.width;
+ h = texture.height;
+ } else if (renderbuffer) {
+ w = renderbuffer.width;
+ h = renderbuffer.height;
+ }
+ this.width = w;
+ this.height = h;
+ }
+
+ function decRef (attachment) {
+ if (attachment) {
+ if (attachment.texture) {
+ attachment.texture._texture.decRef();
+ }
+ if (attachment.renderbuffer) {
+ attachment.renderbuffer._renderbuffer.decRef();
+ }
+ }
+ }
+
+ function incRefAndCheckShape (attachment, width, height) {
+ if (!attachment) {
+ return
+ }
+ if (attachment.texture) {
+ var texture = attachment.texture._texture;
+ var tw = Math.max(1, texture.width);
+ var th = Math.max(1, texture.height);
+ check$1(tw === width && th === height,
+ 'inconsistent width/height for supplied texture');
+ texture.refCount += 1;
+ } else {
+ var renderbuffer = attachment.renderbuffer._renderbuffer;
+ check$1(
+ renderbuffer.width === width && renderbuffer.height === height,
+ 'inconsistent width/height for renderbuffer');
+ renderbuffer.refCount += 1;
+ }
+ }
+
+ function attach (location, attachment) {
+ if (attachment) {
+ if (attachment.texture) {
+ gl.framebufferTexture2D(
+ GL_FRAMEBUFFER,
+ location,
+ attachment.target,
+ attachment.texture._texture.texture,
+ 0);
+ } else {
+ gl.framebufferRenderbuffer(
+ GL_FRAMEBUFFER,
+ location,
+ GL_RENDERBUFFER$1,
+ attachment.renderbuffer._renderbuffer.renderbuffer);
+ }
+ }
+ }
+
+ function parseAttachment (attachment) {
+ var target = GL_TEXTURE_2D$1;
+ var texture = null;
+ var renderbuffer = null;
+
+ var data = attachment;
+ if (typeof attachment === 'object') {
+ data = attachment.data;
+ if ('target' in attachment) {
+ target = attachment.target | 0;
+ }
+ }
+
+ check$1.type(data, 'function', 'invalid attachment data');
+
+ var type = data._reglType;
+ if (type === 'texture2d') {
+ texture = data;
+ check$1(target === GL_TEXTURE_2D$1);
+ } else if (type === 'textureCube') {
+ texture = data;
+ check$1(
+ target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 &&
+ target < GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + 6,
+ 'invalid cube map target');
+ } else if (type === 'renderbuffer') {
+ renderbuffer = data;
+ target = GL_RENDERBUFFER$1;
+ } else {
+ check$1.raise('invalid regl object for attachment');
+ }
+
+ return new FramebufferAttachment(target, texture, renderbuffer)
+ }
+
+ function allocAttachment (
+ width,
+ height,
+ isTexture,
+ format,
+ type) {
+ if (isTexture) {
+ var texture = textureState.create2D({
+ width: width,
+ height: height,
+ format: format,
+ type: type
+ });
+ texture._texture.refCount = 0;
+ return new FramebufferAttachment(GL_TEXTURE_2D$1, texture, null)
+ } else {
+ var rb = renderbufferState.create({
+ width: width,
+ height: height,
+ format: format
+ });
+ rb._renderbuffer.refCount = 0;
+ return new FramebufferAttachment(GL_RENDERBUFFER$1, null, rb)
+ }
+ }
+
+ function unwrapAttachment (attachment) {
+ return attachment && (attachment.texture || attachment.renderbuffer)
+ }
+
+ function resizeAttachment (attachment, w, h) {
+ if (attachment) {
+ if (attachment.texture) {
+ attachment.texture.resize(w, h);
+ } else if (attachment.renderbuffer) {
+ attachment.renderbuffer.resize(w, h);
+ }
+ }
+ }
+
+ var framebufferCount = 0;
+ var framebufferSet = {};
+
+ function REGLFramebuffer () {
+ this.id = framebufferCount++;
+ framebufferSet[this.id] = this;
+
+ this.framebuffer = gl.createFramebuffer();
+ this.width = 0;
+ this.height = 0;
+
+ this.colorAttachments = [];
+ this.depthAttachment = null;
+ this.stencilAttachment = null;
+ this.depthStencilAttachment = null;
+ }
+
+ function decFBORefs (framebuffer) {
+ framebuffer.colorAttachments.forEach(decRef);
+ decRef(framebuffer.depthAttachment);
+ decRef(framebuffer.stencilAttachment);
+ decRef(framebuffer.depthStencilAttachment);
+ }
+
+ function destroy (framebuffer) {
+ var handle = framebuffer.framebuffer;
+ check$1(handle, 'must not double destroy framebuffer');
+ gl.deleteFramebuffer(handle);
+ framebuffer.framebuffer = null;
+ stats.framebufferCount--;
+ delete framebufferSet[framebuffer.id];
+ }
+
+ function updateFramebuffer (framebuffer) {
+ var i;
+
+ gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer.framebuffer);
+ var colorAttachments = framebuffer.colorAttachments;
+ for (i = 0; i < colorAttachments.length; ++i) {
+ attach(GL_COLOR_ATTACHMENT0 + i, colorAttachments[i]);
+ }
+ for (i = colorAttachments.length; i < limits.maxColorAttachments; ++i) {
+ gl.framebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + i,
+ GL_TEXTURE_2D$1,
+ null,
+ 0);
+ }
+
+ gl.framebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_TEXTURE_2D$1,
+ null,
+ 0);
+ gl.framebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ GL_TEXTURE_2D$1,
+ null,
+ 0);
+ gl.framebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_STENCIL_ATTACHMENT,
+ GL_TEXTURE_2D$1,
+ null,
+ 0);
+
+ attach(GL_DEPTH_ATTACHMENT, framebuffer.depthAttachment);
+ attach(GL_STENCIL_ATTACHMENT, framebuffer.stencilAttachment);
+ attach(GL_DEPTH_STENCIL_ATTACHMENT, framebuffer.depthStencilAttachment);
+
+ // Check status code
+ var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
+ if (status !== GL_FRAMEBUFFER_COMPLETE) {
+ check$1.raise('framebuffer configuration not supported, status = ' +
+ statusCode[status]);
+ }
+
+ gl.bindFramebuffer(GL_FRAMEBUFFER, framebufferState.next);
+ framebufferState.cur = framebufferState.next;
+
+ // FIXME: Clear error code here. This is a work around for a bug in
+ // headless-gl
+ gl.getError();
+ }
+
+ function createFBO (a0, a1) {
+ var framebuffer = new REGLFramebuffer();
+ stats.framebufferCount++;
+
+ function reglFramebuffer (a, b) {
+ var i;
+
+ check$1(framebufferState.next !== framebuffer,
+ 'can not update framebuffer which is currently in use');
+
+ var extDrawBuffers = extensions.webgl_draw_buffers;
+
+ var width = 0;
+ var height = 0;
+
+ var needsDepth = true;
+ var needsStencil = true;
+
+ var colorBuffer = null;
+ var colorTexture = true;
+ var colorFormat = 'rgba';
+ var colorType = 'uint8';
+ var colorCount = 1;
+
+ var depthBuffer = null;
+ var stencilBuffer = null;
+ var depthStencilBuffer = null;
+ var depthStencilTexture = false;
+
+ if (typeof a === 'number') {
+ width = a | 0;
+ height = (b | 0) || width;
+ } else if (!a) {
+ width = height = 1;
+ } else {
+ check$1.type(a, 'object', 'invalid arguments for framebuffer');
+ var options = a;
+
+ if ('shape' in options) {
+ var shape = options.shape;
+ check$1(Array.isArray(shape) && shape.length >= 2,
+ 'invalid shape for framebuffer');
+ width = shape[0];
+ height = shape[1];
+ } else {
+ if ('radius' in options) {
+ width = height = options.radius;
+ }
+ if ('width' in options) {
+ width = options.width;
+ }
+ if ('height' in options) {
+ height = options.height;
+ }
+ }
+
+ if ('color' in options ||
+ 'colors' in options) {
+ colorBuffer =
+ options.color ||
+ options.colors;
+ if (Array.isArray(colorBuffer)) {
+ check$1(
+ colorBuffer.length === 1 || extDrawBuffers,
+ 'multiple render targets not supported');
+ }
+ }
+
+ if (!colorBuffer) {
+ if ('colorCount' in options) {
+ colorCount = options.colorCount | 0;
+ check$1(colorCount > 0, 'invalid color buffer count');
+ }
+
+ if ('colorTexture' in options) {
+ colorTexture = !!options.colorTexture;
+ colorFormat = 'rgba4';
+ }
+
+ if ('colorType' in options) {
+ colorType = options.colorType;
+ if (!colorTexture) {
+ if (colorType === 'half float' || colorType === 'float16') {
+ check$1(extensions.ext_color_buffer_half_float,
+ 'you must enable EXT_color_buffer_half_float to use 16-bit render buffers');
+ colorFormat = 'rgba16f';
+ } else if (colorType === 'float' || colorType === 'float32') {
+ check$1(extensions.webgl_color_buffer_float,
+ 'you must enable WEBGL_color_buffer_float in order to use 32-bit floating point renderbuffers');
+ colorFormat = 'rgba32f';
+ }
+ } else {
+ check$1(extensions.oes_texture_float ||
+ !(colorType === 'float' || colorType === 'float32'),
+ 'you must enable OES_texture_float in order to use floating point framebuffer objects');
+ check$1(extensions.oes_texture_half_float ||
+ !(colorType === 'half float' || colorType === 'float16'),
+ 'you must enable OES_texture_half_float in order to use 16-bit floating point framebuffer objects');
+ }
+ check$1.oneOf(colorType, colorTypes, 'invalid color type');
+ }
+
+ if ('colorFormat' in options) {
+ colorFormat = options.colorFormat;
+ if (colorTextureFormats.indexOf(colorFormat) >= 0) {
+ colorTexture = true;
+ } else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) {
+ colorTexture = false;
+ } else {
+ if (colorTexture) {
+ check$1.oneOf(
+ options.colorFormat, colorTextureFormats,
+ 'invalid color format for texture');
+ } else {
+ check$1.oneOf(
+ options.colorFormat, colorRenderbufferFormats,
+ 'invalid color format for renderbuffer');
+ }
+ }
+ }
+ }
+
+ if ('depthTexture' in options || 'depthStencilTexture' in options) {
+ depthStencilTexture = !!(options.depthTexture ||
+ options.depthStencilTexture);
+ check$1(!depthStencilTexture || extensions.webgl_depth_texture,
+ 'webgl_depth_texture extension not supported');
+ }
+
+ if ('depth' in options) {
+ if (typeof options.depth === 'boolean') {
+ needsDepth = options.depth;
+ } else {
+ depthBuffer = options.depth;
+ needsStencil = false;
+ }
+ }
+
+ if ('stencil' in options) {
+ if (typeof options.stencil === 'boolean') {
+ needsStencil = options.stencil;
+ } else {
+ stencilBuffer = options.stencil;
+ needsDepth = false;
+ }
+ }
+
+ if ('depthStencil' in options) {
+ if (typeof options.depthStencil === 'boolean') {
+ needsDepth = needsStencil = options.depthStencil;
+ } else {
+ depthStencilBuffer = options.depthStencil;
+ needsDepth = false;
+ needsStencil = false;
+ }
+ }
+ }
+
+ // parse attachments
+ var colorAttachments = null;
+ var depthAttachment = null;
+ var stencilAttachment = null;
+ var depthStencilAttachment = null;
+
+ // Set up color attachments
+ if (Array.isArray(colorBuffer)) {
+ colorAttachments = colorBuffer.map(parseAttachment);
+ } else if (colorBuffer) {
+ colorAttachments = [parseAttachment(colorBuffer)];
+ } else {
+ colorAttachments = new Array(colorCount);
+ for (i = 0; i < colorCount; ++i) {
+ colorAttachments[i] = allocAttachment(
+ width,
+ height,
+ colorTexture,
+ colorFormat,
+ colorType);
+ }
+ }
+
+ check$1(extensions.webgl_draw_buffers || colorAttachments.length <= 1,
+ 'you must enable the WEBGL_draw_buffers extension in order to use multiple color buffers.');
+ check$1(colorAttachments.length <= limits.maxColorAttachments,
+ 'too many color attachments, not supported');
+
+ width = width || colorAttachments[0].width;
+ height = height || colorAttachments[0].height;
+
+ if (depthBuffer) {
+ depthAttachment = parseAttachment(depthBuffer);
+ } else if (needsDepth && !needsStencil) {
+ depthAttachment = allocAttachment(
+ width,
+ height,
+ depthStencilTexture,
+ 'depth',
+ 'uint32');
+ }
+
+ if (stencilBuffer) {
+ stencilAttachment = parseAttachment(stencilBuffer);
+ } else if (needsStencil && !needsDepth) {
+ stencilAttachment = allocAttachment(
+ width,
+ height,
+ false,
+ 'stencil',
+ 'uint8');
+ }
+
+ if (depthStencilBuffer) {
+ depthStencilAttachment = parseAttachment(depthStencilBuffer);
+ } else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) {
+ depthStencilAttachment = allocAttachment(
+ width,
+ height,
+ depthStencilTexture,
+ 'depth stencil',
+ 'depth stencil');
+ }
+
+ check$1(
+ (!!depthBuffer) + (!!stencilBuffer) + (!!depthStencilBuffer) <= 1,
+ 'invalid framebuffer configuration, can specify exactly one depth/stencil attachment');
+
+ var commonColorAttachmentSize = null;
+
+ for (i = 0; i < colorAttachments.length; ++i) {
+ incRefAndCheckShape(colorAttachments[i], width, height);
+ check$1(!colorAttachments[i] ||
+ (colorAttachments[i].texture &&
+ colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0) ||
+ (colorAttachments[i].renderbuffer &&
+ colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0),
+ 'framebuffer color attachment ' + i + ' is invalid');
+
+ if (colorAttachments[i] && colorAttachments[i].texture) {
+ var colorAttachmentSize =
+ textureFormatChannels[colorAttachments[i].texture._texture.format] *
+ textureTypeSizes[colorAttachments[i].texture._texture.type];
+
+ if (commonColorAttachmentSize === null) {
+ commonColorAttachmentSize = colorAttachmentSize;
+ } else {
+ // We need to make sure that all color attachments have the same number of bitplanes
+ // (that is, the same numer of bits per pixel)
+ // This is required by the GLES2.0 standard. See the beginning of Chapter 4 in that document.
+ check$1(commonColorAttachmentSize === colorAttachmentSize,
+ 'all color attachments much have the same number of bits per pixel.');
+ }
+ }
+ }
+ incRefAndCheckShape(depthAttachment, width, height);
+ check$1(!depthAttachment ||
+ (depthAttachment.texture &&
+ depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT$1) ||
+ (depthAttachment.renderbuffer &&
+ depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16$1),
+ 'invalid depth attachment for framebuffer object');
+ incRefAndCheckShape(stencilAttachment, width, height);
+ check$1(!stencilAttachment ||
+ (stencilAttachment.renderbuffer &&
+ stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8$1),
+ 'invalid stencil attachment for framebuffer object');
+ incRefAndCheckShape(depthStencilAttachment, width, height);
+ check$1(!depthStencilAttachment ||
+ (depthStencilAttachment.texture &&
+ depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL$2) ||
+ (depthStencilAttachment.renderbuffer &&
+ depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL$2),
+ 'invalid depth-stencil attachment for framebuffer object');
+
+ // decrement references
+ decFBORefs(framebuffer);
+
+ framebuffer.width = width;
+ framebuffer.height = height;
+
+ framebuffer.colorAttachments = colorAttachments;
+ framebuffer.depthAttachment = depthAttachment;
+ framebuffer.stencilAttachment = stencilAttachment;
+ framebuffer.depthStencilAttachment = depthStencilAttachment;
+
+ reglFramebuffer.color = colorAttachments.map(unwrapAttachment);
+ reglFramebuffer.depth = unwrapAttachment(depthAttachment);
+ reglFramebuffer.stencil = unwrapAttachment(stencilAttachment);
+ reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment);
+
+ reglFramebuffer.width = framebuffer.width;
+ reglFramebuffer.height = framebuffer.height;
+
+ updateFramebuffer(framebuffer);
+
+ return reglFramebuffer
+ }
+
+ function resize (w_, h_) {
+ check$1(framebufferState.next !== framebuffer,
+ 'can not resize a framebuffer which is currently in use');
+
+ var w = w_ | 0;
+ var h = (h_ | 0) || w;
+ if (w === framebuffer.width && h === framebuffer.height) {
+ return reglFramebuffer
+ }
+
+ // resize all buffers
+ var colorAttachments = framebuffer.colorAttachments;
+ for (var i = 0; i < colorAttachments.length; ++i) {
+ resizeAttachment(colorAttachments[i], w, h);
+ }
+ resizeAttachment(framebuffer.depthAttachment, w, h);
+ resizeAttachment(framebuffer.stencilAttachment, w, h);
+ resizeAttachment(framebuffer.depthStencilAttachment, w, h);
+
+ framebuffer.width = reglFramebuffer.width = w;
+ framebuffer.height = reglFramebuffer.height = h;
+
+ updateFramebuffer(framebuffer);
+
+ return reglFramebuffer
+ }
+
+ reglFramebuffer(a0, a1);
+
+ return extend(reglFramebuffer, {
+ resize: resize,
+ _reglType: 'framebuffer',
+ _framebuffer: framebuffer,
+ destroy: function () {
+ destroy(framebuffer);
+ decFBORefs(framebuffer);
+ },
+ use: function (block) {
+ framebufferState.setFBO({
+ framebuffer: reglFramebuffer
+ }, block);
+ }
+ })
+ }
+
+ function createCubeFBO (options) {
+ var faces = Array(6);
+
+ function reglFramebufferCube (a) {
+ var i;
+
+ check$1(faces.indexOf(framebufferState.next) < 0,
+ 'can not update framebuffer which is currently in use');
+
+ var extDrawBuffers = extensions.webgl_draw_buffers;
+
+ var params = {
+ color: null
+ };
+
+ var radius = 0;
+
+ var colorBuffer = null;
+ var colorFormat = 'rgba';
+ var colorType = 'uint8';
+ var colorCount = 1;
+
+ if (typeof a === 'number') {
+ radius = a | 0;
+ } else if (!a) {
+ radius = 1;
+ } else {
+ check$1.type(a, 'object', 'invalid arguments for framebuffer');
+ var options = a;
+
+ if ('shape' in options) {
+ var shape = options.shape;
+ check$1(
+ Array.isArray(shape) && shape.length >= 2,
+ 'invalid shape for framebuffer');
+ check$1(
+ shape[0] === shape[1],
+ 'cube framebuffer must be square');
+ radius = shape[0];
+ } else {
+ if ('radius' in options) {
+ radius = options.radius | 0;
+ }
+ if ('width' in options) {
+ radius = options.width | 0;
+ if ('height' in options) {
+ check$1(options.height === radius, 'must be square');
+ }
+ } else if ('height' in options) {
+ radius = options.height | 0;
+ }
+ }
+
+ if ('color' in options ||
+ 'colors' in options) {
+ colorBuffer =
+ options.color ||
+ options.colors;
+ if (Array.isArray(colorBuffer)) {
+ check$1(
+ colorBuffer.length === 1 || extDrawBuffers,
+ 'multiple render targets not supported');
+ }
+ }
+
+ if (!colorBuffer) {
+ if ('colorCount' in options) {
+ colorCount = options.colorCount | 0;
+ check$1(colorCount > 0, 'invalid color buffer count');
+ }
+
+ if ('colorType' in options) {
+ check$1.oneOf(
+ options.colorType, colorTypes,
+ 'invalid color type');
+ colorType = options.colorType;
+ }
+
+ if ('colorFormat' in options) {
+ colorFormat = options.colorFormat;
+ check$1.oneOf(
+ options.colorFormat, colorTextureFormats,
+ 'invalid color format for texture');
+ }
+ }
+
+ if ('depth' in options) {
+ params.depth = options.depth;
+ }
+
+ if ('stencil' in options) {
+ params.stencil = options.stencil;
+ }
+
+ if ('depthStencil' in options) {
+ params.depthStencil = options.depthStencil;
+ }
+ }
+
+ var colorCubes;
+ if (colorBuffer) {
+ if (Array.isArray(colorBuffer)) {
+ colorCubes = [];
+ for (i = 0; i < colorBuffer.length; ++i) {
+ colorCubes[i] = colorBuffer[i];
+ }
+ } else {
+ colorCubes = [ colorBuffer ];
+ }
+ } else {
+ colorCubes = Array(colorCount);
+ var cubeMapParams = {
+ radius: radius,
+ format: colorFormat,
+ type: colorType
+ };
+ for (i = 0; i < colorCount; ++i) {
+ colorCubes[i] = textureState.createCube(cubeMapParams);
+ }
+ }
+
+ // Check color cubes
+ params.color = Array(colorCubes.length);
+ for (i = 0; i < colorCubes.length; ++i) {
+ var cube = colorCubes[i];
+ check$1(
+ typeof cube === 'function' && cube._reglType === 'textureCube',
+ 'invalid cube map');
+ radius = radius || cube.width;
+ check$1(
+ cube.width === radius && cube.height === radius,
+ 'invalid cube map shape');
+ params.color[i] = {
+ target: GL_TEXTURE_CUBE_MAP_POSITIVE_X$1,
+ data: colorCubes[i]
+ };
+ }
+
+ for (i = 0; i < 6; ++i) {
+ for (var j = 0; j < colorCubes.length; ++j) {
+ params.color[j].target = GL_TEXTURE_CUBE_MAP_POSITIVE_X$1 + i;
+ }
+ // reuse depth-stencil attachments across all cube maps
+ if (i > 0) {
+ params.depth = faces[0].depth;
+ params.stencil = faces[0].stencil;
+ params.depthStencil = faces[0].depthStencil;
+ }
+ if (faces[i]) {
+ (faces[i])(params);
+ } else {
+ faces[i] = createFBO(params);
+ }
+ }
+
+ return extend(reglFramebufferCube, {
+ width: radius,
+ height: radius,
+ color: colorCubes
+ })
+ }
+
+ function resize (radius_) {
+ var i;
+ var radius = radius_ | 0;
+ check$1(radius > 0 && radius <= limits.maxCubeMapSize,
+ 'invalid radius for cube fbo');
+
+ if (radius === reglFramebufferCube.width) {
+ return reglFramebufferCube
+ }
+
+ var colors = reglFramebufferCube.color;
+ for (i = 0; i < colors.length; ++i) {
+ colors[i].resize(radius);
+ }
+
+ for (i = 0; i < 6; ++i) {
+ faces[i].resize(radius);
+ }
+
+ reglFramebufferCube.width = reglFramebufferCube.height = radius;
+
+ return reglFramebufferCube
+ }
+
+ reglFramebufferCube(options);
+
+ return extend(reglFramebufferCube, {
+ faces: faces,
+ resize: resize,
+ _reglType: 'framebufferCube',
+ destroy: function () {
+ faces.forEach(function (f) {
+ f.destroy();
+ });
+ }
+ })
+ }
+
+ function restoreFramebuffers () {
+ values(framebufferSet).forEach(function (fb) {
+ fb.framebuffer = gl.createFramebuffer();
+ updateFramebuffer(fb);
+ });
+ }
+
+ return extend(framebufferState, {
+ getFramebuffer: function (object) {
+ if (typeof object === 'function' && object._reglType === 'framebuffer') {
+ var fbo = object._framebuffer;
+ if (fbo instanceof REGLFramebuffer) {
+ return fbo
+ }
+ }
+ return null
+ },
+ create: createFBO,
+ createCube: createCubeFBO,
+ clear: function () {
+ values(framebufferSet).forEach(destroy);
+ },
+ restore: restoreFramebuffers
+ })
+}
+
+var GL_FLOAT$5 = 5126;
+
+function AttributeRecord () {
+ this.state = 0;
+
+ this.x = 0.0;
+ this.y = 0.0;
+ this.z = 0.0;
+ this.w = 0.0;
+
+ this.buffer = null;
+ this.size = 0;
+ this.normalized = false;
+ this.type = GL_FLOAT$5;
+ this.offset = 0;
+ this.stride = 0;
+ this.divisor = 0;
+}
+
+function wrapAttributeState (
+ gl,
+ extensions,
+ limits,
+ bufferState,
+ stringStore) {
+ var NUM_ATTRIBUTES = limits.maxAttributes;
+ var attributeBindings = new Array(NUM_ATTRIBUTES);
+ for (var i = 0; i < NUM_ATTRIBUTES; ++i) {
+ attributeBindings[i] = new AttributeRecord();
+ }
+
+ return {
+ Record: AttributeRecord,
+ scope: {},
+ state: attributeBindings
+ }
+}
+
+var GL_FRAGMENT_SHADER = 35632;
+var GL_VERTEX_SHADER = 35633;
+
+var GL_ACTIVE_UNIFORMS = 0x8B86;
+var GL_ACTIVE_ATTRIBUTES = 0x8B89;
+
+function wrapShaderState (gl, stringStore, stats, config) {
+ // ===================================================
+ // glsl compilation and linking
+ // ===================================================
+ var fragShaders = {};
+ var vertShaders = {};
+
+ function ActiveInfo (name, id, location, info) {
+ this.name = name;
+ this.id = id;
+ this.location = location;
+ this.info = info;
+ }
+
+ function insertActiveInfo (list, info) {
+ for (var i = 0; i < list.length; ++i) {
+ if (list[i].id === info.id) {
+ list[i].location = info.location;
+ return
+ }
+ }
+ list.push(info);
+ }
+
+ function getShader (type, id, command) {
+ var cache = type === GL_FRAGMENT_SHADER ? fragShaders : vertShaders;
+ var shader = cache[id];
+
+ if (!shader) {
+ var source = stringStore.str(id);
+ shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+ check$1.shaderError(gl, shader, source, type, command);
+ cache[id] = shader;
+ }
+
+ return shader
+ }
+
+ // ===================================================
+ // program linking
+ // ===================================================
+ var programCache = {};
+ var programList = [];
+
+ var PROGRAM_COUNTER = 0;
+
+ function REGLProgram (fragId, vertId) {
+ this.id = PROGRAM_COUNTER++;
+ this.fragId = fragId;
+ this.vertId = vertId;
+ this.program = null;
+ this.uniforms = [];
+ this.attributes = [];
+
+ if (config.profile) {
+ this.stats = {
+ uniformsCount: 0,
+ attributesCount: 0
+ };
+ }
+ }
+
+ function linkProgram (desc, command) {
+ var i, info;
+
+ // -------------------------------
+ // compile & link
+ // -------------------------------
+ var fragShader = getShader(GL_FRAGMENT_SHADER, desc.fragId);
+ var vertShader = getShader(GL_VERTEX_SHADER, desc.vertId);
+
+ var program = desc.program = gl.createProgram();
+ gl.attachShader(program, fragShader);
+ gl.attachShader(program, vertShader);
+ gl.linkProgram(program);
+ check$1.linkError(
+ gl,
+ program,
+ stringStore.str(desc.fragId),
+ stringStore.str(desc.vertId),
+ command);
+
+ // -------------------------------
+ // grab uniforms
+ // -------------------------------
+ var numUniforms = gl.getProgramParameter(program, GL_ACTIVE_UNIFORMS);
+ if (config.profile) {
+ desc.stats.uniformsCount = numUniforms;
+ }
+ var uniforms = desc.uniforms;
+ for (i = 0; i < numUniforms; ++i) {
+ info = gl.getActiveUniform(program, i);
+ if (info) {
+ if (info.size > 1) {
+ for (var j = 0; j < info.size; ++j) {
+ var name = info.name.replace('[0]', '[' + j + ']');
+ insertActiveInfo(uniforms, new ActiveInfo(
+ name,
+ stringStore.id(name),
+ gl.getUniformLocation(program, name),
+ info));
+ }
+ } else {
+ insertActiveInfo(uniforms, new ActiveInfo(
+ info.name,
+ stringStore.id(info.name),
+ gl.getUniformLocation(program, info.name),
+ info));
+ }
+ }
+ }
+
+ // -------------------------------
+ // grab attributes
+ // -------------------------------
+ var numAttributes = gl.getProgramParameter(program, GL_ACTIVE_ATTRIBUTES);
+ if (config.profile) {
+ desc.stats.attributesCount = numAttributes;
+ }
+
+ var attributes = desc.attributes;
+ for (i = 0; i < numAttributes; ++i) {
+ info = gl.getActiveAttrib(program, i);
+ if (info) {
+ insertActiveInfo(attributes, new ActiveInfo(
+ info.name,
+ stringStore.id(info.name),
+ gl.getAttribLocation(program, info.name),
+ info));
+ }
+ }
+ }
+
+ if (config.profile) {
+ stats.getMaxUniformsCount = function () {
+ var m = 0;
+ programList.forEach(function (desc) {
+ if (desc.stats.uniformsCount > m) {
+ m = desc.stats.uniformsCount;
+ }
+ });
+ return m
+ };
+
+ stats.getMaxAttributesCount = function () {
+ var m = 0;
+ programList.forEach(function (desc) {
+ if (desc.stats.attributesCount > m) {
+ m = desc.stats.attributesCount;
+ }
+ });
+ return m
+ };
+ }
+
+ function restoreShaders () {
+ fragShaders = {};
+ vertShaders = {};
+ for (var i = 0; i < programList.length; ++i) {
+ linkProgram(programList[i]);
+ }
+ }
+
+ return {
+ clear: function () {
+ var deleteShader = gl.deleteShader.bind(gl);
+ values(fragShaders).forEach(deleteShader);
+ fragShaders = {};
+ values(vertShaders).forEach(deleteShader);
+ vertShaders = {};
+
+ programList.forEach(function (desc) {
+ gl.deleteProgram(desc.program);
+ });
+ programList.length = 0;
+ programCache = {};
+
+ stats.shaderCount = 0;
+ },
+
+ program: function (vertId, fragId, command) {
+ check$1.command(vertId >= 0, 'missing vertex shader', command);
+ check$1.command(fragId >= 0, 'missing fragment shader', command);
+
+ var cache = programCache[fragId];
+ if (!cache) {
+ cache = programCache[fragId] = {};
+ }
+ var program = cache[vertId];
+ if (!program) {
+ program = new REGLProgram(fragId, vertId);
+ stats.shaderCount++;
+
+ linkProgram(program, command);
+ cache[vertId] = program;
+ programList.push(program);
+ }
+ return program
+ },
+
+ restore: restoreShaders,
+
+ shader: getShader,
+
+ frag: -1,
+ vert: -1
+ }
+}
+
+var GL_RGBA$2 = 6408;
+var GL_UNSIGNED_BYTE$6 = 5121;
+var GL_PACK_ALIGNMENT = 0x0D05;
+var GL_FLOAT$6 = 0x1406; // 5126
+
+function wrapReadPixels (
+ gl,
+ framebufferState,
+ reglPoll,
+ context,
+ glAttributes,
+ extensions) {
+ function readPixelsImpl (input) {
+ var type;
+ if (framebufferState.next === null) {
+ check$1(
+ glAttributes.preserveDrawingBuffer,
+ 'you must create a webgl context with "preserveDrawingBuffer":true in order to read pixels from the drawing buffer');
+ type = GL_UNSIGNED_BYTE$6;
+ } else {
+ check$1(
+ framebufferState.next.colorAttachments[0].texture !== null,
+ 'You cannot read from a renderbuffer');
+ type = framebufferState.next.colorAttachments[0].texture._texture.type;
+
+ if (extensions.oes_texture_float) {
+ check$1(
+ type === GL_UNSIGNED_BYTE$6 || type === GL_FLOAT$6,
+ 'Reading from a framebuffer is only allowed for the types \'uint8\' and \'float\'');
+ } else {
+ check$1(
+ type === GL_UNSIGNED_BYTE$6,
+ 'Reading from a framebuffer is only allowed for the type \'uint8\'');
+ }
+ }
+
+ var x = 0;
+ var y = 0;
+ var width = context.framebufferWidth;
+ var height = context.framebufferHeight;
+ var data = null;
+
+ if (isTypedArray(input)) {
+ data = input;
+ } else if (input) {
+ check$1.type(input, 'object', 'invalid arguments to regl.read()');
+ x = input.x | 0;
+ y = input.y | 0;
+ check$1(
+ x >= 0 && x < context.framebufferWidth,
+ 'invalid x offset for regl.read');
+ check$1(
+ y >= 0 && y < context.framebufferHeight,
+ 'invalid y offset for regl.read');
+ width = (input.width || (context.framebufferWidth - x)) | 0;
+ height = (input.height || (context.framebufferHeight - y)) | 0;
+ data = input.data || null;
+ }
+
+ // sanity check input.data
+ if (data) {
+ if (type === GL_UNSIGNED_BYTE$6) {
+ check$1(
+ data instanceof Uint8Array,
+ 'buffer must be \'Uint8Array\' when reading from a framebuffer of type \'uint8\'');
+ } else if (type === GL_FLOAT$6) {
+ check$1(
+ data instanceof Float32Array,
+ 'buffer must be \'Float32Array\' when reading from a framebuffer of type \'float\'');
+ }
+ }
+
+ check$1(
+ width > 0 && width + x <= context.framebufferWidth,
+ 'invalid width for read pixels');
+ check$1(
+ height > 0 && height + y <= context.framebufferHeight,
+ 'invalid height for read pixels');
+
+ // Update WebGL state
+ reglPoll();
+
+ // Compute size
+ var size = width * height * 4;
+
+ // Allocate data
+ if (!data) {
+ if (type === GL_UNSIGNED_BYTE$6) {
+ data = new Uint8Array(size);
+ } else if (type === GL_FLOAT$6) {
+ data = data || new Float32Array(size);
+ }
+ }
+
+ // Type check
+ check$1.isTypedArray(data, 'data buffer for regl.read() must be a typedarray');
+ check$1(data.byteLength >= size, 'data buffer for regl.read() too small');
+
+ // Run read pixels
+ gl.pixelStorei(GL_PACK_ALIGNMENT, 4);
+ gl.readPixels(x, y, width, height, GL_RGBA$2,
+ type,
+ data);
+
+ return data
+ }
+
+ function readPixelsFBO (options) {
+ var result;
+ framebufferState.setFBO({
+ framebuffer: options.framebuffer
+ }, function () {
+ result = readPixelsImpl(options);
+ });
+ return result
+ }
+
+ function readPixels (options) {
+ if (!options || !('framebuffer' in options)) {
+ return readPixelsImpl(options)
+ } else {
+ return readPixelsFBO(options)
+ }
+ }
+
+ return readPixels
+}
+
+function slice (x) {
+ return Array.prototype.slice.call(x)
+}
+
+function join (x) {
+ return slice(x).join('')
+}
+
+function createEnvironment () {
+ // Unique variable id counter
+ var varCounter = 0;
+
+ // Linked values are passed from this scope into the generated code block
+ // Calling link() passes a value into the generated scope and returns
+ // the variable name which it is bound to
+ var linkedNames = [];
+ var linkedValues = [];
+ function link (value) {
+ for (var i = 0; i < linkedValues.length; ++i) {
+ if (linkedValues[i] === value) {
+ return linkedNames[i]
+ }
+ }
+
+ var name = 'g' + (varCounter++);
+ linkedNames.push(name);
+ linkedValues.push(value);
+ return name
+ }
+
+ // create a code block
+ function block () {
+ var code = [];
+ function push () {
+ code.push.apply(code, slice(arguments));
+ }
+
+ var vars = [];
+ function def () {
+ var name = 'v' + (varCounter++);
+ vars.push(name);
+
+ if (arguments.length > 0) {
+ code.push(name, '=');
+ code.push.apply(code, slice(arguments));
+ code.push(';');
+ }
+
+ return name
+ }
+
+ return extend(push, {
+ def: def,
+ toString: function () {
+ return join([
+ (vars.length > 0 ? 'var ' + vars + ';' : ''),
+ join(code)
+ ])
+ }
+ })
+ }
+
+ function scope () {
+ var entry = block();
+ var exit = block();
+
+ var entryToString = entry.toString;
+ var exitToString = exit.toString;
+
+ function save (object, prop) {
+ exit(object, prop, '=', entry.def(object, prop), ';');
+ }
+
+ return extend(function () {
+ entry.apply(entry, slice(arguments));
+ }, {
+ def: entry.def,
+ entry: entry,
+ exit: exit,
+ save: save,
+ set: function (object, prop, value) {
+ save(object, prop);
+ entry(object, prop, '=', value, ';');
+ },
+ toString: function () {
+ return entryToString() + exitToString()
+ }
+ })
+ }
+
+ function conditional () {
+ var pred = join(arguments);
+ var thenBlock = scope();
+ var elseBlock = scope();
+
+ var thenToString = thenBlock.toString;
+ var elseToString = elseBlock.toString;
+
+ return extend(thenBlock, {
+ then: function () {
+ thenBlock.apply(thenBlock, slice(arguments));
+ return this
+ },
+ else: function () {
+ elseBlock.apply(elseBlock, slice(arguments));
+ return this
+ },
+ toString: function () {
+ var elseClause = elseToString();
+ if (elseClause) {
+ elseClause = 'else{' + elseClause + '}';
+ }
+ return join([
+ 'if(', pred, '){',
+ thenToString(),
+ '}', elseClause
+ ])
+ }
+ })
+ }
+
+ // procedure list
+ var globalBlock = block();
+ var procedures = {};
+ function proc (name, count) {
+ var args = [];
+ function arg () {
+ var name = 'a' + args.length;
+ args.push(name);
+ return name
+ }
+
+ count = count || 0;
+ for (var i = 0; i < count; ++i) {
+ arg();
+ }
+
+ var body = scope();
+ var bodyToString = body.toString;
+
+ var result = procedures[name] = extend(body, {
+ arg: arg,
+ toString: function () {
+ return join([
+ 'function(', args.join(), '){',
+ bodyToString(),
+ '}'
+ ])
+ }
+ });
+
+ return result
+ }
+
+ function compile () {
+ var code = ['"use strict";',
+ globalBlock,
+ 'return {'];
+ Object.keys(procedures).forEach(function (name) {
+ code.push('"', name, '":', procedures[name].toString(), ',');
+ });
+ code.push('}');
+ var src = join(code)
+ .replace(/;/g, ';\n')
+ .replace(/}/g, '}\n')
+ .replace(/{/g, '{\n');
+ var proc = Function.apply(null, linkedNames.concat(src));
+ return proc.apply(null, linkedValues)
+ }
+
+ return {
+ global: globalBlock,
+ link: link,
+ block: block,
+ proc: proc,
+ scope: scope,
+ cond: conditional,
+ compile: compile
+ }
+}
+
+// "cute" names for vector components
+var CUTE_COMPONENTS = 'xyzw'.split('');
+
+var GL_UNSIGNED_BYTE$7 = 5121;
+
+var ATTRIB_STATE_POINTER = 1;
+var ATTRIB_STATE_CONSTANT = 2;
+
+var DYN_FUNC$1 = 0;
+var DYN_PROP$1 = 1;
+var DYN_CONTEXT$1 = 2;
+var DYN_STATE$1 = 3;
+var DYN_THUNK = 4;
+
+var S_DITHER = 'dither';
+var S_BLEND_ENABLE = 'blend.enable';
+var S_BLEND_COLOR = 'blend.color';
+var S_BLEND_EQUATION = 'blend.equation';
+var S_BLEND_FUNC = 'blend.func';
+var S_DEPTH_ENABLE = 'depth.enable';
+var S_DEPTH_FUNC = 'depth.func';
+var S_DEPTH_RANGE = 'depth.range';
+var S_DEPTH_MASK = 'depth.mask';
+var S_COLOR_MASK = 'colorMask';
+var S_CULL_ENABLE = 'cull.enable';
+var S_CULL_FACE = 'cull.face';
+var S_FRONT_FACE = 'frontFace';
+var S_LINE_WIDTH = 'lineWidth';
+var S_POLYGON_OFFSET_ENABLE = 'polygonOffset.enable';
+var S_POLYGON_OFFSET_OFFSET = 'polygonOffset.offset';
+var S_SAMPLE_ALPHA = 'sample.alpha';
+var S_SAMPLE_ENABLE = 'sample.enable';
+var S_SAMPLE_COVERAGE = 'sample.coverage';
+var S_STENCIL_ENABLE = 'stencil.enable';
+var S_STENCIL_MASK = 'stencil.mask';
+var S_STENCIL_FUNC = 'stencil.func';
+var S_STENCIL_OPFRONT = 'stencil.opFront';
+var S_STENCIL_OPBACK = 'stencil.opBack';
+var S_SCISSOR_ENABLE = 'scissor.enable';
+var S_SCISSOR_BOX = 'scissor.box';
+var S_VIEWPORT = 'viewport';
+
+var S_PROFILE = 'profile';
+
+var S_FRAMEBUFFER = 'framebuffer';
+var S_VERT = 'vert';
+var S_FRAG = 'frag';
+var S_ELEMENTS = 'elements';
+var S_PRIMITIVE = 'primitive';
+var S_COUNT = 'count';
+var S_OFFSET = 'offset';
+var S_INSTANCES = 'instances';
+
+var SUFFIX_WIDTH = 'Width';
+var SUFFIX_HEIGHT = 'Height';
+
+var S_FRAMEBUFFER_WIDTH = S_FRAMEBUFFER + SUFFIX_WIDTH;
+var S_FRAMEBUFFER_HEIGHT = S_FRAMEBUFFER + SUFFIX_HEIGHT;
+var S_VIEWPORT_WIDTH = S_VIEWPORT + SUFFIX_WIDTH;
+var S_VIEWPORT_HEIGHT = S_VIEWPORT + SUFFIX_HEIGHT;
+var S_DRAWINGBUFFER = 'drawingBuffer';
+var S_DRAWINGBUFFER_WIDTH = S_DRAWINGBUFFER + SUFFIX_WIDTH;
+var S_DRAWINGBUFFER_HEIGHT = S_DRAWINGBUFFER + SUFFIX_HEIGHT;
+
+var NESTED_OPTIONS = [
+ S_BLEND_FUNC,
+ S_BLEND_EQUATION,
+ S_STENCIL_FUNC,
+ S_STENCIL_OPFRONT,
+ S_STENCIL_OPBACK,
+ S_SAMPLE_COVERAGE,
+ S_VIEWPORT,
+ S_SCISSOR_BOX,
+ S_POLYGON_OFFSET_OFFSET
+];
+
+var GL_ARRAY_BUFFER$1 = 34962;
+var GL_ELEMENT_ARRAY_BUFFER$1 = 34963;
+
+var GL_FRAGMENT_SHADER$1 = 35632;
+var GL_VERTEX_SHADER$1 = 35633;
+
+var GL_TEXTURE_2D$2 = 0x0DE1;
+var GL_TEXTURE_CUBE_MAP$1 = 0x8513;
+
+var GL_CULL_FACE = 0x0B44;
+var GL_BLEND = 0x0BE2;
+var GL_DITHER = 0x0BD0;
+var GL_STENCIL_TEST = 0x0B90;
+var GL_DEPTH_TEST = 0x0B71;
+var GL_SCISSOR_TEST = 0x0C11;
+var GL_POLYGON_OFFSET_FILL = 0x8037;
+var GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
+var GL_SAMPLE_COVERAGE = 0x80A0;
+
+var GL_FLOAT$7 = 5126;
+var GL_FLOAT_VEC2 = 35664;
+var GL_FLOAT_VEC3 = 35665;
+var GL_FLOAT_VEC4 = 35666;
+var GL_INT$3 = 5124;
+var GL_INT_VEC2 = 35667;
+var GL_INT_VEC3 = 35668;
+var GL_INT_VEC4 = 35669;
+var GL_BOOL = 35670;
+var GL_BOOL_VEC2 = 35671;
+var GL_BOOL_VEC3 = 35672;
+var GL_BOOL_VEC4 = 35673;
+var GL_FLOAT_MAT2 = 35674;
+var GL_FLOAT_MAT3 = 35675;
+var GL_FLOAT_MAT4 = 35676;
+var GL_SAMPLER_2D = 35678;
+var GL_SAMPLER_CUBE = 35680;
+
+var GL_TRIANGLES$1 = 4;
+
+var GL_FRONT = 1028;
+var GL_BACK = 1029;
+var GL_CW = 0x0900;
+var GL_CCW = 0x0901;
+var GL_MIN_EXT = 0x8007;
+var GL_MAX_EXT = 0x8008;
+var GL_ALWAYS = 519;
+var GL_KEEP = 7680;
+var GL_ZERO = 0;
+var GL_ONE = 1;
+var GL_FUNC_ADD = 0x8006;
+var GL_LESS = 513;
+
+var GL_FRAMEBUFFER$1 = 0x8D40;
+var GL_COLOR_ATTACHMENT0$1 = 0x8CE0;
+
+var blendFuncs = {
+ '0': 0,
+ '1': 1,
+ 'zero': 0,
+ 'one': 1,
+ 'src color': 768,
+ 'one minus src color': 769,
+ 'src alpha': 770,
+ 'one minus src alpha': 771,
+ 'dst color': 774,
+ 'one minus dst color': 775,
+ 'dst alpha': 772,
+ 'one minus dst alpha': 773,
+ 'constant color': 32769,
+ 'one minus constant color': 32770,
+ 'constant alpha': 32771,
+ 'one minus constant alpha': 32772,
+ 'src alpha saturate': 776
+};
+
+// There are invalid values for srcRGB and dstRGB. See:
+// https://www.khronos.org/registry/webgl/specs/1.0/#6.13
+// https://github.com/KhronosGroup/WebGL/blob/0d3201f5f7ec3c0060bc1f04077461541f1987b9/conformance-suites/1.0.3/conformance/misc/webgl-specific.html#L56
+var invalidBlendCombinations = [
+ 'constant color, constant alpha',
+ 'one minus constant color, constant alpha',
+ 'constant color, one minus constant alpha',
+ 'one minus constant color, one minus constant alpha',
+ 'constant alpha, constant color',
+ 'constant alpha, one minus constant color',
+ 'one minus constant alpha, constant color',
+ 'one minus constant alpha, one minus constant color'
+];
+
+var compareFuncs = {
+ 'never': 512,
+ 'less': 513,
+ '<': 513,
+ 'equal': 514,
+ '=': 514,
+ '==': 514,
+ '===': 514,
+ 'lequal': 515,
+ '<=': 515,
+ 'greater': 516,
+ '>': 516,
+ 'notequal': 517,
+ '!=': 517,
+ '!==': 517,
+ 'gequal': 518,
+ '>=': 518,
+ 'always': 519
+};
+
+var stencilOps = {
+ '0': 0,
+ 'zero': 0,
+ 'keep': 7680,
+ 'replace': 7681,
+ 'increment': 7682,
+ 'decrement': 7683,
+ 'increment wrap': 34055,
+ 'decrement wrap': 34056,
+ 'invert': 5386
+};
+
+var shaderType = {
+ 'frag': GL_FRAGMENT_SHADER$1,
+ 'vert': GL_VERTEX_SHADER$1
+};
+
+var orientationType = {
+ 'cw': GL_CW,
+ 'ccw': GL_CCW
+};
+
+function isBufferArgs (x) {
+ return Array.isArray(x) ||
+ isTypedArray(x) ||
+ isNDArrayLike(x)
+}
+
+// Make sure viewport is processed first
+function sortState (state) {
+ return state.sort(function (a, b) {
+ if (a === S_VIEWPORT) {
+ return -1
+ } else if (b === S_VIEWPORT) {
+ return 1
+ }
+ return (a < b) ? -1 : 1
+ })
+}
+
+function Declaration (thisDep, contextDep, propDep, append) {
+ this.thisDep = thisDep;
+ this.contextDep = contextDep;
+ this.propDep = propDep;
+ this.append = append;
+}
+
+function isStatic (decl) {
+ return decl && !(decl.thisDep || decl.contextDep || decl.propDep)
+}
+
+function createStaticDecl (append) {
+ return new Declaration(false, false, false, append)
+}
+
+function createDynamicDecl (dyn, append) {
+ var type = dyn.type;
+ if (type === DYN_FUNC$1) {
+ var numArgs = dyn.data.length;
+ return new Declaration(
+ true,
+ numArgs >= 1,
+ numArgs >= 2,
+ append)
+ } else if (type === DYN_THUNK) {
+ var data = dyn.data;
+ return new Declaration(
+ data.thisDep,
+ data.contextDep,
+ data.propDep,
+ append)
+ } else {
+ return new Declaration(
+ type === DYN_STATE$1,
+ type === DYN_CONTEXT$1,
+ type === DYN_PROP$1,
+ append)
+ }
+}
+
+var SCOPE_DECL = new Declaration(false, false, false, function () {});
+
+function reglCore (
+ gl,
+ stringStore,
+ extensions,
+ limits,
+ bufferState,
+ elementState,
+ textureState,
+ framebufferState,
+ uniformState,
+ attributeState,
+ shaderState,
+ drawState,
+ contextState,
+ timer,
+ config) {
+ var AttributeRecord = attributeState.Record;
+
+ var blendEquations = {
+ 'add': 32774,
+ 'subtract': 32778,
+ 'reverse subtract': 32779
+ };
+ if (extensions.ext_blend_minmax) {
+ blendEquations.min = GL_MIN_EXT;
+ blendEquations.max = GL_MAX_EXT;
+ }
+
+ var extInstancing = extensions.angle_instanced_arrays;
+ var extDrawBuffers = extensions.webgl_draw_buffers;
+
+ // ===================================================
+ // ===================================================
+ // WEBGL STATE
+ // ===================================================
+ // ===================================================
+ var currentState = {
+ dirty: true,
+ profile: config.profile
+ };
+ var nextState = {};
+ var GL_STATE_NAMES = [];
+ var GL_FLAGS = {};
+ var GL_VARIABLES = {};
+
+ function propName (name) {
+ return name.replace('.', '_')
+ }
+
+ function stateFlag (sname, cap, init) {
+ var name = propName(sname);
+ GL_STATE_NAMES.push(sname);
+ nextState[name] = currentState[name] = !!init;
+ GL_FLAGS[name] = cap;
+ }
+
+ function stateVariable (sname, func, init) {
+ var name = propName(sname);
+ GL_STATE_NAMES.push(sname);
+ if (Array.isArray(init)) {
+ currentState[name] = init.slice();
+ nextState[name] = init.slice();
+ } else {
+ currentState[name] = nextState[name] = init;
+ }
+ GL_VARIABLES[name] = func;
+ }
+
+ // Dithering
+ stateFlag(S_DITHER, GL_DITHER);
+
+ // Blending
+ stateFlag(S_BLEND_ENABLE, GL_BLEND);
+ stateVariable(S_BLEND_COLOR, 'blendColor', [0, 0, 0, 0]);
+ stateVariable(S_BLEND_EQUATION, 'blendEquationSeparate',
+ [GL_FUNC_ADD, GL_FUNC_ADD]);
+ stateVariable(S_BLEND_FUNC, 'blendFuncSeparate',
+ [GL_ONE, GL_ZERO, GL_ONE, GL_ZERO]);
+
+ // Depth
+ stateFlag(S_DEPTH_ENABLE, GL_DEPTH_TEST, true);
+ stateVariable(S_DEPTH_FUNC, 'depthFunc', GL_LESS);
+ stateVariable(S_DEPTH_RANGE, 'depthRange', [0, 1]);
+ stateVariable(S_DEPTH_MASK, 'depthMask', true);
+
+ // Color mask
+ stateVariable(S_COLOR_MASK, S_COLOR_MASK, [true, true, true, true]);
+
+ // Face culling
+ stateFlag(S_CULL_ENABLE, GL_CULL_FACE);
+ stateVariable(S_CULL_FACE, 'cullFace', GL_BACK);
+
+ // Front face orientation
+ stateVariable(S_FRONT_FACE, S_FRONT_FACE, GL_CCW);
+
+ // Line width
+ stateVariable(S_LINE_WIDTH, S_LINE_WIDTH, 1);
+
+ // Polygon offset
+ stateFlag(S_POLYGON_OFFSET_ENABLE, GL_POLYGON_OFFSET_FILL);
+ stateVariable(S_POLYGON_OFFSET_OFFSET, 'polygonOffset', [0, 0]);
+
+ // Sample coverage
+ stateFlag(S_SAMPLE_ALPHA, GL_SAMPLE_ALPHA_TO_COVERAGE);
+ stateFlag(S_SAMPLE_ENABLE, GL_SAMPLE_COVERAGE);
+ stateVariable(S_SAMPLE_COVERAGE, 'sampleCoverage', [1, false]);
+
+ // Stencil
+ stateFlag(S_STENCIL_ENABLE, GL_STENCIL_TEST);
+ stateVariable(S_STENCIL_MASK, 'stencilMask', -1);
+ stateVariable(S_STENCIL_FUNC, 'stencilFunc', [GL_ALWAYS, 0, -1]);
+ stateVariable(S_STENCIL_OPFRONT, 'stencilOpSeparate',
+ [GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP]);
+ stateVariable(S_STENCIL_OPBACK, 'stencilOpSeparate',
+ [GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP]);
+
+ // Scissor
+ stateFlag(S_SCISSOR_ENABLE, GL_SCISSOR_TEST);
+ stateVariable(S_SCISSOR_BOX, 'scissor',
+ [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]);
+
+ // Viewport
+ stateVariable(S_VIEWPORT, S_VIEWPORT,
+ [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]);
+
+ // ===================================================
+ // ===================================================
+ // ENVIRONMENT
+ // ===================================================
+ // ===================================================
+ var sharedState = {
+ gl: gl,
+ context: contextState,
+ strings: stringStore,
+ next: nextState,
+ current: currentState,
+ draw: drawState,
+ elements: elementState,
+ buffer: bufferState,
+ shader: shaderState,
+ attributes: attributeState.state,
+ uniforms: uniformState,
+ framebuffer: framebufferState,
+ extensions: extensions,
+
+ timer: timer,
+ isBufferArgs: isBufferArgs
+ };
+
+ var sharedConstants = {
+ primTypes: primTypes,
+ compareFuncs: compareFuncs,
+ blendFuncs: blendFuncs,
+ blendEquations: blendEquations,
+ stencilOps: stencilOps,
+ glTypes: glTypes,
+ orientationType: orientationType
+ };
+
+ check$1.optional(function () {
+ sharedState.isArrayLike = isArrayLike;
+ });
+
+ if (extDrawBuffers) {
+ sharedConstants.backBuffer = [GL_BACK];
+ sharedConstants.drawBuffer = loop(limits.maxDrawbuffers, function (i) {
+ if (i === 0) {
+ return [0]
+ }
+ return loop(i, function (j) {
+ return GL_COLOR_ATTACHMENT0$1 + j
+ })
+ });
+ }
+
+ var drawCallCounter = 0;
+ function createREGLEnvironment () {
+ var env = createEnvironment();
+ var link = env.link;
+ var global = env.global;
+ env.id = drawCallCounter++;
+
+ env.batchId = '0';
+
+ // link shared state
+ var SHARED = link(sharedState);
+ var shared = env.shared = {
+ props: 'a0'
+ };
+ Object.keys(sharedState).forEach(function (prop) {
+ shared[prop] = global.def(SHARED, '.', prop);
+ });
+
+ // Inject runtime assertion stuff for debug builds
+ check$1.optional(function () {
+ env.CHECK = link(check$1);
+ env.commandStr = check$1.guessCommand();
+ env.command = link(env.commandStr);
+ env.assert = function (block, pred, message) {
+ block(
+ 'if(!(', pred, '))',
+ this.CHECK, '.commandRaise(', link(message), ',', this.command, ');');
+ };
+
+ sharedConstants.invalidBlendCombinations = invalidBlendCombinations;
+ });
+
+ // Copy GL state variables over
+ var nextVars = env.next = {};
+ var currentVars = env.current = {};
+ Object.keys(GL_VARIABLES).forEach(function (variable) {
+ if (Array.isArray(currentState[variable])) {
+ nextVars[variable] = global.def(shared.next, '.', variable);
+ currentVars[variable] = global.def(shared.current, '.', variable);
+ }
+ });
+
+ // Initialize shared constants
+ var constants = env.constants = {};
+ Object.keys(sharedConstants).forEach(function (name) {
+ constants[name] = global.def(JSON.stringify(sharedConstants[name]));
+ });
+
+ // Helper function for calling a block
+ env.invoke = function (block, x) {
+ switch (x.type) {
+ case DYN_FUNC$1:
+ var argList = [
+ 'this',
+ shared.context,
+ shared.props,
+ env.batchId
+ ];
+ return block.def(
+ link(x.data), '.call(',
+ argList.slice(0, Math.max(x.data.length + 1, 4)),
+ ')')
+ case DYN_PROP$1:
+ return block.def(shared.props, x.data)
+ case DYN_CONTEXT$1:
+ return block.def(shared.context, x.data)
+ case DYN_STATE$1:
+ return block.def('this', x.data)
+ case DYN_THUNK:
+ x.data.append(env, block);
+ return x.data.ref
+ }
+ };
+
+ env.attribCache = {};
+
+ var scopeAttribs = {};
+ env.scopeAttrib = function (name) {
+ var id = stringStore.id(name);
+ if (id in scopeAttribs) {
+ return scopeAttribs[id]
+ }
+ var binding = attributeState.scope[id];
+ if (!binding) {
+ binding = attributeState.scope[id] = new AttributeRecord();
+ }
+ var result = scopeAttribs[id] = link(binding);
+ return result
+ };
+
+ return env
+ }
+
+ // ===================================================
+ // ===================================================
+ // PARSING
+ // ===================================================
+ // ===================================================
+ function parseProfile (options) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ var profileEnable;
+ if (S_PROFILE in staticOptions) {
+ var value = !!staticOptions[S_PROFILE];
+ profileEnable = createStaticDecl(function (env, scope) {
+ return value
+ });
+ profileEnable.enable = value;
+ } else if (S_PROFILE in dynamicOptions) {
+ var dyn = dynamicOptions[S_PROFILE];
+ profileEnable = createDynamicDecl(dyn, function (env, scope) {
+ return env.invoke(scope, dyn)
+ });
+ }
+
+ return profileEnable
+ }
+
+ function parseFramebuffer (options, env) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ if (S_FRAMEBUFFER in staticOptions) {
+ var framebuffer = staticOptions[S_FRAMEBUFFER];
+ if (framebuffer) {
+ framebuffer = framebufferState.getFramebuffer(framebuffer);
+ check$1.command(framebuffer, 'invalid framebuffer object');
+ return createStaticDecl(function (env, block) {
+ var FRAMEBUFFER = env.link(framebuffer);
+ var shared = env.shared;
+ block.set(
+ shared.framebuffer,
+ '.next',
+ FRAMEBUFFER);
+ var CONTEXT = shared.context;
+ block.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_WIDTH,
+ FRAMEBUFFER + '.width');
+ block.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_HEIGHT,
+ FRAMEBUFFER + '.height');
+ return FRAMEBUFFER
+ })
+ } else {
+ return createStaticDecl(function (env, scope) {
+ var shared = env.shared;
+ scope.set(
+ shared.framebuffer,
+ '.next',
+ 'null');
+ var CONTEXT = shared.context;
+ scope.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_WIDTH,
+ CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH);
+ scope.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_HEIGHT,
+ CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT);
+ return 'null'
+ })
+ }
+ } else if (S_FRAMEBUFFER in dynamicOptions) {
+ var dyn = dynamicOptions[S_FRAMEBUFFER];
+ return createDynamicDecl(dyn, function (env, scope) {
+ var FRAMEBUFFER_FUNC = env.invoke(scope, dyn);
+ var shared = env.shared;
+ var FRAMEBUFFER_STATE = shared.framebuffer;
+ var FRAMEBUFFER = scope.def(
+ FRAMEBUFFER_STATE, '.getFramebuffer(', FRAMEBUFFER_FUNC, ')');
+
+ check$1.optional(function () {
+ env.assert(scope,
+ '!' + FRAMEBUFFER_FUNC + '||' + FRAMEBUFFER,
+ 'invalid framebuffer object');
+ });
+
+ scope.set(
+ FRAMEBUFFER_STATE,
+ '.next',
+ FRAMEBUFFER);
+ var CONTEXT = shared.context;
+ scope.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_WIDTH,
+ FRAMEBUFFER + '?' + FRAMEBUFFER + '.width:' +
+ CONTEXT + '.' + S_DRAWINGBUFFER_WIDTH);
+ scope.set(
+ CONTEXT,
+ '.' + S_FRAMEBUFFER_HEIGHT,
+ FRAMEBUFFER +
+ '?' + FRAMEBUFFER + '.height:' +
+ CONTEXT + '.' + S_DRAWINGBUFFER_HEIGHT);
+ return FRAMEBUFFER
+ })
+ } else {
+ return null
+ }
+ }
+
+ function parseViewportScissor (options, framebuffer, env) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ function parseBox (param) {
+ if (param in staticOptions) {
+ var box = staticOptions[param];
+ check$1.commandType(box, 'object', 'invalid ' + param, env.commandStr);
+
+ var isStatic = true;
+ var x = box.x | 0;
+ var y = box.y | 0;
+ var w, h;
+ if ('width' in box) {
+ w = box.width | 0;
+ check$1.command(w >= 0, 'invalid ' + param, env.commandStr);
+ } else {
+ isStatic = false;
+ }
+ if ('height' in box) {
+ h = box.height | 0;
+ check$1.command(h >= 0, 'invalid ' + param, env.commandStr);
+ } else {
+ isStatic = false;
+ }
+
+ return new Declaration(
+ !isStatic && framebuffer && framebuffer.thisDep,
+ !isStatic && framebuffer && framebuffer.contextDep,
+ !isStatic && framebuffer && framebuffer.propDep,
+ function (env, scope) {
+ var CONTEXT = env.shared.context;
+ var BOX_W = w;
+ if (!('width' in box)) {
+ BOX_W = scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', x);
+ }
+ var BOX_H = h;
+ if (!('height' in box)) {
+ BOX_H = scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', y);
+ }
+ return [x, y, BOX_W, BOX_H]
+ })
+ } else if (param in dynamicOptions) {
+ var dynBox = dynamicOptions[param];
+ var result = createDynamicDecl(dynBox, function (env, scope) {
+ var BOX = env.invoke(scope, dynBox);
+
+ check$1.optional(function () {
+ env.assert(scope,
+ BOX + '&&typeof ' + BOX + '==="object"',
+ 'invalid ' + param);
+ });
+
+ var CONTEXT = env.shared.context;
+ var BOX_X = scope.def(BOX, '.x|0');
+ var BOX_Y = scope.def(BOX, '.y|0');
+ var BOX_W = scope.def(
+ '"width" in ', BOX, '?', BOX, '.width|0:',
+ '(', CONTEXT, '.', S_FRAMEBUFFER_WIDTH, '-', BOX_X, ')');
+ var BOX_H = scope.def(
+ '"height" in ', BOX, '?', BOX, '.height|0:',
+ '(', CONTEXT, '.', S_FRAMEBUFFER_HEIGHT, '-', BOX_Y, ')');
+
+ check$1.optional(function () {
+ env.assert(scope,
+ BOX_W + '>=0&&' +
+ BOX_H + '>=0',
+ 'invalid ' + param);
+ });
+
+ return [BOX_X, BOX_Y, BOX_W, BOX_H]
+ });
+ if (framebuffer) {
+ result.thisDep = result.thisDep || framebuffer.thisDep;
+ result.contextDep = result.contextDep || framebuffer.contextDep;
+ result.propDep = result.propDep || framebuffer.propDep;
+ }
+ return result
+ } else if (framebuffer) {
+ return new Declaration(
+ framebuffer.thisDep,
+ framebuffer.contextDep,
+ framebuffer.propDep,
+ function (env, scope) {
+ var CONTEXT = env.shared.context;
+ return [
+ 0, 0,
+ scope.def(CONTEXT, '.', S_FRAMEBUFFER_WIDTH),
+ scope.def(CONTEXT, '.', S_FRAMEBUFFER_HEIGHT)]
+ })
+ } else {
+ return null
+ }
+ }
+
+ var viewport = parseBox(S_VIEWPORT);
+
+ if (viewport) {
+ var prevViewport = viewport;
+ viewport = new Declaration(
+ viewport.thisDep,
+ viewport.contextDep,
+ viewport.propDep,
+ function (env, scope) {
+ var VIEWPORT = prevViewport.append(env, scope);
+ var CONTEXT = env.shared.context;
+ scope.set(
+ CONTEXT,
+ '.' + S_VIEWPORT_WIDTH,
+ VIEWPORT[2]);
+ scope.set(
+ CONTEXT,
+ '.' + S_VIEWPORT_HEIGHT,
+ VIEWPORT[3]);
+ return VIEWPORT
+ });
+ }
+
+ return {
+ viewport: viewport,
+ scissor_box: parseBox(S_SCISSOR_BOX)
+ }
+ }
+
+ function parseProgram (options) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ function parseShader (name) {
+ if (name in staticOptions) {
+ var id = stringStore.id(staticOptions[name]);
+ check$1.optional(function () {
+ shaderState.shader(shaderType[name], id, check$1.guessCommand());
+ });
+ var result = createStaticDecl(function () {
+ return id
+ });
+ result.id = id;
+ return result
+ } else if (name in dynamicOptions) {
+ var dyn = dynamicOptions[name];
+ return createDynamicDecl(dyn, function (env, scope) {
+ var str = env.invoke(scope, dyn);
+ var id = scope.def(env.shared.strings, '.id(', str, ')');
+ check$1.optional(function () {
+ scope(
+ env.shared.shader, '.shader(',
+ shaderType[name], ',',
+ id, ',',
+ env.command, ');');
+ });
+ return id
+ })
+ }
+ return null
+ }
+
+ var frag = parseShader(S_FRAG);
+ var vert = parseShader(S_VERT);
+
+ var program = null;
+ var progVar;
+ if (isStatic(frag) && isStatic(vert)) {
+ program = shaderState.program(vert.id, frag.id);
+ progVar = createStaticDecl(function (env, scope) {
+ return env.link(program)
+ });
+ } else {
+ progVar = new Declaration(
+ (frag && frag.thisDep) || (vert && vert.thisDep),
+ (frag && frag.contextDep) || (vert && vert.contextDep),
+ (frag && frag.propDep) || (vert && vert.propDep),
+ function (env, scope) {
+ var SHADER_STATE = env.shared.shader;
+ var fragId;
+ if (frag) {
+ fragId = frag.append(env, scope);
+ } else {
+ fragId = scope.def(SHADER_STATE, '.', S_FRAG);
+ }
+ var vertId;
+ if (vert) {
+ vertId = vert.append(env, scope);
+ } else {
+ vertId = scope.def(SHADER_STATE, '.', S_VERT);
+ }
+ var progDef = SHADER_STATE + '.program(' + vertId + ',' + fragId;
+ check$1.optional(function () {
+ progDef += ',' + env.command;
+ });
+ return scope.def(progDef + ')')
+ });
+ }
+
+ return {
+ frag: frag,
+ vert: vert,
+ progVar: progVar,
+ program: program
+ }
+ }
+
+ function parseDraw (options, env) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ function parseElements () {
+ if (S_ELEMENTS in staticOptions) {
+ var elements = staticOptions[S_ELEMENTS];
+ if (isBufferArgs(elements)) {
+ elements = elementState.getElements(elementState.create(elements, true));
+ } else if (elements) {
+ elements = elementState.getElements(elements);
+ check$1.command(elements, 'invalid elements', env.commandStr);
+ }
+ var result = createStaticDecl(function (env, scope) {
+ if (elements) {
+ var result = env.link(elements);
+ env.ELEMENTS = result;
+ return result
+ }
+ env.ELEMENTS = null;
+ return null
+ });
+ result.value = elements;
+ return result
+ } else if (S_ELEMENTS in dynamicOptions) {
+ var dyn = dynamicOptions[S_ELEMENTS];
+ return createDynamicDecl(dyn, function (env, scope) {
+ var shared = env.shared;
+
+ var IS_BUFFER_ARGS = shared.isBufferArgs;
+ var ELEMENT_STATE = shared.elements;
+
+ var elementDefn = env.invoke(scope, dyn);
+ var elements = scope.def('null');
+ var elementStream = scope.def(IS_BUFFER_ARGS, '(', elementDefn, ')');
+
+ var ifte = env.cond(elementStream)
+ .then(elements, '=', ELEMENT_STATE, '.createStream(', elementDefn, ');')
+ .else(elements, '=', ELEMENT_STATE, '.getElements(', elementDefn, ');');
+
+ check$1.optional(function () {
+ env.assert(ifte.else,
+ '!' + elementDefn + '||' + elements,
+ 'invalid elements');
+ });
+
+ scope.entry(ifte);
+ scope.exit(
+ env.cond(elementStream)
+ .then(ELEMENT_STATE, '.destroyStream(', elements, ');'));
+
+ env.ELEMENTS = elements;
+
+ return elements
+ })
+ }
+
+ return null
+ }
+
+ var elements = parseElements();
+
+ function parsePrimitive () {
+ if (S_PRIMITIVE in staticOptions) {
+ var primitive = staticOptions[S_PRIMITIVE];
+ check$1.commandParameter(primitive, primTypes, 'invalid primitve', env.commandStr);
+ return createStaticDecl(function (env, scope) {
+ return primTypes[primitive]
+ })
+ } else if (S_PRIMITIVE in dynamicOptions) {
+ var dynPrimitive = dynamicOptions[S_PRIMITIVE];
+ return createDynamicDecl(dynPrimitive, function (env, scope) {
+ var PRIM_TYPES = env.constants.primTypes;
+ var prim = env.invoke(scope, dynPrimitive);
+ check$1.optional(function () {
+ env.assert(scope,
+ prim + ' in ' + PRIM_TYPES,
+ 'invalid primitive, must be one of ' + Object.keys(primTypes));
+ });
+ return scope.def(PRIM_TYPES, '[', prim, ']')
+ })
+ } else if (elements) {
+ if (isStatic(elements)) {
+ if (elements.value) {
+ return createStaticDecl(function (env, scope) {
+ return scope.def(env.ELEMENTS, '.primType')
+ })
+ } else {
+ return createStaticDecl(function () {
+ return GL_TRIANGLES$1
+ })
+ }
+ } else {
+ return new Declaration(
+ elements.thisDep,
+ elements.contextDep,
+ elements.propDep,
+ function (env, scope) {
+ var elements = env.ELEMENTS;
+ return scope.def(elements, '?', elements, '.primType:', GL_TRIANGLES$1)
+ })
+ }
+ }
+ return null
+ }
+
+ function parseParam (param, isOffset) {
+ if (param in staticOptions) {
+ var value = staticOptions[param] | 0;
+ check$1.command(!isOffset || value >= 0, 'invalid ' + param, env.commandStr);
+ return createStaticDecl(function (env, scope) {
+ if (isOffset) {
+ env.OFFSET = value;
+ }
+ return value
+ })
+ } else if (param in dynamicOptions) {
+ var dynValue = dynamicOptions[param];
+ return createDynamicDecl(dynValue, function (env, scope) {
+ var result = env.invoke(scope, dynValue);
+ if (isOffset) {
+ env.OFFSET = result;
+ check$1.optional(function () {
+ env.assert(scope,
+ result + '>=0',
+ 'invalid ' + param);
+ });
+ }
+ return result
+ })
+ } else if (isOffset && elements) {
+ return createStaticDecl(function (env, scope) {
+ env.OFFSET = '0';
+ return 0
+ })
+ }
+ return null
+ }
+
+ var OFFSET = parseParam(S_OFFSET, true);
+
+ function parseVertCount () {
+ if (S_COUNT in staticOptions) {
+ var count = staticOptions[S_COUNT] | 0;
+ check$1.command(
+ typeof count === 'number' && count >= 0, 'invalid vertex count', env.commandStr);
+ return createStaticDecl(function () {
+ return count
+ })
+ } else if (S_COUNT in dynamicOptions) {
+ var dynCount = dynamicOptions[S_COUNT];
+ return createDynamicDecl(dynCount, function (env, scope) {
+ var result = env.invoke(scope, dynCount);
+ check$1.optional(function () {
+ env.assert(scope,
+ 'typeof ' + result + '==="number"&&' +
+ result + '>=0&&' +
+ result + '===(' + result + '|0)',
+ 'invalid vertex count');
+ });
+ return result
+ })
+ } else if (elements) {
+ if (isStatic(elements)) {
+ if (elements) {
+ if (OFFSET) {
+ return new Declaration(
+ OFFSET.thisDep,
+ OFFSET.contextDep,
+ OFFSET.propDep,
+ function (env, scope) {
+ var result = scope.def(
+ env.ELEMENTS, '.vertCount-', env.OFFSET);
+
+ check$1.optional(function () {
+ env.assert(scope,
+ result + '>=0',
+ 'invalid vertex offset/element buffer too small');
+ });
+
+ return result
+ })
+ } else {
+ return createStaticDecl(function (env, scope) {
+ return scope.def(env.ELEMENTS, '.vertCount')
+ })
+ }
+ } else {
+ var result = createStaticDecl(function () {
+ return -1
+ });
+ check$1.optional(function () {
+ result.MISSING = true;
+ });
+ return result
+ }
+ } else {
+ var variable = new Declaration(
+ elements.thisDep || OFFSET.thisDep,
+ elements.contextDep || OFFSET.contextDep,
+ elements.propDep || OFFSET.propDep,
+ function (env, scope) {
+ var elements = env.ELEMENTS;
+ if (env.OFFSET) {
+ return scope.def(elements, '?', elements, '.vertCount-',
+ env.OFFSET, ':-1')
+ }
+ return scope.def(elements, '?', elements, '.vertCount:-1')
+ });
+ check$1.optional(function () {
+ variable.DYNAMIC = true;
+ });
+ return variable
+ }
+ }
+ return null
+ }
+
+ return {
+ elements: elements,
+ primitive: parsePrimitive(),
+ count: parseVertCount(),
+ instances: parseParam(S_INSTANCES, false),
+ offset: OFFSET
+ }
+ }
+
+ function parseGLState (options, env) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ var STATE = {};
+
+ GL_STATE_NAMES.forEach(function (prop) {
+ var param = propName(prop);
+
+ function parseParam (parseStatic, parseDynamic) {
+ if (prop in staticOptions) {
+ var value = parseStatic(staticOptions[prop]);
+ STATE[param] = createStaticDecl(function () {
+ return value
+ });
+ } else if (prop in dynamicOptions) {
+ var dyn = dynamicOptions[prop];
+ STATE[param] = createDynamicDecl(dyn, function (env, scope) {
+ return parseDynamic(env, scope, env.invoke(scope, dyn))
+ });
+ }
+ }
+
+ switch (prop) {
+ case S_CULL_ENABLE:
+ case S_BLEND_ENABLE:
+ case S_DITHER:
+ case S_STENCIL_ENABLE:
+ case S_DEPTH_ENABLE:
+ case S_SCISSOR_ENABLE:
+ case S_POLYGON_OFFSET_ENABLE:
+ case S_SAMPLE_ALPHA:
+ case S_SAMPLE_ENABLE:
+ case S_DEPTH_MASK:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'boolean', prop, env.commandStr);
+ return value
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ 'typeof ' + value + '==="boolean"',
+ 'invalid flag ' + prop, env.commandStr);
+ });
+ return value
+ })
+
+ case S_DEPTH_FUNC:
+ return parseParam(
+ function (value) {
+ check$1.commandParameter(value, compareFuncs, 'invalid ' + prop, env.commandStr);
+ return compareFuncs[value]
+ },
+ function (env, scope, value) {
+ var COMPARE_FUNCS = env.constants.compareFuncs;
+ check$1.optional(function () {
+ env.assert(scope,
+ value + ' in ' + COMPARE_FUNCS,
+ 'invalid ' + prop + ', must be one of ' + Object.keys(compareFuncs));
+ });
+ return scope.def(COMPARE_FUNCS, '[', value, ']')
+ })
+
+ case S_DEPTH_RANGE:
+ return parseParam(
+ function (value) {
+ check$1.command(
+ isArrayLike(value) &&
+ value.length === 2 &&
+ typeof value[0] === 'number' &&
+ typeof value[1] === 'number' &&
+ value[0] <= value[1],
+ 'depth range is 2d array',
+ env.commandStr);
+ return value
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ env.shared.isArrayLike + '(' + value + ')&&' +
+ value + '.length===2&&' +
+ 'typeof ' + value + '[0]==="number"&&' +
+ 'typeof ' + value + '[1]==="number"&&' +
+ value + '[0]<=' + value + '[1]',
+ 'depth range must be a 2d array');
+ });
+
+ var Z_NEAR = scope.def('+', value, '[0]');
+ var Z_FAR = scope.def('+', value, '[1]');
+ return [Z_NEAR, Z_FAR]
+ })
+
+ case S_BLEND_FUNC:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'object', 'blend.func', env.commandStr);
+ var srcRGB = ('srcRGB' in value ? value.srcRGB : value.src);
+ var srcAlpha = ('srcAlpha' in value ? value.srcAlpha : value.src);
+ var dstRGB = ('dstRGB' in value ? value.dstRGB : value.dst);
+ var dstAlpha = ('dstAlpha' in value ? value.dstAlpha : value.dst);
+ check$1.commandParameter(srcRGB, blendFuncs, param + '.srcRGB', env.commandStr);
+ check$1.commandParameter(srcAlpha, blendFuncs, param + '.srcAlpha', env.commandStr);
+ check$1.commandParameter(dstRGB, blendFuncs, param + '.dstRGB', env.commandStr);
+ check$1.commandParameter(dstAlpha, blendFuncs, param + '.dstAlpha', env.commandStr);
+
+ check$1.command(
+ (invalidBlendCombinations.indexOf(srcRGB + ', ' + dstRGB) === -1),
+ 'unallowed blending combination (srcRGB, dstRGB) = (' + srcRGB + ', ' + dstRGB + ')', env.commandStr);
+
+ return [
+ blendFuncs[srcRGB],
+ blendFuncs[dstRGB],
+ blendFuncs[srcAlpha],
+ blendFuncs[dstAlpha]
+ ]
+ },
+ function (env, scope, value) {
+ var BLEND_FUNCS = env.constants.blendFuncs;
+
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '&&typeof ' + value + '==="object"',
+ 'invalid blend func, must be an object');
+ });
+
+ function read (prefix, suffix) {
+ var func = scope.def(
+ '"', prefix, suffix, '" in ', value,
+ '?', value, '.', prefix, suffix,
+ ':', value, '.', prefix);
+
+ check$1.optional(function () {
+ env.assert(scope,
+ func + ' in ' + BLEND_FUNCS,
+ 'invalid ' + prop + '.' + prefix + suffix + ', must be one of ' + Object.keys(blendFuncs));
+ });
+
+ return func
+ }
+
+ var srcRGB = read('src', 'RGB');
+ var dstRGB = read('dst', 'RGB');
+
+ check$1.optional(function () {
+ var INVALID_BLEND_COMBINATIONS = env.constants.invalidBlendCombinations;
+
+ env.assert(scope,
+ INVALID_BLEND_COMBINATIONS +
+ '.indexOf(' + srcRGB + '+", "+' + dstRGB + ') === -1 ',
+ 'unallowed blending combination for (srcRGB, dstRGB)'
+ );
+ });
+
+ var SRC_RGB = scope.def(BLEND_FUNCS, '[', srcRGB, ']');
+ var SRC_ALPHA = scope.def(BLEND_FUNCS, '[', read('src', 'Alpha'), ']');
+ var DST_RGB = scope.def(BLEND_FUNCS, '[', dstRGB, ']');
+ var DST_ALPHA = scope.def(BLEND_FUNCS, '[', read('dst', 'Alpha'), ']');
+
+ return [SRC_RGB, DST_RGB, SRC_ALPHA, DST_ALPHA]
+ })
+
+ case S_BLEND_EQUATION:
+ return parseParam(
+ function (value) {
+ if (typeof value === 'string') {
+ check$1.commandParameter(value, blendEquations, 'invalid ' + prop, env.commandStr);
+ return [
+ blendEquations[value],
+ blendEquations[value]
+ ]
+ } else if (typeof value === 'object') {
+ check$1.commandParameter(
+ value.rgb, blendEquations, prop + '.rgb', env.commandStr);
+ check$1.commandParameter(
+ value.alpha, blendEquations, prop + '.alpha', env.commandStr);
+ return [
+ blendEquations[value.rgb],
+ blendEquations[value.alpha]
+ ]
+ } else {
+ check$1.commandRaise('invalid blend.equation', env.commandStr);
+ }
+ },
+ function (env, scope, value) {
+ var BLEND_EQUATIONS = env.constants.blendEquations;
+
+ var RGB = scope.def();
+ var ALPHA = scope.def();
+
+ var ifte = env.cond('typeof ', value, '==="string"');
+
+ check$1.optional(function () {
+ function checkProp (block, name, value) {
+ env.assert(block,
+ value + ' in ' + BLEND_EQUATIONS,
+ 'invalid ' + name + ', must be one of ' + Object.keys(blendEquations));
+ }
+ checkProp(ifte.then, prop, value);
+
+ env.assert(ifte.else,
+ value + '&&typeof ' + value + '==="object"',
+ 'invalid ' + prop);
+ checkProp(ifte.else, prop + '.rgb', value + '.rgb');
+ checkProp(ifte.else, prop + '.alpha', value + '.alpha');
+ });
+
+ ifte.then(
+ RGB, '=', ALPHA, '=', BLEND_EQUATIONS, '[', value, '];');
+ ifte.else(
+ RGB, '=', BLEND_EQUATIONS, '[', value, '.rgb];',
+ ALPHA, '=', BLEND_EQUATIONS, '[', value, '.alpha];');
+
+ scope(ifte);
+
+ return [RGB, ALPHA]
+ })
+
+ case S_BLEND_COLOR:
+ return parseParam(
+ function (value) {
+ check$1.command(
+ isArrayLike(value) &&
+ value.length === 4,
+ 'blend.color must be a 4d array', env.commandStr);
+ return loop(4, function (i) {
+ return +value[i]
+ })
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ env.shared.isArrayLike + '(' + value + ')&&' +
+ value + '.length===4',
+ 'blend.color must be a 4d array');
+ });
+ return loop(4, function (i) {
+ return scope.def('+', value, '[', i, ']')
+ })
+ })
+
+ case S_STENCIL_MASK:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'number', param, env.commandStr);
+ return value | 0
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ 'typeof ' + value + '==="number"',
+ 'invalid stencil.mask');
+ });
+ return scope.def(value, '|0')
+ })
+
+ case S_STENCIL_FUNC:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'object', param, env.commandStr);
+ var cmp = value.cmp || 'keep';
+ var ref = value.ref || 0;
+ var mask = 'mask' in value ? value.mask : -1;
+ check$1.commandParameter(cmp, compareFuncs, prop + '.cmp', env.commandStr);
+ check$1.commandType(ref, 'number', prop + '.ref', env.commandStr);
+ check$1.commandType(mask, 'number', prop + '.mask', env.commandStr);
+ return [
+ compareFuncs[cmp],
+ ref,
+ mask
+ ]
+ },
+ function (env, scope, value) {
+ var COMPARE_FUNCS = env.constants.compareFuncs;
+ check$1.optional(function () {
+ function assert () {
+ env.assert(scope,
+ Array.prototype.join.call(arguments, ''),
+ 'invalid stencil.func');
+ }
+ assert(value + '&&typeof ', value, '==="object"');
+ assert('!("cmp" in ', value, ')||(',
+ value, '.cmp in ', COMPARE_FUNCS, ')');
+ });
+ var cmp = scope.def(
+ '"cmp" in ', value,
+ '?', COMPARE_FUNCS, '[', value, '.cmp]',
+ ':', GL_KEEP);
+ var ref = scope.def(value, '.ref|0');
+ var mask = scope.def(
+ '"mask" in ', value,
+ '?', value, '.mask|0:-1');
+ return [cmp, ref, mask]
+ })
+
+ case S_STENCIL_OPFRONT:
+ case S_STENCIL_OPBACK:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'object', param, env.commandStr);
+ var fail = value.fail || 'keep';
+ var zfail = value.zfail || 'keep';
+ var zpass = value.zpass || 'keep';
+ check$1.commandParameter(fail, stencilOps, prop + '.fail', env.commandStr);
+ check$1.commandParameter(zfail, stencilOps, prop + '.zfail', env.commandStr);
+ check$1.commandParameter(zpass, stencilOps, prop + '.zpass', env.commandStr);
+ return [
+ prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT,
+ stencilOps[fail],
+ stencilOps[zfail],
+ stencilOps[zpass]
+ ]
+ },
+ function (env, scope, value) {
+ var STENCIL_OPS = env.constants.stencilOps;
+
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '&&typeof ' + value + '==="object"',
+ 'invalid ' + prop);
+ });
+
+ function read (name) {
+ check$1.optional(function () {
+ env.assert(scope,
+ '!("' + name + '" in ' + value + ')||' +
+ '(' + value + '.' + name + ' in ' + STENCIL_OPS + ')',
+ 'invalid ' + prop + '.' + name + ', must be one of ' + Object.keys(stencilOps));
+ });
+
+ return scope.def(
+ '"', name, '" in ', value,
+ '?', STENCIL_OPS, '[', value, '.', name, ']:',
+ GL_KEEP)
+ }
+
+ return [
+ prop === S_STENCIL_OPBACK ? GL_BACK : GL_FRONT,
+ read('fail'),
+ read('zfail'),
+ read('zpass')
+ ]
+ })
+
+ case S_POLYGON_OFFSET_OFFSET:
+ return parseParam(
+ function (value) {
+ check$1.commandType(value, 'object', param, env.commandStr);
+ var factor = value.factor | 0;
+ var units = value.units | 0;
+ check$1.commandType(factor, 'number', param + '.factor', env.commandStr);
+ check$1.commandType(units, 'number', param + '.units', env.commandStr);
+ return [factor, units]
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '&&typeof ' + value + '==="object"',
+ 'invalid ' + prop);
+ });
+
+ var FACTOR = scope.def(value, '.factor|0');
+ var UNITS = scope.def(value, '.units|0');
+
+ return [FACTOR, UNITS]
+ })
+
+ case S_CULL_FACE:
+ return parseParam(
+ function (value) {
+ var face = 0;
+ if (value === 'front') {
+ face = GL_FRONT;
+ } else if (value === 'back') {
+ face = GL_BACK;
+ }
+ check$1.command(!!face, param, env.commandStr);
+ return face
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '==="front"||' +
+ value + '==="back"',
+ 'invalid cull.face');
+ });
+ return scope.def(value, '==="front"?', GL_FRONT, ':', GL_BACK)
+ })
+
+ case S_LINE_WIDTH:
+ return parseParam(
+ function (value) {
+ check$1.command(
+ typeof value === 'number' &&
+ value >= limits.lineWidthDims[0] &&
+ value <= limits.lineWidthDims[1],
+ 'invalid line width, must positive number between ' +
+ limits.lineWidthDims[0] + ' and ' + limits.lineWidthDims[1], env.commandStr);
+ return value
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ 'typeof ' + value + '==="number"&&' +
+ value + '>=' + limits.lineWidthDims[0] + '&&' +
+ value + '<=' + limits.lineWidthDims[1],
+ 'invalid line width');
+ });
+
+ return value
+ })
+
+ case S_FRONT_FACE:
+ return parseParam(
+ function (value) {
+ check$1.commandParameter(value, orientationType, param, env.commandStr);
+ return orientationType[value]
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '==="cw"||' +
+ value + '==="ccw"',
+ 'invalid frontFace, must be one of cw,ccw');
+ });
+ return scope.def(value + '==="cw"?' + GL_CW + ':' + GL_CCW)
+ })
+
+ case S_COLOR_MASK:
+ return parseParam(
+ function (value) {
+ check$1.command(
+ isArrayLike(value) && value.length === 4,
+ 'color.mask must be length 4 array', env.commandStr);
+ return value.map(function (v) { return !!v })
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ env.shared.isArrayLike + '(' + value + ')&&' +
+ value + '.length===4',
+ 'invalid color.mask');
+ });
+ return loop(4, function (i) {
+ return '!!' + value + '[' + i + ']'
+ })
+ })
+
+ case S_SAMPLE_COVERAGE:
+ return parseParam(
+ function (value) {
+ check$1.command(typeof value === 'object' && value, param, env.commandStr);
+ var sampleValue = 'value' in value ? value.value : 1;
+ var sampleInvert = !!value.invert;
+ check$1.command(
+ typeof sampleValue === 'number' &&
+ sampleValue >= 0 && sampleValue <= 1,
+ 'sample.coverage.value must be a number between 0 and 1', env.commandStr);
+ return [sampleValue, sampleInvert]
+ },
+ function (env, scope, value) {
+ check$1.optional(function () {
+ env.assert(scope,
+ value + '&&typeof ' + value + '==="object"',
+ 'invalid sample.coverage');
+ });
+ var VALUE = scope.def(
+ '"value" in ', value, '?+', value, '.value:1');
+ var INVERT = scope.def('!!', value, '.invert');
+ return [VALUE, INVERT]
+ })
+ }
+ });
+
+ return STATE
+ }
+
+ function parseUniforms (uniforms, env) {
+ var staticUniforms = uniforms.static;
+ var dynamicUniforms = uniforms.dynamic;
+
+ var UNIFORMS = {};
+
+ Object.keys(staticUniforms).forEach(function (name) {
+ var value = staticUniforms[name];
+ var result;
+ if (typeof value === 'number' ||
+ typeof value === 'boolean') {
+ result = createStaticDecl(function () {
+ return value
+ });
+ } else if (typeof value === 'function') {
+ var reglType = value._reglType;
+ if (reglType === 'texture2d' ||
+ reglType === 'textureCube') {
+ result = createStaticDecl(function (env) {
+ return env.link(value)
+ });
+ } else if (reglType === 'framebuffer' ||
+ reglType === 'framebufferCube') {
+ check$1.command(value.color.length > 0,
+ 'missing color attachment for framebuffer sent to uniform "' + name + '"', env.commandStr);
+ result = createStaticDecl(function (env) {
+ return env.link(value.color[0])
+ });
+ } else {
+ check$1.commandRaise('invalid data for uniform "' + name + '"', env.commandStr);
+ }
+ } else if (isArrayLike(value)) {
+ result = createStaticDecl(function (env) {
+ var ITEM = env.global.def('[',
+ loop(value.length, function (i) {
+ check$1.command(
+ typeof value[i] === 'number' ||
+ typeof value[i] === 'boolean',
+ 'invalid uniform ' + name, env.commandStr);
+ return value[i]
+ }), ']');
+ return ITEM
+ });
+ } else {
+ check$1.commandRaise('invalid or missing data for uniform "' + name + '"', env.commandStr);
+ }
+ result.value = value;
+ UNIFORMS[name] = result;
+ });
+
+ Object.keys(dynamicUniforms).forEach(function (key) {
+ var dyn = dynamicUniforms[key];
+ UNIFORMS[key] = createDynamicDecl(dyn, function (env, scope) {
+ return env.invoke(scope, dyn)
+ });
+ });
+
+ return UNIFORMS
+ }
+
+ function parseAttributes (attributes, env) {
+ var staticAttributes = attributes.static;
+ var dynamicAttributes = attributes.dynamic;
+
+ var attributeDefs = {};
+
+ Object.keys(staticAttributes).forEach(function (attribute) {
+ var value = staticAttributes[attribute];
+ var id = stringStore.id(attribute);
+
+ var record = new AttributeRecord();
+ if (isBufferArgs(value)) {
+ record.state = ATTRIB_STATE_POINTER;
+ record.buffer = bufferState.getBuffer(
+ bufferState.create(value, GL_ARRAY_BUFFER$1, false, true));
+ record.type = 0;
+ } else {
+ var buffer = bufferState.getBuffer(value);
+ if (buffer) {
+ record.state = ATTRIB_STATE_POINTER;
+ record.buffer = buffer;
+ record.type = 0;
+ } else {
+ check$1.command(typeof value === 'object' && value,
+ 'invalid data for attribute ' + attribute, env.commandStr);
+ if (value.constant) {
+ var constant = value.constant;
+ record.buffer = 'null';
+ record.state = ATTRIB_STATE_CONSTANT;
+ if (typeof constant === 'number') {
+ record.x = constant;
+ } else {
+ check$1.command(
+ isArrayLike(constant) &&
+ constant.length > 0 &&
+ constant.length <= 4,
+ 'invalid constant for attribute ' + attribute, env.commandStr);
+ CUTE_COMPONENTS.forEach(function (c, i) {
+ if (i < constant.length) {
+ record[c] = constant[i];
+ }
+ });
+ }
+ } else {
+ if (isBufferArgs(value.buffer)) {
+ buffer = bufferState.getBuffer(
+ bufferState.create(value.buffer, GL_ARRAY_BUFFER$1, false, true));
+ } else {
+ buffer = bufferState.getBuffer(value.buffer);
+ }
+ check$1.command(!!buffer, 'missing buffer for attribute "' + attribute + '"', env.commandStr);
+
+ var offset = value.offset | 0;
+ check$1.command(offset >= 0,
+ 'invalid offset for attribute "' + attribute + '"', env.commandStr);
+
+ var stride = value.stride | 0;
+ check$1.command(stride >= 0 && stride < 256,
+ 'invalid stride for attribute "' + attribute + '", must be integer betweeen [0, 255]', env.commandStr);
+
+ var size = value.size | 0;
+ check$1.command(!('size' in value) || (size > 0 && size <= 4),
+ 'invalid size for attribute "' + attribute + '", must be 1,2,3,4', env.commandStr);
+
+ var normalized = !!value.normalized;
+
+ var type = 0;
+ if ('type' in value) {
+ check$1.commandParameter(
+ value.type, glTypes,
+ 'invalid type for attribute ' + attribute, env.commandStr);
+ type = glTypes[value.type];
+ }
+
+ var divisor = value.divisor | 0;
+ if ('divisor' in value) {
+ check$1.command(divisor === 0 || extInstancing,
+ 'cannot specify divisor for attribute "' + attribute + '", instancing not supported', env.commandStr);
+ check$1.command(divisor >= 0,
+ 'invalid divisor for attribute "' + attribute + '"', env.commandStr);
+ }
+
+ check$1.optional(function () {
+ var command = env.commandStr;
+
+ var VALID_KEYS = [
+ 'buffer',
+ 'offset',
+ 'divisor',
+ 'normalized',
+ 'type',
+ 'size',
+ 'stride'
+ ];
+
+ Object.keys(value).forEach(function (prop) {
+ check$1.command(
+ VALID_KEYS.indexOf(prop) >= 0,
+ 'unknown parameter "' + prop + '" for attribute pointer "' + attribute + '" (valid parameters are ' + VALID_KEYS + ')',
+ command);
+ });
+ });
+
+ record.buffer = buffer;
+ record.state = ATTRIB_STATE_POINTER;
+ record.size = size;
+ record.normalized = normalized;
+ record.type = type || buffer.dtype;
+ record.offset = offset;
+ record.stride = stride;
+ record.divisor = divisor;
+ }
+ }
+ }
+
+ attributeDefs[attribute] = createStaticDecl(function (env, scope) {
+ var cache = env.attribCache;
+ if (id in cache) {
+ return cache[id]
+ }
+ var result = {
+ isStream: false
+ };
+ Object.keys(record).forEach(function (key) {
+ result[key] = record[key];
+ });
+ if (record.buffer) {
+ result.buffer = env.link(record.buffer);
+ result.type = result.type || (result.buffer + '.dtype');
+ }
+ cache[id] = result;
+ return result
+ });
+ });
+
+ Object.keys(dynamicAttributes).forEach(function (attribute) {
+ var dyn = dynamicAttributes[attribute];
+
+ function appendAttributeCode (env, block) {
+ var VALUE = env.invoke(block, dyn);
+
+ var shared = env.shared;
+
+ var IS_BUFFER_ARGS = shared.isBufferArgs;
+ var BUFFER_STATE = shared.buffer;
+
+ // Perform validation on attribute
+ check$1.optional(function () {
+ env.assert(block,
+ VALUE + '&&(typeof ' + VALUE + '==="object"||typeof ' +
+ VALUE + '==="function")&&(' +
+ IS_BUFFER_ARGS + '(' + VALUE + ')||' +
+ BUFFER_STATE + '.getBuffer(' + VALUE + ')||' +
+ BUFFER_STATE + '.getBuffer(' + VALUE + '.buffer)||' +
+ IS_BUFFER_ARGS + '(' + VALUE + '.buffer)||' +
+ '("constant" in ' + VALUE +
+ '&&(typeof ' + VALUE + '.constant==="number"||' +
+ shared.isArrayLike + '(' + VALUE + '.constant))))',
+ 'invalid dynamic attribute "' + attribute + '"');
+ });
+
+ // allocate names for result
+ var result = {
+ isStream: block.def(false)
+ };
+ var defaultRecord = new AttributeRecord();
+ defaultRecord.state = ATTRIB_STATE_POINTER;
+ Object.keys(defaultRecord).forEach(function (key) {
+ result[key] = block.def('' + defaultRecord[key]);
+ });
+
+ var BUFFER = result.buffer;
+ var TYPE = result.type;
+ block(
+ 'if(', IS_BUFFER_ARGS, '(', VALUE, ')){',
+ result.isStream, '=true;',
+ BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, ');',
+ TYPE, '=', BUFFER, '.dtype;',
+ '}else{',
+ BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, ');',
+ 'if(', BUFFER, '){',
+ TYPE, '=', BUFFER, '.dtype;',
+ '}else if("constant" in ', VALUE, '){',
+ result.state, '=', ATTRIB_STATE_CONSTANT, ';',
+ 'if(typeof ' + VALUE + '.constant === "number"){',
+ result[CUTE_COMPONENTS[0]], '=', VALUE, '.constant;',
+ CUTE_COMPONENTS.slice(1).map(function (n) {
+ return result[n]
+ }).join('='), '=0;',
+ '}else{',
+ CUTE_COMPONENTS.map(function (name, i) {
+ return (
+ result[name] + '=' + VALUE + '.constant.length>=' + i +
+ '?' + VALUE + '.constant[' + i + ']:0;'
+ )
+ }).join(''),
+ '}}else{',
+ 'if(', IS_BUFFER_ARGS, '(', VALUE, '.buffer)){',
+ BUFFER, '=', BUFFER_STATE, '.createStream(', GL_ARRAY_BUFFER$1, ',', VALUE, '.buffer);',
+ '}else{',
+ BUFFER, '=', BUFFER_STATE, '.getBuffer(', VALUE, '.buffer);',
+ '}',
+ TYPE, '="type" in ', VALUE, '?',
+ shared.glTypes, '[', VALUE, '.type]:', BUFFER, '.dtype;',
+ result.normalized, '=!!', VALUE, '.normalized;');
+ function emitReadRecord (name) {
+ block(result[name], '=', VALUE, '.', name, '|0;');
+ }
+ emitReadRecord('size');
+ emitReadRecord('offset');
+ emitReadRecord('stride');
+ emitReadRecord('divisor');
+
+ block('}}');
+
+ block.exit(
+ 'if(', result.isStream, '){',
+ BUFFER_STATE, '.destroyStream(', BUFFER, ');',
+ '}');
+
+ return result
+ }
+
+ attributeDefs[attribute] = createDynamicDecl(dyn, appendAttributeCode);
+ });
+
+ return attributeDefs
+ }
+
+ function parseContext (context) {
+ var staticContext = context.static;
+ var dynamicContext = context.dynamic;
+ var result = {};
+
+ Object.keys(staticContext).forEach(function (name) {
+ var value = staticContext[name];
+ result[name] = createStaticDecl(function (env, scope) {
+ if (typeof value === 'number' || typeof value === 'boolean') {
+ return '' + value
+ } else {
+ return env.link(value)
+ }
+ });
+ });
+
+ Object.keys(dynamicContext).forEach(function (name) {
+ var dyn = dynamicContext[name];
+ result[name] = createDynamicDecl(dyn, function (env, scope) {
+ return env.invoke(scope, dyn)
+ });
+ });
+
+ return result
+ }
+
+ function parseArguments (options, attributes, uniforms, context, env) {
+ var staticOptions = options.static;
+ var dynamicOptions = options.dynamic;
+
+ check$1.optional(function () {
+ var KEY_NAMES = [
+ S_FRAMEBUFFER,
+ S_VERT,
+ S_FRAG,
+ S_ELEMENTS,
+ S_PRIMITIVE,
+ S_OFFSET,
+ S_COUNT,
+ S_INSTANCES,
+ S_PROFILE
+ ].concat(GL_STATE_NAMES);
+
+ function checkKeys (dict) {
+ Object.keys(dict).forEach(function (key) {
+ check$1.command(
+ KEY_NAMES.indexOf(key) >= 0,
+ 'unknown parameter "' + key + '"',
+ env.commandStr);
+ });
+ }
+
+ checkKeys(staticOptions);
+ checkKeys(dynamicOptions);
+ });
+
+ var framebuffer = parseFramebuffer(options, env);
+ var viewportAndScissor = parseViewportScissor(options, framebuffer, env);
+ var draw = parseDraw(options, env);
+ var state = parseGLState(options, env);
+ var shader = parseProgram(options, env);
+
+ function copyBox (name) {
+ var defn = viewportAndScissor[name];
+ if (defn) {
+ state[name] = defn;
+ }
+ }
+ copyBox(S_VIEWPORT);
+ copyBox(propName(S_SCISSOR_BOX));
+
+ var dirty = Object.keys(state).length > 0;
+
+ var result = {
+ framebuffer: framebuffer,
+ draw: draw,
+ shader: shader,
+ state: state,
+ dirty: dirty
+ };
+
+ result.profile = parseProfile(options, env);
+ result.uniforms = parseUniforms(uniforms, env);
+ result.attributes = parseAttributes(attributes, env);
+ result.context = parseContext(context, env);
+ return result
+ }
+
+ // ===================================================
+ // ===================================================
+ // COMMON UPDATE FUNCTIONS
+ // ===================================================
+ // ===================================================
+ function emitContext (env, scope, context) {
+ var shared = env.shared;
+ var CONTEXT = shared.context;
+
+ var contextEnter = env.scope();
+
+ Object.keys(context).forEach(function (name) {
+ scope.save(CONTEXT, '.' + name);
+ var defn = context[name];
+ contextEnter(CONTEXT, '.', name, '=', defn.append(env, scope), ';');
+ });
+
+ scope(contextEnter);
+ }
+
+ // ===================================================
+ // ===================================================
+ // COMMON DRAWING FUNCTIONS
+ // ===================================================
+ // ===================================================
+ function emitPollFramebuffer (env, scope, framebuffer, skipCheck) {
+ var shared = env.shared;
+
+ var GL = shared.gl;
+ var FRAMEBUFFER_STATE = shared.framebuffer;
+ var EXT_DRAW_BUFFERS;
+ if (extDrawBuffers) {
+ EXT_DRAW_BUFFERS = scope.def(shared.extensions, '.webgl_draw_buffers');
+ }
+
+ var constants = env.constants;
+
+ var DRAW_BUFFERS = constants.drawBuffer;
+ var BACK_BUFFER = constants.backBuffer;
+
+ var NEXT;
+ if (framebuffer) {
+ NEXT = framebuffer.append(env, scope);
+ } else {
+ NEXT = scope.def(FRAMEBUFFER_STATE, '.next');
+ }
+
+ if (!skipCheck) {
+ scope('if(', NEXT, '!==', FRAMEBUFFER_STATE, '.cur){');
+ }
+ scope(
+ 'if(', NEXT, '){',
+ GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',', NEXT, '.framebuffer);');
+ if (extDrawBuffers) {
+ scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(',
+ DRAW_BUFFERS, '[', NEXT, '.colorAttachments.length]);');
+ }
+ scope('}else{',
+ GL, '.bindFramebuffer(', GL_FRAMEBUFFER$1, ',null);');
+ if (extDrawBuffers) {
+ scope(EXT_DRAW_BUFFERS, '.drawBuffersWEBGL(', BACK_BUFFER, ');');
+ }
+ scope(
+ '}',
+ FRAMEBUFFER_STATE, '.cur=', NEXT, ';');
+ if (!skipCheck) {
+ scope('}');
+ }
+ }
+
+ function emitPollState (env, scope, args) {
+ var shared = env.shared;
+
+ var GL = shared.gl;
+
+ var CURRENT_VARS = env.current;
+ var NEXT_VARS = env.next;
+ var CURRENT_STATE = shared.current;
+ var NEXT_STATE = shared.next;
+
+ var block = env.cond(CURRENT_STATE, '.dirty');
+
+ GL_STATE_NAMES.forEach(function (prop) {
+ var param = propName(prop);
+ if (param in args.state) {
+ return
+ }
+
+ var NEXT, CURRENT;
+ if (param in NEXT_VARS) {
+ NEXT = NEXT_VARS[param];
+ CURRENT = CURRENT_VARS[param];
+ var parts = loop(currentState[param].length, function (i) {
+ return block.def(NEXT, '[', i, ']')
+ });
+ block(env.cond(parts.map(function (p, i) {
+ return p + '!==' + CURRENT + '[' + i + ']'
+ }).join('||'))
+ .then(
+ GL, '.', GL_VARIABLES[param], '(', parts, ');',
+ parts.map(function (p, i) {
+ return CURRENT + '[' + i + ']=' + p
+ }).join(';'), ';'));
+ } else {
+ NEXT = block.def(NEXT_STATE, '.', param);
+ var ifte = env.cond(NEXT, '!==', CURRENT_STATE, '.', param);
+ block(ifte);
+ if (param in GL_FLAGS) {
+ ifte(
+ env.cond(NEXT)
+ .then(GL, '.enable(', GL_FLAGS[param], ');')
+ .else(GL, '.disable(', GL_FLAGS[param], ');'),
+ CURRENT_STATE, '.', param, '=', NEXT, ';');
+ } else {
+ ifte(
+ GL, '.', GL_VARIABLES[param], '(', NEXT, ');',
+ CURRENT_STATE, '.', param, '=', NEXT, ';');
+ }
+ }
+ });
+ if (Object.keys(args.state).length === 0) {
+ block(CURRENT_STATE, '.dirty=false;');
+ }
+ scope(block);
+ }
+
+ function emitSetOptions (env, scope, options, filter) {
+ var shared = env.shared;
+ var CURRENT_VARS = env.current;
+ var CURRENT_STATE = shared.current;
+ var GL = shared.gl;
+ sortState(Object.keys(options)).forEach(function (param) {
+ var defn = options[param];
+ if (filter && !filter(defn)) {
+ return
+ }
+ var variable = defn.append(env, scope);
+ if (GL_FLAGS[param]) {
+ var flag = GL_FLAGS[param];
+ if (isStatic(defn)) {
+ if (variable) {
+ scope(GL, '.enable(', flag, ');');
+ } else {
+ scope(GL, '.disable(', flag, ');');
+ }
+ } else {
+ scope(env.cond(variable)
+ .then(GL, '.enable(', flag, ');')
+ .else(GL, '.disable(', flag, ');'));
+ }
+ scope(CURRENT_STATE, '.', param, '=', variable, ';');
+ } else if (isArrayLike(variable)) {
+ var CURRENT = CURRENT_VARS[param];
+ scope(
+ GL, '.', GL_VARIABLES[param], '(', variable, ');',
+ variable.map(function (v, i) {
+ return CURRENT + '[' + i + ']=' + v
+ }).join(';'), ';');
+ } else {
+ scope(
+ GL, '.', GL_VARIABLES[param], '(', variable, ');',
+ CURRENT_STATE, '.', param, '=', variable, ';');
+ }
+ });
+ }
+
+ function injectExtensions (env, scope) {
+ if (extInstancing) {
+ env.instancing = scope.def(
+ env.shared.extensions, '.angle_instanced_arrays');
+ }
+ }
+
+ function emitProfile (env, scope, args, useScope, incrementCounter) {
+ var shared = env.shared;
+ var STATS = env.stats;
+ var CURRENT_STATE = shared.current;
+ var TIMER = shared.timer;
+ var profileArg = args.profile;
+
+ function perfCounter () {
+ if (typeof performance === 'undefined') {
+ return 'Date.now()'
+ } else {
+ return 'performance.now()'
+ }
+ }
+
+ var CPU_START, QUERY_COUNTER;
+ function emitProfileStart (block) {
+ CPU_START = scope.def();
+ block(CPU_START, '=', perfCounter(), ';');
+ if (typeof incrementCounter === 'string') {
+ block(STATS, '.count+=', incrementCounter, ';');
+ } else {
+ block(STATS, '.count++;');
+ }
+ if (timer) {
+ if (useScope) {
+ QUERY_COUNTER = scope.def();
+ block(QUERY_COUNTER, '=', TIMER, '.getNumPendingQueries();');
+ } else {
+ block(TIMER, '.beginQuery(', STATS, ');');
+ }
+ }
+ }
+
+ function emitProfileEnd (block) {
+ block(STATS, '.cpuTime+=', perfCounter(), '-', CPU_START, ';');
+ if (timer) {
+ if (useScope) {
+ block(TIMER, '.pushScopeStats(',
+ QUERY_COUNTER, ',',
+ TIMER, '.getNumPendingQueries(),',
+ STATS, ');');
+ } else {
+ block(TIMER, '.endQuery();');
+ }
+ }
+ }
+
+ function scopeProfile (value) {
+ var prev = scope.def(CURRENT_STATE, '.profile');
+ scope(CURRENT_STATE, '.profile=', value, ';');
+ scope.exit(CURRENT_STATE, '.profile=', prev, ';');
+ }
+
+ var USE_PROFILE;
+ if (profileArg) {
+ if (isStatic(profileArg)) {
+ if (profileArg.enable) {
+ emitProfileStart(scope);
+ emitProfileEnd(scope.exit);
+ scopeProfile('true');
+ } else {
+ scopeProfile('false');
+ }
+ return
+ }
+ USE_PROFILE = profileArg.append(env, scope);
+ scopeProfile(USE_PROFILE);
+ } else {
+ USE_PROFILE = scope.def(CURRENT_STATE, '.profile');
+ }
+
+ var start = env.block();
+ emitProfileStart(start);
+ scope('if(', USE_PROFILE, '){', start, '}');
+ var end = env.block();
+ emitProfileEnd(end);
+ scope.exit('if(', USE_PROFILE, '){', end, '}');
+ }
+
+ function emitAttributes (env, scope, args, attributes, filter) {
+ var shared = env.shared;
+
+ function typeLength (x) {
+ switch (x) {
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ return 2
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ return 3
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ return 4
+ default:
+ return 1
+ }
+ }
+
+ function emitBindAttribute (ATTRIBUTE, size, record) {
+ var GL = shared.gl;
+
+ var LOCATION = scope.def(ATTRIBUTE, '.location');
+ var BINDING = scope.def(shared.attributes, '[', LOCATION, ']');
+
+ var STATE = record.state;
+ var BUFFER = record.buffer;
+ var CONST_COMPONENTS = [
+ record.x,
+ record.y,
+ record.z,
+ record.w
+ ];
+
+ var COMMON_KEYS = [
+ 'buffer',
+ 'normalized',
+ 'offset',
+ 'stride'
+ ];
+
+ function emitBuffer () {
+ scope(
+ 'if(!', BINDING, '.buffer){',
+ GL, '.enableVertexAttribArray(', LOCATION, ');}');
+
+ var TYPE = record.type;
+ var SIZE;
+ if (!record.size) {
+ SIZE = size;
+ } else {
+ SIZE = scope.def(record.size, '||', size);
+ }
+
+ scope('if(',
+ BINDING, '.type!==', TYPE, '||',
+ BINDING, '.size!==', SIZE, '||',
+ COMMON_KEYS.map(function (key) {
+ return BINDING + '.' + key + '!==' + record[key]
+ }).join('||'),
+ '){',
+ GL, '.bindBuffer(', GL_ARRAY_BUFFER$1, ',', BUFFER, '.buffer);',
+ GL, '.vertexAttribPointer(', [
+ LOCATION,
+ SIZE,
+ TYPE,
+ record.normalized,
+ record.stride,
+ record.offset
+ ], ');',
+ BINDING, '.type=', TYPE, ';',
+ BINDING, '.size=', SIZE, ';',
+ COMMON_KEYS.map(function (key) {
+ return BINDING + '.' + key + '=' + record[key] + ';'
+ }).join(''),
+ '}');
+
+ if (extInstancing) {
+ var DIVISOR = record.divisor;
+ scope(
+ 'if(', BINDING, '.divisor!==', DIVISOR, '){',
+ env.instancing, '.vertexAttribDivisorANGLE(', [LOCATION, DIVISOR], ');',
+ BINDING, '.divisor=', DIVISOR, ';}');
+ }
+ }
+
+ function emitConstant () {
+ scope(
+ 'if(', BINDING, '.buffer){',
+ GL, '.disableVertexAttribArray(', LOCATION, ');',
+ '}if(', CUTE_COMPONENTS.map(function (c, i) {
+ return BINDING + '.' + c + '!==' + CONST_COMPONENTS[i]
+ }).join('||'), '){',
+ GL, '.vertexAttrib4f(', LOCATION, ',', CONST_COMPONENTS, ');',
+ CUTE_COMPONENTS.map(function (c, i) {
+ return BINDING + '.' + c + '=' + CONST_COMPONENTS[i] + ';'
+ }).join(''),
+ '}');
+ }
+
+ if (STATE === ATTRIB_STATE_POINTER) {
+ emitBuffer();
+ } else if (STATE === ATTRIB_STATE_CONSTANT) {
+ emitConstant();
+ } else {
+ scope('if(', STATE, '===', ATTRIB_STATE_POINTER, '){');
+ emitBuffer();
+ scope('}else{');
+ emitConstant();
+ scope('}');
+ }
+ }
+
+ attributes.forEach(function (attribute) {
+ var name = attribute.name;
+ var arg = args.attributes[name];
+ var record;
+ if (arg) {
+ if (!filter(arg)) {
+ return
+ }
+ record = arg.append(env, scope);
+ } else {
+ if (!filter(SCOPE_DECL)) {
+ return
+ }
+ var scopeAttrib = env.scopeAttrib(name);
+ check$1.optional(function () {
+ env.assert(scope,
+ scopeAttrib + '.state',
+ 'missing attribute ' + name);
+ });
+ record = {};
+ Object.keys(new AttributeRecord()).forEach(function (key) {
+ record[key] = scope.def(scopeAttrib, '.', key);
+ });
+ }
+ emitBindAttribute(
+ env.link(attribute), typeLength(attribute.info.type), record);
+ });
+ }
+
+ function emitUniforms (env, scope, args, uniforms, filter) {
+ var shared = env.shared;
+ var GL = shared.gl;
+
+ var infix;
+ for (var i = 0; i < uniforms.length; ++i) {
+ var uniform = uniforms[i];
+ var name = uniform.name;
+ var type = uniform.info.type;
+ var arg = args.uniforms[name];
+ var UNIFORM = env.link(uniform);
+ var LOCATION = UNIFORM + '.location';
+
+ var VALUE;
+ if (arg) {
+ if (!filter(arg)) {
+ continue
+ }
+ if (isStatic(arg)) {
+ var value = arg.value;
+ check$1.command(
+ value !== null && typeof value !== 'undefined',
+ 'missing uniform "' + name + '"', env.commandStr);
+ if (type === GL_SAMPLER_2D || type === GL_SAMPLER_CUBE) {
+ check$1.command(
+ typeof value === 'function' &&
+ ((type === GL_SAMPLER_2D &&
+ (value._reglType === 'texture2d' ||
+ value._reglType === 'framebuffer')) ||
+ (type === GL_SAMPLER_CUBE &&
+ (value._reglType === 'textureCube' ||
+ value._reglType === 'framebufferCube'))),
+ 'invalid texture for uniform ' + name, env.commandStr);
+ var TEX_VALUE = env.link(value._texture || value.color[0]._texture);
+ scope(GL, '.uniform1i(', LOCATION, ',', TEX_VALUE + '.bind());');
+ scope.exit(TEX_VALUE, '.unbind();');
+ } else if (
+ type === GL_FLOAT_MAT2 ||
+ type === GL_FLOAT_MAT3 ||
+ type === GL_FLOAT_MAT4) {
+ check$1.optional(function () {
+ check$1.command(isArrayLike(value),
+ 'invalid matrix for uniform ' + name, env.commandStr);
+ check$1.command(
+ (type === GL_FLOAT_MAT2 && value.length === 4) ||
+ (type === GL_FLOAT_MAT3 && value.length === 9) ||
+ (type === GL_FLOAT_MAT4 && value.length === 16),
+ 'invalid length for matrix uniform ' + name, env.commandStr);
+ });
+ var MAT_VALUE = env.global.def('new Float32Array([' +
+ Array.prototype.slice.call(value) + '])');
+ var dim = 2;
+ if (type === GL_FLOAT_MAT3) {
+ dim = 3;
+ } else if (type === GL_FLOAT_MAT4) {
+ dim = 4;
+ }
+ scope(
+ GL, '.uniformMatrix', dim, 'fv(',
+ LOCATION, ',false,', MAT_VALUE, ');');
+ } else {
+ switch (type) {
+ case GL_FLOAT$7:
+ check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr);
+ infix = '1f';
+ break
+ case GL_FLOAT_VEC2:
+ check$1.command(
+ isArrayLike(value) && value.length === 2,
+ 'uniform ' + name, env.commandStr);
+ infix = '2f';
+ break
+ case GL_FLOAT_VEC3:
+ check$1.command(
+ isArrayLike(value) && value.length === 3,
+ 'uniform ' + name, env.commandStr);
+ infix = '3f';
+ break
+ case GL_FLOAT_VEC4:
+ check$1.command(
+ isArrayLike(value) && value.length === 4,
+ 'uniform ' + name, env.commandStr);
+ infix = '4f';
+ break
+ case GL_BOOL:
+ check$1.commandType(value, 'boolean', 'uniform ' + name, env.commandStr);
+ infix = '1i';
+ break
+ case GL_INT$3:
+ check$1.commandType(value, 'number', 'uniform ' + name, env.commandStr);
+ infix = '1i';
+ break
+ case GL_BOOL_VEC2:
+ check$1.command(
+ isArrayLike(value) && value.length === 2,
+ 'uniform ' + name, env.commandStr);
+ infix = '2i';
+ break
+ case GL_INT_VEC2:
+ check$1.command(
+ isArrayLike(value) && value.length === 2,
+ 'uniform ' + name, env.commandStr);
+ infix = '2i';
+ break
+ case GL_BOOL_VEC3:
+ check$1.command(
+ isArrayLike(value) && value.length === 3,
+ 'uniform ' + name, env.commandStr);
+ infix = '3i';
+ break
+ case GL_INT_VEC3:
+ check$1.command(
+ isArrayLike(value) && value.length === 3,
+ 'uniform ' + name, env.commandStr);
+ infix = '3i';
+ break
+ case GL_BOOL_VEC4:
+ check$1.command(
+ isArrayLike(value) && value.length === 4,
+ 'uniform ' + name, env.commandStr);
+ infix = '4i';
+ break
+ case GL_INT_VEC4:
+ check$1.command(
+ isArrayLike(value) && value.length === 4,
+ 'uniform ' + name, env.commandStr);
+ infix = '4i';
+ break
+ }
+ scope(GL, '.uniform', infix, '(', LOCATION, ',',
+ isArrayLike(value) ? Array.prototype.slice.call(value) : value,
+ ');');
+ }
+ continue
+ } else {
+ VALUE = arg.append(env, scope);
+ }
+ } else {
+ if (!filter(SCOPE_DECL)) {
+ continue
+ }
+ VALUE = scope.def(shared.uniforms, '[', stringStore.id(name), ']');
+ }
+
+ if (type === GL_SAMPLER_2D) {
+ scope(
+ 'if(', VALUE, '&&', VALUE, '._reglType==="framebuffer"){',
+ VALUE, '=', VALUE, '.color[0];',
+ '}');
+ } else if (type === GL_SAMPLER_CUBE) {
+ scope(
+ 'if(', VALUE, '&&', VALUE, '._reglType==="framebufferCube"){',
+ VALUE, '=', VALUE, '.color[0];',
+ '}');
+ }
+
+ // perform type validation
+ check$1.optional(function () {
+ function check (pred, message) {
+ env.assert(scope, pred,
+ 'bad data or missing for uniform "' + name + '". ' + message);
+ }
+
+ function checkType (type) {
+ check(
+ 'typeof ' + VALUE + '==="' + type + '"',
+ 'invalid type, expected ' + type);
+ }
+
+ function checkVector (n, type) {
+ check(
+ shared.isArrayLike + '(' + VALUE + ')&&' + VALUE + '.length===' + n,
+ 'invalid vector, should have length ' + n, env.commandStr);
+ }
+
+ function checkTexture (target) {
+ check(
+ 'typeof ' + VALUE + '==="function"&&' +
+ VALUE + '._reglType==="texture' +
+ (target === GL_TEXTURE_2D$2 ? '2d' : 'Cube') + '"',
+ 'invalid texture type', env.commandStr);
+ }
+
+ switch (type) {
+ case GL_INT$3:
+ checkType('number');
+ break
+ case GL_INT_VEC2:
+ checkVector(2, 'number');
+ break
+ case GL_INT_VEC3:
+ checkVector(3, 'number');
+ break
+ case GL_INT_VEC4:
+ checkVector(4, 'number');
+ break
+ case GL_FLOAT$7:
+ checkType('number');
+ break
+ case GL_FLOAT_VEC2:
+ checkVector(2, 'number');
+ break
+ case GL_FLOAT_VEC3:
+ checkVector(3, 'number');
+ break
+ case GL_FLOAT_VEC4:
+ checkVector(4, 'number');
+ break
+ case GL_BOOL:
+ checkType('boolean');
+ break
+ case GL_BOOL_VEC2:
+ checkVector(2, 'boolean');
+ break
+ case GL_BOOL_VEC3:
+ checkVector(3, 'boolean');
+ break
+ case GL_BOOL_VEC4:
+ checkVector(4, 'boolean');
+ break
+ case GL_FLOAT_MAT2:
+ checkVector(4, 'number');
+ break
+ case GL_FLOAT_MAT3:
+ checkVector(9, 'number');
+ break
+ case GL_FLOAT_MAT4:
+ checkVector(16, 'number');
+ break
+ case GL_SAMPLER_2D:
+ checkTexture(GL_TEXTURE_2D$2);
+ break
+ case GL_SAMPLER_CUBE:
+ checkTexture(GL_TEXTURE_CUBE_MAP$1);
+ break
+ }
+ });
+
+ var unroll = 1;
+ switch (type) {
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ var TEX = scope.def(VALUE, '._texture');
+ scope(GL, '.uniform1i(', LOCATION, ',', TEX, '.bind());');
+ scope.exit(TEX, '.unbind();');
+ continue
+
+ case GL_INT$3:
+ case GL_BOOL:
+ infix = '1i';
+ break
+
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ infix = '2i';
+ unroll = 2;
+ break
+
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ infix = '3i';
+ unroll = 3;
+ break
+
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ infix = '4i';
+ unroll = 4;
+ break
+
+ case GL_FLOAT$7:
+ infix = '1f';
+ break
+
+ case GL_FLOAT_VEC2:
+ infix = '2f';
+ unroll = 2;
+ break
+
+ case GL_FLOAT_VEC3:
+ infix = '3f';
+ unroll = 3;
+ break
+
+ case GL_FLOAT_VEC4:
+ infix = '4f';
+ unroll = 4;
+ break
+
+ case GL_FLOAT_MAT2:
+ infix = 'Matrix2fv';
+ break
+
+ case GL_FLOAT_MAT3:
+ infix = 'Matrix3fv';
+ break
+
+ case GL_FLOAT_MAT4:
+ infix = 'Matrix4fv';
+ break
+ }
+
+ scope(GL, '.uniform', infix, '(', LOCATION, ',');
+ if (infix.charAt(0) === 'M') {
+ var matSize = Math.pow(type - GL_FLOAT_MAT2 + 2, 2);
+ var STORAGE = env.global.def('new Float32Array(', matSize, ')');
+ scope(
+ 'false,(Array.isArray(', VALUE, ')||', VALUE, ' instanceof Float32Array)?', VALUE, ':(',
+ loop(matSize, function (i) {
+ return STORAGE + '[' + i + ']=' + VALUE + '[' + i + ']'
+ }), ',', STORAGE, ')');
+ } else if (unroll > 1) {
+ scope(loop(unroll, function (i) {
+ return VALUE + '[' + i + ']'
+ }));
+ } else {
+ scope(VALUE);
+ }
+ scope(');');
+ }
+ }
+
+ function emitDraw (env, outer, inner, args) {
+ var shared = env.shared;
+ var GL = shared.gl;
+ var DRAW_STATE = shared.draw;
+
+ var drawOptions = args.draw;
+
+ function emitElements () {
+ var defn = drawOptions.elements;
+ var ELEMENTS;
+ var scope = outer;
+ if (defn) {
+ if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
+ scope = inner;
+ }
+ ELEMENTS = defn.append(env, scope);
+ } else {
+ ELEMENTS = scope.def(DRAW_STATE, '.', S_ELEMENTS);
+ }
+ if (ELEMENTS) {
+ scope(
+ 'if(' + ELEMENTS + ')' +
+ GL + '.bindBuffer(' + GL_ELEMENT_ARRAY_BUFFER$1 + ',' + ELEMENTS + '.buffer.buffer);');
+ }
+ return ELEMENTS
+ }
+
+ function emitCount () {
+ var defn = drawOptions.count;
+ var COUNT;
+ var scope = outer;
+ if (defn) {
+ if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
+ scope = inner;
+ }
+ COUNT = defn.append(env, scope);
+ check$1.optional(function () {
+ if (defn.MISSING) {
+ env.assert(outer, 'false', 'missing vertex count');
+ }
+ if (defn.DYNAMIC) {
+ env.assert(scope, COUNT + '>=0', 'missing vertex count');
+ }
+ });
+ } else {
+ COUNT = scope.def(DRAW_STATE, '.', S_COUNT);
+ check$1.optional(function () {
+ env.assert(scope, COUNT + '>=0', 'missing vertex count');
+ });
+ }
+ return COUNT
+ }
+
+ var ELEMENTS = emitElements();
+ function emitValue (name) {
+ var defn = drawOptions[name];
+ if (defn) {
+ if ((defn.contextDep && args.contextDynamic) || defn.propDep) {
+ return defn.append(env, inner)
+ } else {
+ return defn.append(env, outer)
+ }
+ } else {
+ return outer.def(DRAW_STATE, '.', name)
+ }
+ }
+
+ var PRIMITIVE = emitValue(S_PRIMITIVE);
+ var OFFSET = emitValue(S_OFFSET);
+
+ var COUNT = emitCount();
+ if (typeof COUNT === 'number') {
+ if (COUNT === 0) {
+ return
+ }
+ } else {
+ inner('if(', COUNT, '){');
+ inner.exit('}');
+ }
+
+ var INSTANCES, EXT_INSTANCING;
+ if (extInstancing) {
+ INSTANCES = emitValue(S_INSTANCES);
+ EXT_INSTANCING = env.instancing;
+ }
+
+ var ELEMENT_TYPE = ELEMENTS + '.type';
+
+ var elementsStatic = drawOptions.elements && isStatic(drawOptions.elements);
+
+ function emitInstancing () {
+ function drawElements () {
+ inner(EXT_INSTANCING, '.drawElementsInstancedANGLE(', [
+ PRIMITIVE,
+ COUNT,
+ ELEMENT_TYPE,
+ OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)',
+ INSTANCES
+ ], ');');
+ }
+
+ function drawArrays () {
+ inner(EXT_INSTANCING, '.drawArraysInstancedANGLE(',
+ [PRIMITIVE, OFFSET, COUNT, INSTANCES], ');');
+ }
+
+ if (ELEMENTS) {
+ if (!elementsStatic) {
+ inner('if(', ELEMENTS, '){');
+ drawElements();
+ inner('}else{');
+ drawArrays();
+ inner('}');
+ } else {
+ drawElements();
+ }
+ } else {
+ drawArrays();
+ }
+ }
+
+ function emitRegular () {
+ function drawElements () {
+ inner(GL + '.drawElements(' + [
+ PRIMITIVE,
+ COUNT,
+ ELEMENT_TYPE,
+ OFFSET + '<<((' + ELEMENT_TYPE + '-' + GL_UNSIGNED_BYTE$7 + ')>>1)'
+ ] + ');');
+ }
+
+ function drawArrays () {
+ inner(GL + '.drawArrays(' + [PRIMITIVE, OFFSET, COUNT] + ');');
+ }
+
+ if (ELEMENTS) {
+ if (!elementsStatic) {
+ inner('if(', ELEMENTS, '){');
+ drawElements();
+ inner('}else{');
+ drawArrays();
+ inner('}');
+ } else {
+ drawElements();
+ }
+ } else {
+ drawArrays();
+ }
+ }
+
+ if (extInstancing && (typeof INSTANCES !== 'number' || INSTANCES >= 0)) {
+ if (typeof INSTANCES === 'string') {
+ inner('if(', INSTANCES, '>0){');
+ emitInstancing();
+ inner('}else if(', INSTANCES, '<0){');
+ emitRegular();
+ inner('}');
+ } else {
+ emitInstancing();
+ }
+ } else {
+ emitRegular();
+ }
+ }
+
+ function createBody (emitBody, parentEnv, args, program, count) {
+ var env = createREGLEnvironment();
+ var scope = env.proc('body', count);
+ check$1.optional(function () {
+ env.commandStr = parentEnv.commandStr;
+ env.command = env.link(parentEnv.commandStr);
+ });
+ if (extInstancing) {
+ env.instancing = scope.def(
+ env.shared.extensions, '.angle_instanced_arrays');
+ }
+ emitBody(env, scope, args, program);
+ return env.compile().body
+ }
+
+ // ===================================================
+ // ===================================================
+ // DRAW PROC
+ // ===================================================
+ // ===================================================
+ function emitDrawBody (env, draw, args, program) {
+ injectExtensions(env, draw);
+ emitAttributes(env, draw, args, program.attributes, function () {
+ return true
+ });
+ emitUniforms(env, draw, args, program.uniforms, function () {
+ return true
+ });
+ emitDraw(env, draw, draw, args);
+ }
+
+ function emitDrawProc (env, args) {
+ var draw = env.proc('draw', 1);
+
+ injectExtensions(env, draw);
+
+ emitContext(env, draw, args.context);
+ emitPollFramebuffer(env, draw, args.framebuffer);
+
+ emitPollState(env, draw, args);
+ emitSetOptions(env, draw, args.state);
+
+ emitProfile(env, draw, args, false, true);
+
+ var program = args.shader.progVar.append(env, draw);
+ draw(env.shared.gl, '.useProgram(', program, '.program);');
+
+ if (args.shader.program) {
+ emitDrawBody(env, draw, args, args.shader.program);
+ } else {
+ var drawCache = env.global.def('{}');
+ var PROG_ID = draw.def(program, '.id');
+ var CACHED_PROC = draw.def(drawCache, '[', PROG_ID, ']');
+ draw(
+ env.cond(CACHED_PROC)
+ .then(CACHED_PROC, '.call(this,a0);')
+ .else(
+ CACHED_PROC, '=', drawCache, '[', PROG_ID, ']=',
+ env.link(function (program) {
+ return createBody(emitDrawBody, env, args, program, 1)
+ }), '(', program, ');',
+ CACHED_PROC, '.call(this,a0);'));
+ }
+
+ if (Object.keys(args.state).length > 0) {
+ draw(env.shared.current, '.dirty=true;');
+ }
+ }
+
+ // ===================================================
+ // ===================================================
+ // BATCH PROC
+ // ===================================================
+ // ===================================================
+
+ function emitBatchDynamicShaderBody (env, scope, args, program) {
+ env.batchId = 'a1';
+
+ injectExtensions(env, scope);
+
+ function all () {
+ return true
+ }
+
+ emitAttributes(env, scope, args, program.attributes, all);
+ emitUniforms(env, scope, args, program.uniforms, all);
+ emitDraw(env, scope, scope, args);
+ }
+
+ function emitBatchBody (env, scope, args, program) {
+ injectExtensions(env, scope);
+
+ var contextDynamic = args.contextDep;
+
+ var BATCH_ID = scope.def();
+ var PROP_LIST = 'a0';
+ var NUM_PROPS = 'a1';
+ var PROPS = scope.def();
+ env.shared.props = PROPS;
+ env.batchId = BATCH_ID;
+
+ var outer = env.scope();
+ var inner = env.scope();
+
+ scope(
+ outer.entry,
+ 'for(', BATCH_ID, '=0;', BATCH_ID, '<', NUM_PROPS, ';++', BATCH_ID, '){',
+ PROPS, '=', PROP_LIST, '[', BATCH_ID, '];',
+ inner,
+ '}',
+ outer.exit);
+
+ function isInnerDefn (defn) {
+ return ((defn.contextDep && contextDynamic) || defn.propDep)
+ }
+
+ function isOuterDefn (defn) {
+ return !isInnerDefn(defn)
+ }
+
+ if (args.needsContext) {
+ emitContext(env, inner, args.context);
+ }
+ if (args.needsFramebuffer) {
+ emitPollFramebuffer(env, inner, args.framebuffer);
+ }
+ emitSetOptions(env, inner, args.state, isInnerDefn);
+
+ if (args.profile && isInnerDefn(args.profile)) {
+ emitProfile(env, inner, args, false, true);
+ }
+
+ if (!program) {
+ var progCache = env.global.def('{}');
+ var PROGRAM = args.shader.progVar.append(env, inner);
+ var PROG_ID = inner.def(PROGRAM, '.id');
+ var CACHED_PROC = inner.def(progCache, '[', PROG_ID, ']');
+ inner(
+ env.shared.gl, '.useProgram(', PROGRAM, '.program);',
+ 'if(!', CACHED_PROC, '){',
+ CACHED_PROC, '=', progCache, '[', PROG_ID, ']=',
+ env.link(function (program) {
+ return createBody(
+ emitBatchDynamicShaderBody, env, args, program, 2)
+ }), '(', PROGRAM, ');}',
+ CACHED_PROC, '.call(this,a0[', BATCH_ID, '],', BATCH_ID, ');');
+ } else {
+ emitAttributes(env, outer, args, program.attributes, isOuterDefn);
+ emitAttributes(env, inner, args, program.attributes, isInnerDefn);
+ emitUniforms(env, outer, args, program.uniforms, isOuterDefn);
+ emitUniforms(env, inner, args, program.uniforms, isInnerDefn);
+ emitDraw(env, outer, inner, args);
+ }
+ }
+
+ function emitBatchProc (env, args) {
+ var batch = env.proc('batch', 2);
+ env.batchId = '0';
+
+ injectExtensions(env, batch);
+
+ // Check if any context variables depend on props
+ var contextDynamic = false;
+ var needsContext = true;
+ Object.keys(args.context).forEach(function (name) {
+ contextDynamic = contextDynamic || args.context[name].propDep;
+ });
+ if (!contextDynamic) {
+ emitContext(env, batch, args.context);
+ needsContext = false;
+ }
+
+ // framebuffer state affects framebufferWidth/height context vars
+ var framebuffer = args.framebuffer;
+ var needsFramebuffer = false;
+ if (framebuffer) {
+ if (framebuffer.propDep) {
+ contextDynamic = needsFramebuffer = true;
+ } else if (framebuffer.contextDep && contextDynamic) {
+ needsFramebuffer = true;
+ }
+ if (!needsFramebuffer) {
+ emitPollFramebuffer(env, batch, framebuffer);
+ }
+ } else {
+ emitPollFramebuffer(env, batch, null);
+ }
+
+ // viewport is weird because it can affect context vars
+ if (args.state.viewport && args.state.viewport.propDep) {
+ contextDynamic = true;
+ }
+
+ function isInnerDefn (defn) {
+ return (defn.contextDep && contextDynamic) || defn.propDep
+ }
+
+ // set webgl options
+ emitPollState(env, batch, args);
+ emitSetOptions(env, batch, args.state, function (defn) {
+ return !isInnerDefn(defn)
+ });
+
+ if (!args.profile || !isInnerDefn(args.profile)) {
+ emitProfile(env, batch, args, false, 'a1');
+ }
+
+ // Save these values to args so that the batch body routine can use them
+ args.contextDep = contextDynamic;
+ args.needsContext = needsContext;
+ args.needsFramebuffer = needsFramebuffer;
+
+ // determine if shader is dynamic
+ var progDefn = args.shader.progVar;
+ if ((progDefn.contextDep && contextDynamic) || progDefn.propDep) {
+ emitBatchBody(
+ env,
+ batch,
+ args,
+ null);
+ } else {
+ var PROGRAM = progDefn.append(env, batch);
+ batch(env.shared.gl, '.useProgram(', PROGRAM, '.program);');
+ if (args.shader.program) {
+ emitBatchBody(
+ env,
+ batch,
+ args,
+ args.shader.program);
+ } else {
+ var batchCache = env.global.def('{}');
+ var PROG_ID = batch.def(PROGRAM, '.id');
+ var CACHED_PROC = batch.def(batchCache, '[', PROG_ID, ']');
+ batch(
+ env.cond(CACHED_PROC)
+ .then(CACHED_PROC, '.call(this,a0,a1);')
+ .else(
+ CACHED_PROC, '=', batchCache, '[', PROG_ID, ']=',
+ env.link(function (program) {
+ return createBody(emitBatchBody, env, args, program, 2)
+ }), '(', PROGRAM, ');',
+ CACHED_PROC, '.call(this,a0,a1);'));
+ }
+ }
+
+ if (Object.keys(args.state).length > 0) {
+ batch(env.shared.current, '.dirty=true;');
+ }
+ }
+
+ // ===================================================
+ // ===================================================
+ // SCOPE COMMAND
+ // ===================================================
+ // ===================================================
+ function emitScopeProc (env, args) {
+ var scope = env.proc('scope', 3);
+ env.batchId = 'a2';
+
+ var shared = env.shared;
+ var CURRENT_STATE = shared.current;
+
+ emitContext(env, scope, args.context);
+
+ if (args.framebuffer) {
+ args.framebuffer.append(env, scope);
+ }
+
+ sortState(Object.keys(args.state)).forEach(function (name) {
+ var defn = args.state[name];
+ var value = defn.append(env, scope);
+ if (isArrayLike(value)) {
+ value.forEach(function (v, i) {
+ scope.set(env.next[name], '[' + i + ']', v);
+ });
+ } else {
+ scope.set(shared.next, '.' + name, value);
+ }
+ });
+
+ emitProfile(env, scope, args, true, true)
+
+ ;[S_ELEMENTS, S_OFFSET, S_COUNT, S_INSTANCES, S_PRIMITIVE].forEach(
+ function (opt) {
+ var variable = args.draw[opt];
+ if (!variable) {
+ return
+ }
+ scope.set(shared.draw, '.' + opt, '' + variable.append(env, scope));
+ });
+
+ Object.keys(args.uniforms).forEach(function (opt) {
+ scope.set(
+ shared.uniforms,
+ '[' + stringStore.id(opt) + ']',
+ args.uniforms[opt].append(env, scope));
+ });
+
+ Object.keys(args.attributes).forEach(function (name) {
+ var record = args.attributes[name].append(env, scope);
+ var scopeAttrib = env.scopeAttrib(name);
+ Object.keys(new AttributeRecord()).forEach(function (prop) {
+ scope.set(scopeAttrib, '.' + prop, record[prop]);
+ });
+ });
+
+ function saveShader (name) {
+ var shader = args.shader[name];
+ if (shader) {
+ scope.set(shared.shader, '.' + name, shader.append(env, scope));
+ }
+ }
+ saveShader(S_VERT);
+ saveShader(S_FRAG);
+
+ if (Object.keys(args.state).length > 0) {
+ scope(CURRENT_STATE, '.dirty=true;');
+ scope.exit(CURRENT_STATE, '.dirty=true;');
+ }
+
+ scope('a1(', env.shared.context, ',a0,', env.batchId, ');');
+ }
+
+ function isDynamicObject (object) {
+ if (typeof object !== 'object' || isArrayLike(object)) {
+ return
+ }
+ var props = Object.keys(object);
+ for (var i = 0; i < props.length; ++i) {
+ if (dynamic.isDynamic(object[props[i]])) {
+ return true
+ }
+ }
+ return false
+ }
+
+ function splatObject (env, options, name) {
+ var object = options.static[name];
+ if (!object || !isDynamicObject(object)) {
+ return
+ }
+
+ var globals = env.global;
+ var keys = Object.keys(object);
+ var thisDep = false;
+ var contextDep = false;
+ var propDep = false;
+ var objectRef = env.global.def('{}');
+ keys.forEach(function (key) {
+ var value = object[key];
+ if (dynamic.isDynamic(value)) {
+ if (typeof value === 'function') {
+ value = object[key] = dynamic.unbox(value);
+ }
+ var deps = createDynamicDecl(value, null);
+ thisDep = thisDep || deps.thisDep;
+ propDep = propDep || deps.propDep;
+ contextDep = contextDep || deps.contextDep;
+ } else {
+ globals(objectRef, '.', key, '=');
+ switch (typeof value) {
+ case 'number':
+ globals(value);
+ break
+ case 'string':
+ globals('"', value, '"');
+ break
+ case 'object':
+ if (Array.isArray(value)) {
+ globals('[', value.join(), ']');
+ }
+ break
+ default:
+ globals(env.link(value));
+ break
+ }
+ globals(';');
+ }
+ });
+
+ function appendBlock (env, block) {
+ keys.forEach(function (key) {
+ var value = object[key];
+ if (!dynamic.isDynamic(value)) {
+ return
+ }
+ var ref = env.invoke(block, value);
+ block(objectRef, '.', key, '=', ref, ';');
+ });
+ }
+
+ options.dynamic[name] = new dynamic.DynamicVariable(DYN_THUNK, {
+ thisDep: thisDep,
+ contextDep: contextDep,
+ propDep: propDep,
+ ref: objectRef,
+ append: appendBlock
+ });
+ delete options.static[name];
+ }
+
+ // ===========================================================================
+ // ===========================================================================
+ // MAIN DRAW COMMAND
+ // ===========================================================================
+ // ===========================================================================
+ function compileCommand (options, attributes, uniforms, context, stats) {
+ var env = createREGLEnvironment();
+
+ // link stats, so that we can easily access it in the program.
+ env.stats = env.link(stats);
+
+ // splat options and attributes to allow for dynamic nested properties
+ Object.keys(attributes.static).forEach(function (key) {
+ splatObject(env, attributes, key);
+ });
+ NESTED_OPTIONS.forEach(function (name) {
+ splatObject(env, options, name);
+ });
+
+ var args = parseArguments(options, attributes, uniforms, context, env);
+
+ emitDrawProc(env, args);
+ emitScopeProc(env, args);
+ emitBatchProc(env, args);
+
+ return env.compile()
+ }
+
+ // ===========================================================================
+ // ===========================================================================
+ // POLL / REFRESH
+ // ===========================================================================
+ // ===========================================================================
+ return {
+ next: nextState,
+ current: currentState,
+ procs: (function () {
+ var env = createREGLEnvironment();
+ var poll = env.proc('poll');
+ var refresh = env.proc('refresh');
+ var common = env.block();
+ poll(common);
+ refresh(common);
+
+ var shared = env.shared;
+ var GL = shared.gl;
+ var NEXT_STATE = shared.next;
+ var CURRENT_STATE = shared.current;
+
+ common(CURRENT_STATE, '.dirty=false;');
+
+ emitPollFramebuffer(env, poll);
+ emitPollFramebuffer(env, refresh, null, true);
+
+ // Refresh updates all attribute state changes
+ var extInstancing = gl.getExtension('angle_instanced_arrays');
+ var INSTANCING;
+ if (extInstancing) {
+ INSTANCING = env.link(extInstancing);
+ }
+ for (var i = 0; i < limits.maxAttributes; ++i) {
+ var BINDING = refresh.def(shared.attributes, '[', i, ']');
+ var ifte = env.cond(BINDING, '.buffer');
+ ifte.then(
+ GL, '.enableVertexAttribArray(', i, ');',
+ GL, '.bindBuffer(',
+ GL_ARRAY_BUFFER$1, ',',
+ BINDING, '.buffer.buffer);',
+ GL, '.vertexAttribPointer(',
+ i, ',',
+ BINDING, '.size,',
+ BINDING, '.type,',
+ BINDING, '.normalized,',
+ BINDING, '.stride,',
+ BINDING, '.offset);'
+ ).else(
+ GL, '.disableVertexAttribArray(', i, ');',
+ GL, '.vertexAttrib4f(',
+ i, ',',
+ BINDING, '.x,',
+ BINDING, '.y,',
+ BINDING, '.z,',
+ BINDING, '.w);',
+ BINDING, '.buffer=null;');
+ refresh(ifte);
+ if (extInstancing) {
+ refresh(
+ INSTANCING, '.vertexAttribDivisorANGLE(',
+ i, ',',
+ BINDING, '.divisor);');
+ }
+ }
+
+ Object.keys(GL_FLAGS).forEach(function (flag) {
+ var cap = GL_FLAGS[flag];
+ var NEXT = common.def(NEXT_STATE, '.', flag);
+ var block = env.block();
+ block('if(', NEXT, '){',
+ GL, '.enable(', cap, ')}else{',
+ GL, '.disable(', cap, ')}',
+ CURRENT_STATE, '.', flag, '=', NEXT, ';');
+ refresh(block);
+ poll(
+ 'if(', NEXT, '!==', CURRENT_STATE, '.', flag, '){',
+ block,
+ '}');
+ });
+
+ Object.keys(GL_VARIABLES).forEach(function (name) {
+ var func = GL_VARIABLES[name];
+ var init = currentState[name];
+ var NEXT, CURRENT;
+ var block = env.block();
+ block(GL, '.', func, '(');
+ if (isArrayLike(init)) {
+ var n = init.length;
+ NEXT = env.global.def(NEXT_STATE, '.', name);
+ CURRENT = env.global.def(CURRENT_STATE, '.', name);
+ block(
+ loop(n, function (i) {
+ return NEXT + '[' + i + ']'
+ }), ');',
+ loop(n, function (i) {
+ return CURRENT + '[' + i + ']=' + NEXT + '[' + i + '];'
+ }).join(''));
+ poll(
+ 'if(', loop(n, function (i) {
+ return NEXT + '[' + i + ']!==' + CURRENT + '[' + i + ']'
+ }).join('||'), '){',
+ block,
+ '}');
+ } else {
+ NEXT = common.def(NEXT_STATE, '.', name);
+ CURRENT = common.def(CURRENT_STATE, '.', name);
+ block(
+ NEXT, ');',
+ CURRENT_STATE, '.', name, '=', NEXT, ';');
+ poll(
+ 'if(', NEXT, '!==', CURRENT, '){',
+ block,
+ '}');
+ }
+ refresh(block);
+ });
+
+ return env.compile()
+ })(),
+ compile: compileCommand
+ }
+}
+
+function stats () {
+ return {
+ bufferCount: 0,
+ elementsCount: 0,
+ framebufferCount: 0,
+ shaderCount: 0,
+ textureCount: 0,
+ cubeCount: 0,
+ renderbufferCount: 0,
+
+ maxTextureUnits: 0
+ }
+}
+
+var GL_QUERY_RESULT_EXT = 0x8866;
+var GL_QUERY_RESULT_AVAILABLE_EXT = 0x8867;
+var GL_TIME_ELAPSED_EXT = 0x88BF;
+
+var createTimer = function (gl, extensions) {
+ var extTimer = extensions.ext_disjoint_timer_query;
+
+ if (!extTimer) {
+ return null
+ }
+
+ // QUERY POOL BEGIN
+ var queryPool = [];
+ function allocQuery () {
+ return queryPool.pop() || extTimer.createQueryEXT()
+ }
+ function freeQuery (query) {
+ queryPool.push(query);
+ }
+ // QUERY POOL END
+
+ var pendingQueries = [];
+ function beginQuery (stats) {
+ var query = allocQuery();
+ extTimer.beginQueryEXT(GL_TIME_ELAPSED_EXT, query);
+ pendingQueries.push(query);
+ pushScopeStats(pendingQueries.length - 1, pendingQueries.length, stats);
+ }
+
+ function endQuery () {
+ extTimer.endQueryEXT(GL_TIME_ELAPSED_EXT);
+ }
+
+ //
+ // Pending stats pool.
+ //
+ function PendingStats () {
+ this.startQueryIndex = -1;
+ this.endQueryIndex = -1;
+ this.sum = 0;
+ this.stats = null;
+ }
+ var pendingStatsPool = [];
+ function allocPendingStats () {
+ return pendingStatsPool.pop() || new PendingStats()
+ }
+ function freePendingStats (pendingStats) {
+ pendingStatsPool.push(pendingStats);
+ }
+ // Pending stats pool end
+
+ var pendingStats = [];
+ function pushScopeStats (start, end, stats) {
+ var ps = allocPendingStats();
+ ps.startQueryIndex = start;
+ ps.endQueryIndex = end;
+ ps.sum = 0;
+ ps.stats = stats;
+ pendingStats.push(ps);
+ }
+
+ // we should call this at the beginning of the frame,
+ // in order to update gpuTime
+ var timeSum = [];
+ var queryPtr = [];
+ function update () {
+ var ptr, i;
+
+ var n = pendingQueries.length;
+ if (n === 0) {
+ return
+ }
+
+ // Reserve space
+ queryPtr.length = Math.max(queryPtr.length, n + 1);
+ timeSum.length = Math.max(timeSum.length, n + 1);
+ timeSum[0] = 0;
+ queryPtr[0] = 0;
+
+ // Update all pending timer queries
+ var queryTime = 0;
+ ptr = 0;
+ for (i = 0; i < pendingQueries.length; ++i) {
+ var query = pendingQueries[i];
+ if (extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT)) {
+ queryTime += extTimer.getQueryObjectEXT(query, GL_QUERY_RESULT_EXT);
+ freeQuery(query);
+ } else {
+ pendingQueries[ptr++] = query;
+ }
+ timeSum[i + 1] = queryTime;
+ queryPtr[i + 1] = ptr;
+ }
+ pendingQueries.length = ptr;
+
+ // Update all pending stat queries
+ ptr = 0;
+ for (i = 0; i < pendingStats.length; ++i) {
+ var stats = pendingStats[i];
+ var start = stats.startQueryIndex;
+ var end = stats.endQueryIndex;
+ stats.sum += timeSum[end] - timeSum[start];
+ var startPtr = queryPtr[start];
+ var endPtr = queryPtr[end];
+ if (endPtr === startPtr) {
+ stats.stats.gpuTime += stats.sum / 1e6;
+ freePendingStats(stats);
+ } else {
+ stats.startQueryIndex = startPtr;
+ stats.endQueryIndex = endPtr;
+ pendingStats[ptr++] = stats;
+ }
+ }
+ pendingStats.length = ptr;
+ }
+
+ return {
+ beginQuery: beginQuery,
+ endQuery: endQuery,
+ pushScopeStats: pushScopeStats,
+ update: update,
+ getNumPendingQueries: function () {
+ return pendingQueries.length
+ },
+ clear: function () {
+ queryPool.push.apply(queryPool, pendingQueries);
+ for (var i = 0; i < queryPool.length; i++) {
+ extTimer.deleteQueryEXT(queryPool[i]);
+ }
+ pendingQueries.length = 0;
+ queryPool.length = 0;
+ },
+ restore: function () {
+ pendingQueries.length = 0;
+ queryPool.length = 0;
+ }
+ }
+};
+
+var GL_COLOR_BUFFER_BIT = 16384;
+var GL_DEPTH_BUFFER_BIT = 256;
+var GL_STENCIL_BUFFER_BIT = 1024;
+
+var GL_ARRAY_BUFFER = 34962;
+
+var CONTEXT_LOST_EVENT = 'webglcontextlost';
+var CONTEXT_RESTORED_EVENT = 'webglcontextrestored';
+
+var DYN_PROP = 1;
+var DYN_CONTEXT = 2;
+var DYN_STATE = 3;
+
+function find (haystack, needle) {
+ for (var i = 0; i < haystack.length; ++i) {
+ if (haystack[i] === needle) {
+ return i
+ }
+ }
+ return -1
+}
+
+function wrapREGL (args) {
+ var config = parseArgs(args);
+ if (!config) {
+ return null
+ }
+
+ var gl = config.gl;
+ var glAttributes = gl.getContextAttributes();
+ var contextLost = gl.isContextLost();
+
+ var extensionState = createExtensionCache(gl, config);
+ if (!extensionState) {
+ return null
+ }
+
+ var stringStore = createStringStore();
+ var stats$$1 = stats();
+ var extensions = extensionState.extensions;
+ var timer = createTimer(gl, extensions);
+
+ var START_TIME = clock();
+ var WIDTH = gl.drawingBufferWidth;
+ var HEIGHT = gl.drawingBufferHeight;
+
+ var contextState = {
+ tick: 0,
+ time: 0,
+ viewportWidth: WIDTH,
+ viewportHeight: HEIGHT,
+ framebufferWidth: WIDTH,
+ framebufferHeight: HEIGHT,
+ drawingBufferWidth: WIDTH,
+ drawingBufferHeight: HEIGHT,
+ pixelRatio: config.pixelRatio
+ };
+ var uniformState = {};
+ var drawState = {
+ elements: null,
+ primitive: 4, // GL_TRIANGLES
+ count: -1,
+ offset: 0,
+ instances: -1
+ };
+
+ var limits = wrapLimits(gl, extensions);
+ var bufferState = wrapBufferState(gl, stats$$1, config);
+ var elementState = wrapElementsState(gl, extensions, bufferState, stats$$1);
+ var attributeState = wrapAttributeState(
+ gl,
+ extensions,
+ limits,
+ bufferState,
+ stringStore);
+ var shaderState = wrapShaderState(gl, stringStore, stats$$1, config);
+ var textureState = createTextureSet(
+ gl,
+ extensions,
+ limits,
+ function () { core.procs.poll(); },
+ contextState,
+ stats$$1,
+ config);
+ var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats$$1, config);
+ var framebufferState = wrapFBOState(
+ gl,
+ extensions,
+ limits,
+ textureState,
+ renderbufferState,
+ stats$$1);
+ var core = reglCore(
+ gl,
+ stringStore,
+ extensions,
+ limits,
+ bufferState,
+ elementState,
+ textureState,
+ framebufferState,
+ uniformState,
+ attributeState,
+ shaderState,
+ drawState,
+ contextState,
+ timer,
+ config);
+ var readPixels = wrapReadPixels(
+ gl,
+ framebufferState,
+ core.procs.poll,
+ contextState,
+ glAttributes, extensions);
+
+ var nextState = core.next;
+ var canvas = gl.canvas;
+
+ var rafCallbacks = [];
+ var lossCallbacks = [];
+ var restoreCallbacks = [];
+ var destroyCallbacks = [config.onDestroy];
+
+ var activeRAF = null;
+ function handleRAF () {
+ if (rafCallbacks.length === 0) {
+ if (timer) {
+ timer.update();
+ }
+ activeRAF = null;
+ return
+ }
+
+ // schedule next animation frame
+ activeRAF = raf.next(handleRAF);
+
+ // poll for changes
+ poll();
+
+ // fire a callback for all pending rafs
+ for (var i = rafCallbacks.length - 1; i >= 0; --i) {
+ var cb = rafCallbacks[i];
+ if (cb) {
+ cb(contextState, null, 0);
+ }
+ }
+
+ // flush all pending webgl calls
+ gl.flush();
+
+ // poll GPU timers *after* gl.flush so we don't delay command dispatch
+ if (timer) {
+ timer.update();
+ }
+ }
+
+ function startRAF () {
+ if (!activeRAF && rafCallbacks.length > 0) {
+ activeRAF = raf.next(handleRAF);
+ }
+ }
+
+ function stopRAF () {
+ if (activeRAF) {
+ raf.cancel(handleRAF);
+ activeRAF = null;
+ }
+ }
+
+ function handleContextLoss (event) {
+ event.preventDefault();
+
+ // set context lost flag
+ contextLost = true;
+
+ // pause request animation frame
+ stopRAF();
+
+ // lose context
+ lossCallbacks.forEach(function (cb) {
+ cb();
+ });
+ }
+
+ function handleContextRestored (event) {
+ // clear error code
+ gl.getError();
+
+ // clear context lost flag
+ contextLost = false;
+
+ // refresh state
+ extensionState.restore();
+ shaderState.restore();
+ bufferState.restore();
+ textureState.restore();
+ renderbufferState.restore();
+ framebufferState.restore();
+ if (timer) {
+ timer.restore();
+ }
+
+ // refresh state
+ core.procs.refresh();
+
+ // restart RAF
+ startRAF();
+
+ // restore context
+ restoreCallbacks.forEach(function (cb) {
+ cb();
+ });
+ }
+
+ if (canvas) {
+ canvas.addEventListener(CONTEXT_LOST_EVENT, handleContextLoss, false);
+ canvas.addEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored, false);
+ }
+
+ function destroy () {
+ rafCallbacks.length = 0;
+ stopRAF();
+
+ if (canvas) {
+ canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss);
+ canvas.removeEventListener(CONTEXT_RESTORED_EVENT, handleContextRestored);
+ }
+
+ shaderState.clear();
+ framebufferState.clear();
+ renderbufferState.clear();
+ textureState.clear();
+ elementState.clear();
+ bufferState.clear();
+
+ if (timer) {
+ timer.clear();
+ }
+
+ destroyCallbacks.forEach(function (cb) {
+ cb();
+ });
+ }
+
+ function compileProcedure (options) {
+ check$1(!!options, 'invalid args to regl({...})');
+ check$1.type(options, 'object', 'invalid args to regl({...})');
+
+ function flattenNestedOptions (options) {
+ var result = extend({}, options);
+ delete result.uniforms;
+ delete result.attributes;
+ delete result.context;
+
+ if ('stencil' in result && result.stencil.op) {
+ result.stencil.opBack = result.stencil.opFront = result.stencil.op;
+ delete result.stencil.op;
+ }
+
+ function merge (name) {
+ if (name in result) {
+ var child = result[name];
+ delete result[name];
+ Object.keys(child).forEach(function (prop) {
+ result[name + '.' + prop] = child[prop];
+ });
+ }
+ }
+ merge('blend');
+ merge('depth');
+ merge('cull');
+ merge('stencil');
+ merge('polygonOffset');
+ merge('scissor');
+ merge('sample');
+
+ return result
+ }
+
+ function separateDynamic (object) {
+ var staticItems = {};
+ var dynamicItems = {};
+ Object.keys(object).forEach(function (option) {
+ var value = object[option];
+ if (dynamic.isDynamic(value)) {
+ dynamicItems[option] = dynamic.unbox(value, option);
+ } else {
+ staticItems[option] = value;
+ }
+ });
+ return {
+ dynamic: dynamicItems,
+ static: staticItems
+ }
+ }
+
+ // Treat context variables separate from other dynamic variables
+ var context = separateDynamic(options.context || {});
+ var uniforms = separateDynamic(options.uniforms || {});
+ var attributes = separateDynamic(options.attributes || {});
+ var opts = separateDynamic(flattenNestedOptions(options));
+
+ var stats$$1 = {
+ gpuTime: 0.0,
+ cpuTime: 0.0,
+ count: 0
+ };
+
+ var compiled = core.compile(opts, attributes, uniforms, context, stats$$1);
+
+ var draw = compiled.draw;
+ var batch = compiled.batch;
+ var scope = compiled.scope;
+
+ // FIXME: we should modify code generation for batch commands so this
+ // isn't necessary
+ var EMPTY_ARRAY = [];
+ function reserve (count) {
+ while (EMPTY_ARRAY.length < count) {
+ EMPTY_ARRAY.push(null);
+ }
+ return EMPTY_ARRAY
+ }
+
+ function REGLCommand (args, body) {
+ var i;
+ if (contextLost) {
+ check$1.raise('context lost');
+ }
+ if (typeof args === 'function') {
+ return scope.call(this, null, args, 0)
+ } else if (typeof body === 'function') {
+ if (typeof args === 'number') {
+ for (i = 0; i < args; ++i) {
+ scope.call(this, null, body, i);
+ }
+ return
+ } else if (Array.isArray(args)) {
+ for (i = 0; i < args.length; ++i) {
+ scope.call(this, args[i], body, i);
+ }
+ return
+ } else {
+ return scope.call(this, args, body, 0)
+ }
+ } else if (typeof args === 'number') {
+ if (args > 0) {
+ return batch.call(this, reserve(args | 0), args | 0)
+ }
+ } else if (Array.isArray(args)) {
+ if (args.length) {
+ return batch.call(this, args, args.length)
+ }
+ } else {
+ return draw.call(this, args)
+ }
+ }
+
+ return extend(REGLCommand, {
+ stats: stats$$1
+ })
+ }
+
+ var setFBO = framebufferState.setFBO = compileProcedure({
+ framebuffer: dynamic.define.call(null, DYN_PROP, 'framebuffer')
+ });
+
+ function clearImpl (_, options) {
+ var clearFlags = 0;
+ core.procs.poll();
+
+ var c = options.color;
+ if (c) {
+ gl.clearColor(+c[0] || 0, +c[1] || 0, +c[2] || 0, +c[3] || 0);
+ clearFlags |= GL_COLOR_BUFFER_BIT;
+ }
+ if ('depth' in options) {
+ gl.clearDepth(+options.depth);
+ clearFlags |= GL_DEPTH_BUFFER_BIT;
+ }
+ if ('stencil' in options) {
+ gl.clearStencil(options.stencil | 0);
+ clearFlags |= GL_STENCIL_BUFFER_BIT;
+ }
+
+ check$1(!!clearFlags, 'called regl.clear with no buffer specified');
+ gl.clear(clearFlags);
+ }
+
+ function clear (options) {
+ check$1(
+ typeof options === 'object' && options,
+ 'regl.clear() takes an object as input');
+ if ('framebuffer' in options) {
+ if (options.framebuffer &&
+ options.framebuffer_reglType === 'framebufferCube') {
+ for (var i = 0; i < 6; ++i) {
+ setFBO(extend({
+ framebuffer: options.framebuffer.faces[i]
+ }, options), clearImpl);
+ }
+ } else {
+ setFBO(options, clearImpl);
+ }
+ } else {
+ clearImpl(null, options);
+ }
+ }
+
+ function frame (cb) {
+ check$1.type(cb, 'function', 'regl.frame() callback must be a function');
+ rafCallbacks.push(cb);
+
+ function cancel () {
+ // FIXME: should we check something other than equals cb here?
+ // what if a user calls frame twice with the same callback...
+ //
+ var i = find(rafCallbacks, cb);
+ check$1(i >= 0, 'cannot cancel a frame twice');
+ function pendingCancel () {
+ var index = find(rafCallbacks, pendingCancel);
+ rafCallbacks[index] = rafCallbacks[rafCallbacks.length - 1];
+ rafCallbacks.length -= 1;
+ if (rafCallbacks.length <= 0) {
+ stopRAF();
+ }
+ }
+ rafCallbacks[i] = pendingCancel;
+ }
+
+ startRAF();
+
+ return {
+ cancel: cancel
+ }
+ }
+
+ // poll viewport
+ function pollViewport () {
+ var viewport = nextState.viewport;
+ var scissorBox = nextState.scissor_box;
+ viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0;
+ contextState.viewportWidth =
+ contextState.framebufferWidth =
+ contextState.drawingBufferWidth =
+ viewport[2] =
+ scissorBox[2] = gl.drawingBufferWidth;
+ contextState.viewportHeight =
+ contextState.framebufferHeight =
+ contextState.drawingBufferHeight =
+ viewport[3] =
+ scissorBox[3] = gl.drawingBufferHeight;
+ }
+
+ function poll () {
+ contextState.tick += 1;
+ contextState.time = now();
+ pollViewport();
+ core.procs.poll();
+ }
+
+ function refresh () {
+ pollViewport();
+ core.procs.refresh();
+ if (timer) {
+ timer.update();
+ }
+ }
+
+ function now () {
+ return (clock() - START_TIME) / 1000.0
+ }
+
+ refresh();
+
+ function addListener (event, callback) {
+ check$1.type(callback, 'function', 'listener callback must be a function');
+
+ var callbacks;
+ switch (event) {
+ case 'frame':
+ return frame(callback)
+ case 'lost':
+ callbacks = lossCallbacks;
+ break
+ case 'restore':
+ callbacks = restoreCallbacks;
+ break
+ case 'destroy':
+ callbacks = destroyCallbacks;
+ break
+ default:
+ check$1.raise('invalid event, must be one of frame,lost,restore,destroy');
+ }
+
+ callbacks.push(callback);
+ return {
+ cancel: function () {
+ for (var i = 0; i < callbacks.length; ++i) {
+ if (callbacks[i] === callback) {
+ callbacks[i] = callbacks[callbacks.length - 1];
+ callbacks.pop();
+ return
+ }
+ }
+ }
+ }
+ }
+
+ var regl = extend(compileProcedure, {
+ // Clear current FBO
+ clear: clear,
+
+ // Short cuts for dynamic variables
+ prop: dynamic.define.bind(null, DYN_PROP),
+ context: dynamic.define.bind(null, DYN_CONTEXT),
+ this: dynamic.define.bind(null, DYN_STATE),
+
+ // executes an empty draw command
+ draw: compileProcedure({}),
+
+ // Resources
+ buffer: function (options) {
+ return bufferState.create(options, GL_ARRAY_BUFFER, false, false)
+ },
+ elements: function (options) {
+ return elementState.create(options, false)
+ },
+ texture: textureState.create2D,
+ cube: textureState.createCube,
+ renderbuffer: renderbufferState.create,
+ framebuffer: framebufferState.create,
+ framebufferCube: framebufferState.createCube,
+
+ // Expose context attributes
+ attributes: glAttributes,
+
+ // Frame rendering
+ frame: frame,
+ on: addListener,
+
+ // System limits
+ limits: limits,
+ hasExtension: function (name) {
+ return limits.extensions.indexOf(name.toLowerCase()) >= 0
+ },
+
+ // Read pixels
+ read: readPixels,
+
+ // Destroy regl and all associated resources
+ destroy: destroy,
+
+ // Direct GL state manipulation
+ _gl: gl,
+ _refresh: refresh,
+
+ poll: function () {
+ poll();
+ if (timer) {
+ timer.update();
+ }
+ },
+
+ // Current time
+ now: now,
+
+ // regl Statistics Information
+ stats: stats$$1
+ });
+
+ config.onDone(null, regl);
+
+ return regl
+}
+
+return wrapREGL;
+
+})));
+
+
+},{}],12:[function(require,module,exports){
+'use strict'
+
+var parseUnit = require('parse-unit')
+
+module.exports = toPX
+
+var PIXELS_PER_INCH = 96
+
+function getPropertyInPX(element, prop) {
+ var parts = parseUnit(getComputedStyle(element).getPropertyValue(prop))
+ return parts[0] * toPX(parts[1], element)
+}
+
+//This brutal hack is needed
+function getSizeBrutal(unit, element) {
+ var testDIV = document.createElement('div')
+ testDIV.style['font-size'] = '128' + unit
+ element.appendChild(testDIV)
+ var size = getPropertyInPX(testDIV, 'font-size') / 128
+ element.removeChild(testDIV)
+ return size
+}
+
+function toPX(str, element) {
+ element = element || document.body
+ str = (str || 'px').trim().toLowerCase()
+ if(element === window || element === document) {
+ element = document.body
+ }
+ switch(str) {
+ case '%': //Ambiguous, not sure if we should use width or height
+ return element.clientHeight / 100.0
+ case 'ch':
+ case 'ex':
+ return getSizeBrutal(str, element)
+ case 'em':
+ return getPropertyInPX(element, 'font-size')
+ case 'rem':
+ return getPropertyInPX(document.body, 'font-size')
+ case 'vw':
+ return window.innerWidth/100
+ case 'vh':
+ return window.innerHeight/100
+ case 'vmin':
+ return Math.min(window.innerWidth, window.innerHeight) / 100
+ case 'vmax':
+ return Math.max(window.innerWidth, window.innerHeight) / 100
+ case 'in':
+ return PIXELS_PER_INCH
+ case 'cm':
+ return PIXELS_PER_INCH / 2.54
+ case 'mm':
+ return PIXELS_PER_INCH / 25.4
+ case 'pt':
+ return PIXELS_PER_INCH / 72
+ case 'pc':
+ return PIXELS_PER_INCH / 6
+ }
+ return 1
+}
+},{"parse-unit":10}],13:[function(require,module,exports){
+var mouseChange = require('mouse-change')
+var mouseWheel = require('mouse-wheel')
+var identity = require('gl-mat4/identity')
+var perspective = require('gl-mat4/perspective')
+var lookAt = require('gl-mat4/lookAt')
+
+module.exports = createCamera
+
+var isBrowser = typeof window !== 'undefined'
+
+var defaultProps = {
+ // initial cameraState
+ center: [0, 0, 0],
+ theta: 0,
+ phi: 0,
+ distance: 10,
+ up: [0, 1, 0],
+ fovy: Math.PI / 4.0,
+ near: 0.01,
+ far: 1000,
+ flipY: false,
+ // properties
+ damping: 0.9,
+ minDistance: 0.1,
+ maxDistance: 1000,
+ mouse: true
+}
+
+function createCamera (regl, propsOverride) {
+ var props = Object.assign({}, defaultProps, propsOverride)
+
+ var cameraState = {
+ view: identity(new Float32Array(16)),
+ projection: identity(new Float32Array(16)),
+ center: new Float32Array(props.center),
+ theta: props.theta,
+ phi: props.phi,
+ distance: Math.log(props.distance),
+ eye: new Float32Array(3),
+ up: new Float32Array(props.up),
+ fovy: props.fovy,
+ near: props.near,
+ far: props.far,
+ flipY: Boolean(props.flipY),
+ dtheta: 0,
+ dphi: 0
+ }
+
+ var right = new Float32Array([1, 0, 0])
+ var front = new Float32Array([0, 0, 1])
+
+ var minDistance = Math.log(props.minDistance)
+ var maxDistance = Math.log(props.maxDistance)
+
+ var ddistance = 0
+
+ if (isBrowser && props.mouse) {
+ var prevX = 0
+ var prevY = 0
+
+ mouseChange(function (buttons, x, y) {
+ if (buttons & 1) {
+ var dx = (x - prevX) / window.innerWidth
+ var dy = (y - prevY) / window.innerHeight
+ var w = Math.max(cameraState.distance, 0.5)
+
+ cameraState.dtheta += w * dx
+ cameraState.dphi += w * dy
+ }
+ prevX = x
+ prevY = y
+ })
+
mouseWheel(function (dx, dy) {
ddistance += dy / window.innerHeight
})
}
function damp (x) {
- var xd = x * damping
+ var xd = x * props.damping
if (Math.abs(xd) < 0.1) {
return 0
}
diff --git a/regl-camera.js b/regl-camera.js
index 8649229..2c9b7f4 100644
--- a/regl-camera.js
+++ b/regl-camera.js
@@ -8,39 +8,56 @@ module.exports = createCamera
var isBrowser = typeof window !== 'undefined'
-function createCamera (regl, props_) {
- var props = props_ || {}
+var defaultProps = {
+ // initial cameraState
+ center: [0, 0, 0],
+ theta: 0,
+ phi: 0,
+ distance: 10,
+ up: [0, 1, 0],
+ fovy: Math.PI / 4.0,
+ near: 0.01,
+ far: 1000,
+ flipY: false,
+ // properties
+ damping: 0.9,
+ minDistance: 0.1,
+ maxDistance: 1000,
+ mouse: true
+}
+
+function createCamera (regl, propsOverride) {
+ var props = Object.assign({}, defaultProps, propsOverride)
+
var cameraState = {
view: identity(new Float32Array(16)),
projection: identity(new Float32Array(16)),
- center: new Float32Array(props.center || 3),
- theta: props.theta || 0,
- phi: props.phi || 0,
- distance: Math.log(props.distance || 10.0),
+ center: new Float32Array(props.center),
+ theta: props.theta,
+ phi: props.phi,
+ distance: Math.log(props.distance),
eye: new Float32Array(3),
- up: new Float32Array(props.up || [0, 1, 0]),
- fovy: props.fovy || Math.PI / 4.0,
- near: typeof props.near !== 'undefined' ? props.near : 0.01,
- far: typeof props.far !== 'undefined' ? props.far : 1000.0,
- flipY: !!props.flipY,
+ up: new Float32Array(props.up),
+ fovy: props.fovy,
+ near: props.near,
+ far: props.far,
+ flipY: Boolean(props.flipY),
dtheta: 0,
dphi: 0
}
- var damping = typeof props.damping !== 'undefined' ? props.damping : 0.9
-
var right = new Float32Array([1, 0, 0])
var front = new Float32Array([0, 0, 1])
- var minDistance = Math.log('minDistance' in props ? props.minDistance : 0.1)
- var maxDistance = Math.log('maxDistance' in props ? props.maxDistance : 1000)
+ var minDistance = Math.log(props.minDistance)
+ var maxDistance = Math.log(props.maxDistance)
var ddistance = 0
- var prevX = 0
- var prevY = 0
+ if (isBrowser && props.mouse) {
+ var prevX = 0
+ var prevY = 0
- if (isBrowser && props.mouse !== false) {
mouseChange(function (buttons, x, y) {
if (buttons & 1) {
var dx = (x - prevX) / window.innerWidth
@@ -53,13 +70,14 @@ function createCamera (regl, props_) {
prevX = x
prevY = y
})
+
mouseWheel(function (dx, dy) {
ddistance += dy / window.innerHeight
})
}
function damp (x) {
- var xd = x * damping
+ var xd = x * props.damping
if (Math.abs(xd) < 0.1) {
return 0
}